/***************************************************************************** * NAME: exec_clrbdblks * * FUNCTION: Start clrbblks in a child process and wait for it to complete. * * PARAMETERS: none * * NOTES: * * RETURNS: * success: FSCK_OK * failure: something else */ retcode_t exec_clrbdblks( ) { retcode_t ec_rc = FSCK_OK; CHAR szFailName[CCHMAXPATH]; RESULTCODES resc; CHAR szCommandLine[] = "clrbblks\0\0\0\0\0\0\0\0\0\0\0\0"; memcpy((void *) &(szCommandLine[9]), (void *) Vol_Label, sizeof(Vol_Label)); ec_rc = DosExecPgm( szFailName, sizeof(szFailName), EXEC_SYNC, szCommandLine, (PSZ) NULL, &resc, "clrbblks.exe" ); /* * log the result of the DosExecPgm */ sprintf( message_parm_0, "%ld", ec_rc ); msgprms[0] = message_parm_0; msgprmidx[0] = 0; fsck_send_msg( fsck_DOSEXECPGMRC, 0, 1 ); /* * if the DosExecPgm was successful, log and * return the result of the clrbblks process */ if( ec_rc == 0 ) { sprintf( message_parm_0, "%ld,%ld", resc.codeTerminate, resc.codeResult ); msgprms[0] = message_parm_0; msgprmidx[0] = 0; fsck_send_msg( fsck_CLRBBLKSRC, 0, 1 ); ec_rc = resc.codeResult + resc.codeTerminate; } return( ec_rc ); } /* end of exec_clrbdblks() */
/***************************************************************************** * NAME: adjust_parent * * FUNCTION: Add an fsck inode extension record to the parent inode's * fsck inode record so that the directory entry for the * given child will be removed. * * PARAMETERS: * child_ino - input - ordinal number of child inode * child_inorecptr - input - pointer to an fsck record describing the * child inode * parent_ino - input - ordinal number of parent inode * * NOTES: * * RETURNS: * success: FSCK_OK * failure: something else */ retcode_t adjust_parent ( inoidx_t child_ino, fsck_inode_recptr child_inorecptr, inoidx_t parent_ino ) { retcode_t adjp_rc = FSCK_OK; fsck_inode_extptr this_ext; fsck_inode_recptr parent_inorecptr; int is_aggregate = 0; int alloc_ifnull = 0; adjp_rc = get_inorecptr( is_aggregate, alloc_ifnull, parent_ino, &parent_inorecptr ); if( (adjp_rc == FSCK_OK) && (parent_inorecptr == NULL) ) { /* uh oh.... */ adjp_rc = FSCK_INTERNAL_ERROR_4; sprintf( message_parm_0, "%ld", adjp_rc ); /* @F1 */ msgprms[0] = message_parm_0; /* @F1 */ msgprmidx[0] = 0; /* @F1 */ sprintf( message_parm_1, "%ld", child_ino ); /* @F1 */ msgprms[1] = message_parm_1; /* @F1 */ msgprmidx[1] = 0; /* @F1 */ sprintf( message_parm_2, "%ld", parent_ino ); /* @F1 */ msgprms[2] = message_parm_2; /* @F1 */ msgprmidx[2] = 0; /* @F1 */ sprintf( message_parm_3, "%ld", 0 ); /* @F1 */ msgprms[3] = message_parm_3; /* @F1 */ msgprmidx[3] = 0; /* @F1 */ fsck_send_msg( fsck_INTERNALERROR, 0, 4 ); /* @F1 */ } /* end uh oh.... */ else if( adjp_rc == FSCK_OK ) { /* located the parent's inode record */ adjp_rc = get_inode_extension( &this_ext ); if( adjp_rc == FSCK_OK ) { /* got extension */ this_ext->ext_type = rmv_direntry_extension; this_ext->inonum = child_ino; this_ext->next = parent_inorecptr->ext_rec; this_ext->ino_type = child_inorecptr->inode_type; parent_inorecptr->ext_rec = this_ext; parent_inorecptr->adj_entries = 1; agg_recptr->corrections_needed = 1; } /* end got extension */ } /* end located the parent's inode record */ return( adjp_rc ); } /* end of adjust_parent () */
/***************************************************************************** * NAME: check_BdBlkLst_FillLevel * * FUNCTION: If any of the LVM Bad Block Tables composing the LVM Bad * Block List for this partition is more than 50% full, issue a message. * * PARAMETERS: none * * NOTES: This routine is called only during autocheck processing. chkdsk * cannot perform /B processing at that time since the file system * is not yet fully initialized. * * RETURNS: * success: FSCK_OK * failure: something else */ retcode_t check_BdBlkLst_FillLevel ( ) { retcode_t ccbblfl_rc = FSCK_OK; int32 intermed_rc = 0; int32 num_tables = 0; int32 highest_percent_full = 0; intermed_rc = get_LVM_BadBlockList_count( &num_tables ); if( intermed_rc == FSCK_OK ) { intermed_rc = examine_LVM_BadBlockLists( num_tables, &highest_percent_full ); if( intermed_rc == FSCK_OK ) { if( highest_percent_full > 50 ) { fsck_send_msg( fsck_LVMFOUNDBDBLKS, 0, 0 ); } } } return( ccbblfl_rc ); } /* end of check_BdBlkLst_FillLevel() */
/* * NAME: pageVal(pno, eor, pmax) * * FUNCTION: Read the page into the log buffer pool and call setLogpage * to form consistent log page. * * RETURNS: 0 - ok * REFORMAT_ERROR(-3) - I/O error, reformat the log * MAJOR_ERROR(-2) - other major errors other than EIO. */ pageVal(int pno, /* page number in log */ int *eor, /* corresponding eor value */ int *pmax) /* pointer to returned page number */ { int rc, buf0; /* logp[] buffer element number */ /* Read the page into the log buffer pool. */ if ((buf0 = getLogpage(pno)) < 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_PVGETPGFAIL, 0, 2 ); return(buf0); } return(setLogpage(pno, eor, pmax, buf0)); }
/***************************************************************************** * NAME: reset_parents * * FUNCTION: Adjust the fsck notations about the inode's parent(s) if * the parent(s) are corrupt or approved for release. * * PARAMETERS: * ino_recptr - input - pointer to an fsck record describing the inode * ino_idx - input - ordinal number of the inode * * NOTES: * * RETURNS: * success: FSCK_OK * failure: something else */ retcode_t reset_parents ( fsck_inode_recptr ino_recptr, inoidx_t ino_idx ) { retcode_t resps_rc = FSCK_OK; fsck_inode_extptr this_ext; fsck_inode_extptr rest_of_list; int parent_count = 0; inoidx_t stored_parent_inonum; fsck_inode_recptr parent_inorecptr; int aggregate_inode = 0; int alloc_ifnull = 0; /* * if this is a directory with illegal hard links the inode * number in the fsck inode record is the one stored in the * inode on disk. */ if( (ino_recptr->inode_type == directory_inode) && (ino_recptr->unxpctd_prnts) ) { /* dir with multiple parents */ /* * Save the value stored in the inode record and then clear it. */ stored_parent_inonum = ino_recptr->parent_inonum; ino_recptr->parent_inonum = 0; } /* end dir with multiple parents */ else { /* not a dir with multiple parents */ /* * the 1st parent observed is in the inode record. Any others are * in extension records. */ resps_rc = get_inorecptr( aggregate_inode, alloc_ifnull, ino_recptr->parent_inonum, &parent_inorecptr ); if( (resps_rc == FSCK_OK) && (parent_inorecptr == NULL) ) { resps_rc = FSCK_INTERNAL_ERROR_15; sprintf( message_parm_0, "%ld", resps_rc ); /* @F1 */ msgprms[0] = message_parm_0; /* @F1 */ msgprmidx[0] = 0; /* @F1 */ sprintf( message_parm_1, "%ld", ino_idx ); /* @F1 */ msgprms[1] = message_parm_1; /* @F1 */ msgprmidx[1] = 0; /* @F1 */ sprintf( message_parm_2, "%ld", ino_recptr->parent_inonum ); /* @F1 */ msgprms[2] = message_parm_2; /* @F1 */ msgprmidx[2] = 0; /* @F1 */ sprintf( message_parm_3, "%ld", 0 ); /* @F1 */ msgprms[3] = message_parm_3; /* @F1 */ msgprmidx[3] = 0; /* @F1 */ fsck_send_msg( fsck_INTERNALERROR, 0, 4 ); /* @F1 */ } else if( resps_rc == FSCK_OK ) { if( (ino_recptr->parent_inonum == ROOT_I) && (agg_recptr->rootdir_rebuilt) ) { /* * special case: if the parent is root and root was * rebuilt, then this is an orphan */ ino_recptr->parent_inonum = 0; ino_recptr->link_count--; } /* end special case: if the parent is root ... */ else if( (!parent_inorecptr->selected_to_rls) && (!parent_inorecptr->ignore_alloc_blks) ) { /* * keeping this parent and haven't found the * tree to be corrupt */ parent_count++; } /* end keeping this parent */ else { /* releasing this parent */ ino_recptr->parent_inonum = 0; ino_recptr->link_count--; } /* end releasing this parent */ } } /* end else not a dir with multiple parents */ /* * detach the extensions list from the inode record */ this_ext = ino_recptr->ext_rec; ino_recptr->ext_rec = NULL; while( (resps_rc == FSCK_OK ) && (this_ext != NULL) ) { /* there may be more parents */ rest_of_list = this_ext->next; if( this_ext->ext_type != parent_extension ) { /* not a parent */ this_ext->next = ino_recptr->ext_rec; ino_recptr->ext_rec = this_ext; } /* end not a parent */ else { /* parent extension */ resps_rc = get_inorecptr( aggregate_inode, alloc_ifnull, this_ext->inonum, &parent_inorecptr ); if( (resps_rc == FSCK_OK) && (parent_inorecptr == NULL) ) { resps_rc = FSCK_INTERNAL_ERROR_16; sprintf( message_parm_0, "%ld", resps_rc ); msgprms[0] = message_parm_0; /* @F1 */ msgprmidx[0] = 0; /* @F1 */ sprintf( message_parm_1, "%ld", ino_idx ); /* @F1 */ msgprms[1] = message_parm_1; /* @F1 */ msgprmidx[1] = 0; /* @F1 */ sprintf( message_parm_2, "%ld", this_ext->inonum ); /* @F1 */ msgprms[2] = message_parm_2; /* @F1 */ msgprmidx[2] = 0; /* @F1 */ sprintf( message_parm_3, "%ld", 0 ); /* @F1 */ msgprms[3] = message_parm_3; /* @F1 */ msgprmidx[3] = 0; /* @F1 */ fsck_send_msg( fsck_INTERNALERROR, 0, 4 ); /* @F1 */ } else if( resps_rc == FSCK_OK ) { if( (ino_recptr->parent_inonum == ROOT_I) && (agg_recptr->rootdir_rebuilt) ) { /* * special case: if the parent is root and root was * rebuilt, then this is an orphan */ release_inode_extension( this_ext ); ino_recptr->link_count--; } /* end special case: if the parent is root ... */ else if( (!parent_inorecptr->selected_to_rls) && (!parent_inorecptr->ignore_alloc_blks) ) { /* keeping this parent */ parent_count++; if( ino_recptr->parent_inonum == 0 ) { ino_recptr->parent_inonum = this_ext->inonum; release_inode_extension( this_ext ); } else { /* put it back on the list */ this_ext->next = ino_recptr->ext_rec; ino_recptr->ext_rec = this_ext; } /* put it back on the list */ } /* end keeping this parent */ else { /* releasing this parent */ release_inode_extension( this_ext ); ino_recptr->link_count--; } /* end else releasing this parent */ } } /* end else parent extension */ this_ext = rest_of_list; } /* end while there may be more parents */ /* * at this point, if there is at least 1 observed parent which * is not being released, then a parent inode number is stored in * the inode record and any other parents are described in extension * records. * * if this is not a directory inode, we're done. * * if this is a directory inode, need to recheck for illegal hard * links and incorrect parent inode entry. */ if( (resps_rc == FSCK_OK) && (ino_recptr->inode_type == directory_inode) ) { /* * a directory */ if( parent_count == 1 ) { /* 1 parent now */ if( ino_recptr->unxpctd_prnts ) { /* entered with multiple links */ ino_recptr->unxpctd_prnts = 0; /* reset flag */ if( ino_recptr->parent_inonum != stored_parent_inonum ) { /* * Remaining parent doesn't match the one * the on-device inode says owns it. */ ino_recptr->crrct_prnt_inonum = 1; agg_recptr->corrections_needed = 1; agg_recptr->corrections_approved = 1; } /* end remaining parent doesn't match the one the ... */ } /* end entered with multiple links */ } /* end 1 parent now */ else if( parent_count == 0 ) { /* no parents now */ ino_recptr->crrct_prnt_inonum = 0; ino_recptr->unxpctd_prnts = 0; } /* end no parents now */ else { /* multiple parents still */ ino_recptr->unxpctd_prnts = 1; agg_recptr->corrections_needed = 1; resps_rc = get_inode_extension( &this_ext ); if( resps_rc == FSCK_OK ) { /* got one */ this_ext->ext_type = parent_extension; this_ext->inonum = ino_recptr->parent_inonum; this_ext->next = ino_recptr->ext_rec; ino_recptr->ext_rec = this_ext; ino_recptr->parent_inonum = stored_parent_inonum; } /* end got one */ } /* end multiple parents still */ } /* end a directory */ return( resps_rc ); } /* end of reset_parents () */
/***************************************************************************** * NAME: check_link_counts * * FUNCTION: Count links from child directories to their parents. * * Verify that the link count stored in each in-use inode * matches the number of links fsck observed for the inode. * * PARAMETERS: none * * NOTES: * * RETURNS: * success: FSCK_OK * failure: something else */ retcode_t check_link_counts ( ) { retcode_t clc_rc = FSCK_OK; inoidx_t ino_idx; int num_parents; int invalid_count_seen = 0; int low_stored_count_seen = 0; char user_reply; fsck_inode_extptr this_ext; fsck_inode_recptr this_inorec; fsck_inode_recptr parent_inorec; int done_looking = 0; int aggregate_inode = 0; int alloc_ifnull = 0; struct fsck_ino_msg_info ino_msg_info; fsck_msg_info_ptr msg_info_ptr; msg_info_ptr = &ino_msg_info; msg_info_ptr->msg_inopfx = fsck_fset_inode; /* all fileset owned */ /* * count links from child directories to their parents * * (These can't be counted when the parent-child relationship * is observed because that observation occurs while processing * the parent and until the child is processed we don't know * whether the child is a directory or not.) */ clc_rc = get_inorecptr_first( aggregate_inode, &ino_idx, &this_inorec ); while( (clc_rc == FSCK_OK) && (this_inorec != NULL) ) { if( (this_inorec->in_use) && (!this_inorec->selected_to_rls) && (!this_inorec->ignore_alloc_blks) && (this_inorec->inode_type == directory_inode) ) { /* * inode is in use, not being released, and * is type directory */ this_inorec->link_count++; /* for the self entry */ if( (this_inorec->parent_inonum == ROOT_I) && (agg_recptr->rootdir_rebuilt) ) { /* * special case: if the parent is root and root was * rebuilt, then don't increment parent */ if( this_inorec->inonum == ROOT_I ) { /* * special case: if this IS the root, then it's link from itself * to itself DOES count */ this_inorec->link_count++; } } else if( this_inorec->parent_inonum != (ino_t) 0 ) { /* * not an orphan */ clc_rc = get_inorecptr( aggregate_inode, alloc_ifnull, this_inorec->parent_inonum, &parent_inorec ); if( (clc_rc != FSCK_OK) || (parent_inorec == NULL) ) { clc_rc = FSCK_INTERNAL_ERROR_13; sprintf( message_parm_0, "%ld", clc_rc ); /* @F1 */ msgprms[0] = message_parm_0; /* @F1 */ msgprmidx[0] = 0; /* @F1 */ sprintf( message_parm_1, "%ld", ino_idx ); /* @F1 */ msgprms[1] = message_parm_1; /* @F1 */ msgprmidx[1] = 0; /* @F1 */ sprintf( message_parm_2, "%ld", this_inorec->parent_inonum ); /* @F1 */ msgprms[2] = message_parm_2; /* @F1 */ msgprmidx[2] = 0; /* @F1 */ sprintf( message_parm_3, "%ld", 0 ); /* @F1 */ msgprms[3] = message_parm_3; /* @F1 */ msgprmidx[3] = 0; /* @F1 */ fsck_send_msg( fsck_INTERNALERROR, 0, 4 ); /* @F1 */ } else { parent_inorec->link_count++; /* * handle the first (and usually the only) * parent. */ } if( (clc_rc == FSCK_OK) && (this_inorec->ext_rec != NULL) ) { /* * there might be more parents */ num_parents = parent_count( this_inorec ); if( num_parents > 1 ) { /* directory with illegal links */ this_inorec->unxpctd_prnts = 1; agg_recptr->corrections_needed = 1; /* * Create an extension record for the parent inode number * now stored in the child inode record. * When we traverse the aggregate on-disk we'll copy the * stored value into this field of the inode record for * use when displaying paths to the inode. */ clc_rc = get_inode_extension( &this_ext ); if( clc_rc == FSCK_OK ) { /* got extension record */ this_ext->ext_type = parent_extension; this_ext->inonum = this_inorec->parent_inonum; this_ext->next = this_inorec->ext_rec; this_inorec->ext_rec = this_ext; this_inorec->parent_inonum = 0; this_ext = this_ext->next; /* already counted the first * one, back when it was in the * workspace inode record itself */ while ( (clc_rc == FSCK_OK) && (this_ext != NULL) ) { /* exten records to check */ if( this_ext->ext_type == parent_extension ) { clc_rc = get_inorecptr( aggregate_inode, alloc_ifnull, this_ext->inonum, &parent_inorec ); if( (clc_rc != FSCK_OK) || (parent_inorec == NULL) ) { clc_rc = FSCK_INTERNAL_ERROR_14; sprintf( message_parm_0, "%ld", clc_rc ); /* @F1 */ msgprms[0] = message_parm_0; /* @F1 */ msgprmidx[0] = 0; /* @F1 */ sprintf( message_parm_1, "%ld", ino_idx ); /* @F1 */ msgprms[1] = message_parm_1; /* @F1 */ msgprmidx[1] = 0; /* @F1 */ sprintf( message_parm_2, "%ld", this_ext->inonum ); /* @F1 */ msgprms[2] = message_parm_2; /* @F1 */ msgprmidx[2] = 0; /* @F1 */ sprintf( message_parm_3, "%ld", 0 ); /* @F1 */ msgprms[3] = message_parm_3; /* @F1 */ msgprmidx[3] = 0; /* @F1 */ fsck_send_msg( fsck_INTERNALERROR, 0, 4 ); /* @F1 */ } else { parent_inorec->link_count++; } } this_ext = this_ext->next; } /* end while exten records to check */ } /* end got extension record */ } /* end directory with illegal links */ } /* end there might be more parents */ } /* end not an orphan */ } /* end inode is in use and is type directory */ if( clc_rc == FSCK_OK ) { clc_rc = get_inorecptr_next( aggregate_inode, &ino_idx, &this_inorec ); } } /* end while */ /* * verify that stored link counts match observed link counts * * We have added each observed link and subtracted the stored * count. If the stored count is correct the result is 0. */ if( clc_rc == FSCK_OK ) { /* no fatal errors */ clc_rc = get_inorecptr_first( aggregate_inode, &ino_idx, &this_inorec ); while( (clc_rc == FSCK_OK) && (this_inorec != NULL) && (!done_looking) ) { if( (this_inorec->in_use) && (!this_inorec->selected_to_rls) && (!this_inorec->ignore_alloc_blks) ) { /* * inode is in use and not being released */ if( this_inorec->link_count != 0 ) { /* stored * link count doesn't match fsck's observations */ if( this_inorec->parent_inonum == 0 ) { /* inode is an orphan */ this_inorec->crrct_link_count = 1; } else { /* not an orphan */ this_inorec->crrct_link_count = 1; if( this_inorec->link_count > 0 ) { low_stored_count_seen = 1; } invalid_count_seen = 1; msgprms[0] = message_parm_0; msgprmidx[0] = msg_info_ptr->msg_inopfx; sprintf( message_parm_1, "%ld", ino_idx ); msgprms[1] = message_parm_1; msgprmidx[1] = 0; fsck_send_msg( fsck_BADINOLKCT, 0, 2 ); } /* end else not an orphan */ } /* end stored link count doesn't match fsck's observations */ } /* end inode is in use and not being released */ if( clc_rc == FSCK_OK ) { clc_rc = get_inorecptr_next( aggregate_inode, &ino_idx, &this_inorec ); } } /* end while */ if( (clc_rc == FSCK_OK) && (invalid_count_seen) ) { if( agg_recptr->processing_readwrite ) { /* we can fix this */ agg_recptr->corrections_approved = 1; fsck_send_msg( fsck_WILLFIXLINKCTS, 0, 0 ); } /* end we can fix this */ else { /* no write access */ if( low_stored_count_seen ) { agg_recptr->ag_dirty = 1; } /* end if low_stored_count_seen */ /* * reset all link counts (in the fsck workspace) to * zero so that we won't accidentally correct them * while doing link count adjustments. * * (Link count adjustments are side effects of approved * repairs. For example, if a directory inode is * released, the link count of its parent directory * is decremented.) */ clc_rc = get_inorecptr_first( aggregate_inode, &ino_idx, &this_inorec ); while( (clc_rc == FSCK_OK) && (this_inorec != NULL) ) { if( this_inorec->in_use ) { /* inode in use */ this_inorec->crrct_link_count = 0; this_inorec->link_count = 0; } /* end inode in use */ clc_rc = get_inorecptr_next( aggregate_inode, &ino_idx, &this_inorec ); } /* end while */ fsck_send_msg( fsck_BADLINKCTS, 0, 0 ); } /* end no write access */ } /* end if invalid_count_seen */ } /* end no fatal errors */ return( clc_rc ); } /* end of check_link_counts () */
/***************************************************************************** * NAME: check_dir_integrity * * FUNCTION: Verify that no directory has more than 1 entry for any * single inode. If a directory does, then that directory * is corrupt (in Release I of JFS/Warp). * * PARAMETERS: none * * NOTES: none * * RETURNS: * success: FSCK_OK * failure: something else */ retcode_t check_dir_integrity ( ) { retcode_t cdi_rc = FSCK_OK; inoidx_t ino_idx; fsck_inode_recptr this_inorec; fsck_inode_recptr that_inorec; int aggregate_inode = 0; int alloc_ifnull = 0; fsck_inode_extptr this_ext; fsck_inode_extptr that_ext; int dup_parent_detected = 0; struct fsck_ino_msg_info ino_msg_info; fsck_msg_info_ptr msg_info_ptr; msg_info_ptr = &ino_msg_info; msg_info_ptr->msg_inopfx = fsck_fset_inode; /* all fileset owned */ /* * Verify that no inode has multiple links from the same * directory. */ cdi_rc = get_inorecptr_first( aggregate_inode, &ino_idx, &this_inorec ); while( (cdi_rc == FSCK_OK) && (this_inorec != NULL) && (ino_idx < FILESET_OBJECT_I) ) { /* * not interesting until we get past the root inode * and the special fileset inodes. */ cdi_rc = get_inorecptr_next( aggregate_inode, &ino_idx, &this_inorec ); } /* end while */ while( (cdi_rc == FSCK_OK) && (this_inorec != NULL) ) { if( (this_inorec->in_use) && (!this_inorec->selected_to_rls) ) { /* * inode in use and not selected to release */ msg_info_ptr->msg_inonum = ino_idx; if( this_inorec->inode_type == directory_inode ) { msg_info_ptr->msg_inotyp = fsck_directory; } else if( this_inorec->inode_type == symlink_inode ) { msg_info_ptr->msg_inotyp = fsck_symbolic_link; } else { /* a regular file */ msg_info_ptr->msg_inotyp = fsck_file; } if( this_inorec->parent_inonum != 0 ) { /* * at least 1 parent observed by fsck */ if( this_inorec->ext_rec ) { /* * and maybe more parents have been observed */ /* * get the first entry in the extensions * list on the inode record */ this_ext = this_inorec->ext_rec; while( (cdi_rc == FSCK_OK ) && (this_ext != NULL) ) { /* there may be more parents */ if( this_ext->ext_type == parent_extension ) { /* a parent */ cdi_rc = get_inorecptr( aggregate_inode, alloc_ifnull, this_ext->inonum, &that_inorec ); if( (cdi_rc == FSCK_OK) && (!that_inorec->selected_to_rls) ) { /* * parent isn't marked for release (yet) */ dup_parent_detected = 0; if( this_ext->inonum == this_inorec->parent_inonum ) { dup_parent_detected = -1; } else { /* need to check for dups in rest of list */ that_ext = this_ext->next; while( (!dup_parent_detected) && (that_ext != NULL) ) { if( that_ext->ext_type == parent_extension ) /* * another parent extension */ if( this_ext->inonum == that_ext->inonum ) { dup_parent_detected = -1; } that_ext = that_ext->next; } /* end while */ } /* end else need to check for dups in rest of list */ if( dup_parent_detected ) { /* * mark the parent's inode record for release */ that_inorec->selected_to_rls = 1; /* * notify the user that the directory is bad */ msgprms[0] = message_parm_0; msgprmidx[0] = fsck_directory; msgprms[1] = message_parm_1; msgprmidx[1] = msg_info_ptr->msg_inopfx; sprintf( message_parm_2, "%ld", this_ext->inonum ); msgprms[2] = message_parm_2; msgprmidx[2] = 0; sprintf( message_parm_3, "%d", 37 ); msgprms[3] = message_parm_3; msgprmidx[3] = 0; fsck_send_msg( fsck_BADKEYS, 0, 4 ); } /* end dup_parent_detected */ } /* end parent isn't marked for release (yet) */ } /* end a parent */ this_ext = this_ext->next; } /* end while there may be more parents */ } /* end and maybe more parents have been observed */ } /* end at least 1 parent observed by fsck */ } /* end inode in use and not selected to release */ if( cdi_rc == FSCK_OK ) { cdi_rc = get_inorecptr_next( aggregate_inode, &ino_idx, &this_inorec ); } } /* end while */ return( cdi_rc ); } /* end of check_dir_integrity () */
/***************************************************************************** * NAME: check_connectedness * * FUNCTION: Verify that, after approved corrections are made, all inodes * in use will be connected to the root directory tree. * * PARAMETERS: none * * NOTES: o A directory inode must have exactly one parent inode. * * o A non-directory inode must have at least one parent inode. * * RETURNS: * success: FSCK_OK * failure: something else */ retcode_t check_connectedness ( ) { retcode_t cc_rc = FSCK_OK; inoidx_t ino_idx; fsck_inode_extptr this_ext; fsck_inode_recptr this_inorec; fsck_inode_extptr new_ext; char user_reply; int aggregate_inode = 0; int alloc_ifnull = 0; struct fsck_ino_msg_info ino_msg_info; fsck_msg_info_ptr msg_info_ptr; msg_info_ptr = &ino_msg_info; msg_info_ptr->msg_inopfx = fsck_fset_inode; /* all fileset owned */ /* * detect orphan inodes, including ones which we're about to * orphan by releasing inodes. * * if any non-orphan inode was flagged as a directory with illegal * hard links, see if it's going to be true after we release inodes. * If not, make sure the remaining link matches the one stored in * the inode. */ cc_rc = get_inorecptr_first( aggregate_inode, &ino_idx, &this_inorec ); while( (cc_rc == FSCK_OK) && (this_inorec != NULL) && (ino_idx < FILESET_OBJECT_I) ) { /* * not interesting until we get past the root inode * and the special fileset inodes. */ cc_rc = get_inorecptr_next( aggregate_inode, &ino_idx, &this_inorec ); } /* end while */ while( (cc_rc == FSCK_OK) && (this_inorec != NULL) ) { if( (this_inorec->in_use) && (!this_inorec->selected_to_rls) ) { /* * inode in use and not selected to release */ msg_info_ptr->msg_inonum = ino_idx; if( this_inorec->inode_type == directory_inode ) { msg_info_ptr->msg_inotyp = fsck_directory; } else if( this_inorec->inode_type == symlink_inode ) { msg_info_ptr->msg_inotyp = fsck_symbolic_link; } else { /* a regular file */ msg_info_ptr->msg_inotyp = fsck_file; } if( this_inorec->parent_inonum == 0 ) { /* no parents were * observed by fsck */ msgprms[0] = message_parm_0; msgprmidx[0] = msg_info_ptr->msg_inopfx; sprintf( message_parm_1, "%ld", msg_info_ptr->msg_inonum ); msgprms[1] = message_parm_1; msgprmidx[1] = 0; fsck_send_msg( fsck_INONOPATHS, 0, 2 ); } /* end no parents were observed by fsck */ else { /* at least one parent observed by fsck */ cc_rc = reset_parents( this_inorec, ino_idx ); /* * make adjustments to child records for * parents which will be released */ } /* end else at least one parent observed by fsck */ if( cc_rc == FSCK_OK ) { /* nothing fatal */ if( this_inorec->parent_inonum == 0 ) { /* unconnected !! */ /* * do not issue a message to inform the user about * this condition since it is a side effect of * the (approved) release of some other inode(s) */ this_inorec->reconnect = 1; agg_recptr->corrections_approved = 1; cc_rc = get_inode_extension( &new_ext ); if( cc_rc == FSCK_OK ) { /* got an extension record */ new_ext->ext_type = add_direntry_extension; new_ext->inonum = ino_idx; new_ext->ino_type = this_inorec->inode_type; new_ext->next = agg_recptr->inode_reconn_extens; agg_recptr->inode_reconn_extens = new_ext; this_inorec->link_count++; /* increment for the link from * parent after reconnect */ } /* end got an extension record */ } /* end unconnected !! */ else { /* else still connected */ if( this_inorec->unxpctd_prnts ) { /* multiple parents */ cc_rc = display_paths( ino_idx, this_inorec, msg_info_ptr ); if( cc_rc == FSCK_OK ) { /* nothing unexpected */ if( agg_recptr->processing_readwrite ) { /* we can fix this */ cc_rc = adjust_parents( this_inorec, ino_idx ); msgprms[0] = message_parm_0; msgprmidx[0] = msg_info_ptr->msg_inopfx; sprintf( message_parm_1, "%ld", msg_info_ptr->msg_inonum ); msgprms[1] = message_parm_1; msgprmidx[1] = 0; fsck_send_msg( fsck_WILLFIXDIRWHDLKS, 0, 2 ); } /* end we can fix this */ else { /* we don't have write access */ this_inorec->unxpctd_prnts = 0; agg_recptr->ag_dirty = 1; msgprms[0] = message_parm_0; msgprmidx[0] = msg_info_ptr->msg_inopfx; sprintf( message_parm_1, "%ld", msg_info_ptr->msg_inonum ); msgprms[1] = message_parm_1; msgprmidx[1] = 0; fsck_send_msg( fsck_DIRWHDLKS, 0, 2 ); } /* end we don't have write access */ } /* end nothing unexpected */ } /* end multiple parents */ else if( (cc_rc == FSCK_OK) && (this_inorec->crrct_prnt_inonum) ) { /* * a single parent but not the one * named in the implied '..' entry */ cc_rc = display_paths( ino_idx, this_inorec, msg_info_ptr ); if( agg_recptr->processing_readwrite ) { /* we can fix this */ msgprms[0] = message_parm_0; msgprmidx[0] = msg_info_ptr->msg_inopfx; sprintf( message_parm_1, "%ld", msg_info_ptr->msg_inonum ); msgprms[1] = message_parm_1; msgprmidx[1] = 0; fsck_send_msg( fsck_WILLFIXINCREF, 0, 2 ); } /* end we can fix this */ else { /* we don't have write access */ this_inorec->crrct_prnt_inonum = 0; agg_recptr->ag_dirty = 1; msgprms[0] = message_parm_0; msgprmidx[0] = msg_info_ptr->msg_inopfx; sprintf( message_parm_1, "%ld", msg_info_ptr->msg_inonum ); msgprms[1] = message_parm_1; msgprmidx[1] = 0; fsck_send_msg( fsck_INCINOREF, 0, 2 ); } /* end we don't have write access */ } /* end a single parent but not the one named.... */ } /* end else still connected */ } /* end nothing fatal */ } /* end inode in use and not selected to release */ if( cc_rc == FSCK_OK ) { cc_rc = get_inorecptr_next( aggregate_inode, &ino_idx, &this_inorec ); } } /* end while */ return( cc_rc ); } /* end of check_connectedness () */
/* * NAME: moveWords() * * FUNCTION: moves nwords from buffer pool to target. data * is moved in backwards direction starting at offset. * If partial log record is on the previous page, * or we have exhaust the current page (all bytes were read), * the previous page is read into the buffer pool. * On exit buf will point to this page in the buffer pool * and offset to where the move stopped. * * Note: the previous page is fetched whenever * the current page is exhausted (all bytes were read) * even if all the words required to satisfy this move * are on the current page. * * PARAMETERS: nwords - number of 4-byte words to move * target - address of target (begin address) * buf - index in buffer pool of current page * offset - initial offset in buffer pool page, this offset * includes the page head size * * RETURNS: = 0 - ok * < 0 - error returned from getLogpage */ int32 moveWords( int32 nwords, /* number of 4-byte words to move */ int32 *target, /* address of target (begin address) */ int32 *buf, /* index in buffer pool of current page */ int32 *offset) /* initial offset in buffer pool page */ { int n,j,words,pno; int * ptr; j = (*offset - LOGPHDRSIZE)/4 - 1; /* index in log page data area of first word to move */ words = min(nwords,j + 1); /* words on this page to move */ ptr = target + nwords - 1; /* last word of target */ for (n = 0; n < words; n++) { *ptr = logp[*buf].data[j]; j = j - 1; ptr = ptr - 1; } *offset = *offset - 4*words; /* * If partial log record is on the previous page, * or we have read all the log records in the current page, * get the previous page */ if ( words != nwords /* we get less than nwords */ || j < 0) /* or exhaust the page, so offset is just */ /* the page head, then j < 0 */ { /* get previous page */ pno = logptr[*buf]; pno = pno - 1; /* if we hit beginning location of the log, go wrapped, read log record from the end location of the log */ if (pno == 1) pno = logsize - 1; *buf = getLogpage(pno); if (*buf < 0) { sprintf( message_parm_0, "(d) %d", pno ); msgprms[0] = message_parm_0; msgprmidx[0] = 0; sprintf( message_parm_1, "(d) %d", (*buf) ); msgprms[1] = message_parm_1; msgprmidx[1] = 0; fsck_send_msg( lrdo_MWREADFAIL, 0, 2 ); return(*buf); } *offset = LOGPSIZE - LOGPTLRSIZE; j = LOGPSIZE/4 - 4 - 1; /* index last word of data area */ /* move rest of nwords if any. this will never exhaust the page. */ for (n = 0; n < nwords - words ; n++) { *ptr = logp[*buf].data[j]; j = j - 1; ptr = ptr - 1; } *offset = *offset - 4*(nwords - words); } return(0); }
/* * NAME: logRead(logaddr , ld, dataptr) * * FUNCTION: reads the log record addressed by logaddr and * returns the address of the preceding log record. * * PARAMETERS: logaddr - address of the end of log record to read * Note: log is read backward, so this is * the address starting to read * ld - pointer to a log record descriptor * dataptr - pointer to data buffer * * RETURNS: < 0 - there is an i/o error in reading * > 0 - the address of the end of the preceding log record */ logRead( int32 logaddr, /* address of log record to read */ struct lrd *ld, /* pointer to a log record descriptor */ char * dataptr) /* pointer to buffer. LOGPSIZE long */ { int buf,off,rc,nwords, pno; /* get page containing logaddr into log buffer pool */ pno = BTOLOGPN(logaddr); if (pno != loglastp) { loglastp = pno; lognumread += 1; if (lognumread > logsize - 2) { logError(LOGWRAP,0); sprintf( message_parm_0, "(d) %d", lognumread ); msgprms[0] = message_parm_0; msgprmidx[0] = 0; fsck_send_msg( lrdo_LRLOGWRAP, 0, 1 ); return(JLOG_LOGWRAP); } } buf = getLogpage(pno); if (buf < 0) { sprintf( message_parm_0, "(d) %d", pno ); msgprms[0] = message_parm_0; msgprmidx[0] = 0; sprintf( message_parm_1, "(d) %d", buf ); msgprms[1] = message_parm_1; msgprmidx[1] = 0; fsck_send_msg( lrdo_LRREADFAIL, 0, 2 ); return(buf); } /* read the descriptor */ off = logaddr & (LOGPSIZE - 1) ; /* offset just past desc. */ rc = moveWords(LOGRDSIZE/4, (int32 *)ld, &buf, &off); if (rc < 0) { sprintf( message_parm_0, "(d) %d", rc ); msgprms[0] = message_parm_0; msgprmidx[0] = 0; fsck_send_msg( lrdo_LRMWFAIL1, 0, 1 ); return(rc); } /* read the data if there is any */ if (ld->length > 0) { if( ld->length > LOGPSIZE ) { /* @D1 */ rc = READLOGERROR; /* @D1 */ sprintf( message_parm_0, "(d) %d", pno ); /* @D1 */ msgprms[0] = message_parm_0; /* @D1 */ msgprmidx[0] = 0; /* @D1 */ fsck_send_msg( lrdo_LRMWFAIL3, 0, 1 ); /* @D1 */ return(rc); /* @D1 */ } /* @D1 */ nwords = (ld->length + 3)/4; /* if length is partial word, still read it */ rc = moveWords(nwords,(int32 *)dataptr,&buf,&off); if (rc < 0) { sprintf( message_parm_0, "(d) %d", rc ); msgprms[0] = message_parm_0; msgprmidx[0] = 0; fsck_send_msg( lrdo_LRMWFAIL2, 0, 1 ); return(rc); } } return(LOGPNTOB(logptr[buf]) + off); }
/* * 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: findEndOfLog() * * FUNCTION: Returns the address of the end of the last record in the log. * (i.e. the address of the byte following its descriptor). * * Note: At the first release, log page is not written in a ping pong * manner, so the logend is the binary search result * * The end of the log is found by finding the page with the * highest page number and for which h.eor == t.eor and * h.eor > 8 (i.e. a record ends on the page). * Page numbers are compared by comparing their difference * with zero (necessary because page numbers are allowed to wrap.) * * RETURNS: >0 - byte offset of last record * REFORMAT_ERROR(-3) - i/o error, reformat the log * MAJOR_ERROR(-2) - other major errors other than EIO. */ int32 findEndOfLog() { int32 left, right, pmax, pval, eormax, eorval, k, rc; /* binary search for logend */ left = 2; /* first page containing log records since page 0 is never used, page 1 is log superblock */ right = logsize - 1; /* last page containing log records */ if ((rc = pageVal(left, &eormax, &pmax)) < 0) { sprintf( message_parm_0, "(d) %d", rc ); msgprms[0] = message_parm_0; msgprmidx[0] = 0; fsck_send_msg( lrdo_FEOLPGV1FAIL, 0, 1 ); return(rc); } while ((right - left) > 1) { k = (left + right ) >> 1; if ((rc = pageVal(k, &eorval, &pval)) < 0) { sprintf( message_parm_0, "(d) %d", rc ); msgprms[0] = message_parm_0; msgprmidx[0] = 0; fsck_send_msg( lrdo_FEOLPGV2FAIL, 0, 1 ); return(rc); } if (pval - pmax > 0 ) { left = k; pmax = pval; eormax = eorval; } else right = k; } if ((rc = pageVal(right, &eorval, &pval)) < 0) { sprintf( message_parm_0, "(d) %d", rc ); msgprms[0] = message_parm_0; msgprmidx[0] = 0; fsck_send_msg( lrdo_FEOLPGV3FAIL, 0, 1 ); return(rc); } /* * the last thing to determine is whether it is the first page of * the last long log record and system was crashed when its second * page is written. If the eor of the chosen page is LOGPHDRSIZE, * then this page contains a partial log record, ( otherwise, the * the long log record's second page should be chosen ). * This page should be thrown away. its previous page will be * the real last log page. */ if (( pval - pmax ) > 0 ) { if (eorval == LOGPHDRSIZE ) { if ((rc = pageVal(right-1, &eorval, &pval)) < 0) { sprintf( message_parm_0, "(d) %d", rc ); msgprms[0] = message_parm_0; msgprmidx[0] = 0; fsck_send_msg( lrdo_FEOLPGV4FAIL, 0, 1 ); return(rc); } return(LOGPNTOB(right-1) + eorval); } else return(LOGPNTOB(right) + eorval); } else /* pmax will be returned */ { if ( eormax == LOGPHDRSIZE ) { left = (left == 2) ? logsize -1 : left - 1; if ((rc = pageVal(left, &eormax, &pmax)) < 0) { sprintf( message_parm_0, "(d) %d", rc ); msgprms[0] = message_parm_0; msgprmidx[0] = 0; fsck_send_msg( lrdo_FEOLPGV4AFAIL, 0, 1 ); return(rc); } } return(LOGPNTOB(left) + eormax); } }
/****************************************************************** * NAME: get_LVM_BadBlockList_count * * FUNCTION: Query the LVM for the number of tables composing) its bad * block list for the file system. * * PARAMETERS: none * * NOTES: * * RETURNS: * success: 0 * failure: something else */ int32 get_LVM_BadBlockList_count( int32 *list_count ) { int32 glbblc_rc = 0; DDI_OS2LVM_param LVMpp; DDI_OS2LVM_param *pLVMpp = &LVMpp; DDI_OS2LVM_data LVMdp; DDI_OS2LVM_data *pLVMdp = &LVMdp; ULONG ppLen = 0; ULONG dpLen = 0; int32 min_bufsize; int32 bufsize = 1024; char *bufptr = NULL; BadBlockInfo *BB_bufptr = NULL; BadBlockTableInfo *BBT_bufptr = NULL; int32 tablesize; RelocationTable *RTable = NULL; int32 alloc_rc = 0; int I_am_logredo = 0; /* * initialize the LVM DosDevIOCtl parm and data packets */ pLVMpp->Command = 0; pLVMpp->DriveUnit = 0; pLVMpp->TableNumber = 0; pLVMpp->LSN = 0; pLVMdp->ReturnData = 0; pLVMdp->UserBuffer = NULL; /* * allocate a buffer */ alloc_rc = alloc_wrksp( bufsize, dynstg_fsckcbblbuf2, I_am_logredo, (void **) &bufptr ); if( (bufptr == NULL) || (alloc_rc != FSCK_OK) ) { return( FSCK_ENOMEMBDBLK1 ); } /* * ask the LVM how many bad block lists it has for the filesystem */ pLVMpp->Command = GET_BBR_INFO; pLVMdp->UserBuffer = bufptr; glbblc_rc = DosDevIOCtl( Dev_IOPort, IOC_DC, IODC_LV, (void *) pLVMpp, sizeof(DDI_OS2LVM_param), &ppLen, (void *) pLVMdp, sizeof(DDI_OS2LVM_data), &dpLen ); sprintf( message_parm_0, "%ld", glbblc_rc ); msgprms[0] = message_parm_0; msgprmidx[0] = 0; fsck_send_msg( fsck_LVMGETBBLKINFORC, 0, 1 ); if( glbblc_rc != 0 ) { return( glbblc_rc ); } else { /* DosDevIOCtl successful */ if( pLVMdp->ReturnData != BBR_SUCCESS ) { /* cat 8, funct 69 failed */ glbblc_rc = pLVMdp->ReturnData; } else { BB_bufptr = (BadBlockInfo *) bufptr; *list_count = BB_bufptr->TotalTables; sprintf( message_parm_0, "%ld", BB_bufptr->TotalTables ); msgprms[0] = message_parm_0; msgprmidx[0] = 0; fsck_send_msg( fsck_CLRBBLVMNUMLISTS, 0, 1 ); } } /* end else DosDevIOCtl successful */ return( glbblc_rc ); } /* end get_LVM_BadBlockList_count() */
/****************************************************************** * NAME: examine_LVM_BadBlockLists * * FUNCTION: Query the LVM for (the set of tables composing) its bad * block list for the file system. Save the buffers containing * the tables for use populating the JFS Bad Block Inode later. * * PARAMETERS: none * * NOTES: * * RETURNS: * success: 0 * failure: something else */ int32 examine_LVM_BadBlockLists( int32 list_count, int32 *max_fill_level ) { int32 elbbl_rc = 0; int8 buffer_allocated = 0; int32 bbl_idx; DDI_OS2LVM_param LVMpp; DDI_OS2LVM_param *pLVMpp = &LVMpp; DDI_OS2LVM_data LVMdp; DDI_OS2LVM_data *pLVMdp = &LVMdp; ULONG ppLen = 0; ULONG dpLen = 0; int32 bufsize = 1024; char *bufptr = NULL; BadBlockTableInfo *BBT_bufptr = NULL; int32 num_entries, max_entries; int32 this_percent, highest_percent = 0; int32 alloc_rc = 0; int I_am_logredo = 0; /* * initialize the LVM DosDevIOCtl parm and data packets */ pLVMpp->Command = 0; pLVMpp->DriveUnit = 0; pLVMpp->TableNumber = 0; pLVMpp->LSN = 0; pLVMdp->ReturnData = 0; pLVMdp->UserBuffer = NULL; /* * allocate a buffer */ alloc_rc = alloc_wrksp( bufsize, dynstg_fsckcbblbuf1, I_am_logredo, (void **) &bufptr ); if( (bufptr == NULL) || (alloc_rc != FSCK_OK) ) { elbbl_rc = FSCK_ENOMEMBDBLK2; } else { buffer_allocated = -1; } /* * * get info about each of the LVM Bad Block Tables * */ for( bbl_idx = 0; ( (bbl_idx < list_count) && (elbbl_rc == 0) ); bbl_idx++ ) { /* * ask the LVM how big this table is. */ pLVMpp->Command = GET_TBL_SIZE; pLVMpp->TableNumber = bbl_idx; pLVMdp->ReturnData = 0; pLVMdp->UserBuffer = bufptr; elbbl_rc = DosDevIOCtl( Dev_IOPort, IOC_DC, IODC_LV, (void *) pLVMpp, sizeof(DDI_OS2LVM_param), &ppLen, (void *) pLVMdp, sizeof(DDI_OS2LVM_data), &dpLen ); sprintf( message_parm_0, "%ld", elbbl_rc ); msgprms[0] = message_parm_0; msgprmidx[0] = 0; fsck_send_msg( fsck_LVMGETTBLSIZERC, 0, 1 ); if( elbbl_rc == 0 ) { /* DosDevIOCtl successful */ if( pLVMdp->ReturnData != BBR_SUCCESS ) { /* cat 8, funct 69 failed */ elbbl_rc = pLVMdp->ReturnData; break; } else { BBT_bufptr = (BadBlockTableInfo *) bufptr; num_entries = BBT_bufptr->ActiveRelocations; max_entries = BBT_bufptr->MaxRelocationsAllowed; sprintf( message_parm_0, "%ld", bbl_idx ); msgprms[0] = message_parm_0; msgprmidx[0] = 0; sprintf( message_parm_1, "%ld", max_entries ); msgprms[1] = message_parm_1; msgprmidx[1] = 0; sprintf( message_parm_2, "%ld", num_entries ); msgprms[2] = message_parm_2; msgprmidx[2] = 0; fsck_send_msg( fsck_CLRBBLVMLISTDATA, 0, 3 ); } } /* end else DosDevIOCtl successful */ /* * * If the table isn't empty * */ if( (elbbl_rc == 0) && (num_entries > 0) && (max_entries > 0)) { /* * successful so far and the * current table isn't empty */ this_percent = (num_entries * 100) / max_entries; if( this_percent > highest_percent ) { highest_percent = this_percent; } } /* end successful so far and table not empty */ } /* end for bbl_idx */ /* * free the buffer */ if( elbbl_rc == 0 ) { *max_fill_level = highest_percent; } else { *max_fill_level = 0; } return( elbbl_rc ); } /* end examine_LVM_BadBlockLists() */
/***************************************************************************** * NAME: ClrBdBlkLst_processing * * FUNCTION: Invoke the JFS processing to clear the LVM's bad block list. * * PARAMETERS: none * * NOTES: Starts a child process for the utility. * * RETURNS: * success: FSCK_OK * failure: something else */ retcode_t ClrBdBlkLst_processing ( ) { retcode_t kcbbl_rc = FSCK_OK; retcode_t intermed_rc = FSCK_OK; retcode_t redeterm_rc = FSCK_OK; //PS21032004 struct fsckcbbl_record *cbblrecptr; int I_am_logredo = 0; cbblrecptr = &(agg_recptr->blkmp_ctlptr->cbblrec); if( cbblrecptr == NULL ) { if( agg_recptr->blkmp_ctlptr == NULL ) { intermed_rc = alloc_wrksp( sizeof(fsck_blk_map_hdr_t), dynstg_blkmap_hdr, I_am_logredo, (void **) &(agg_recptr->blkmp_ctlptr) ); if( intermed_rc == FSCK_OK ) { strncpy( agg_recptr->blkmp_ctlptr->hdr.eyecatcher, fbmh_eyecatcher_string, strlen(fbmh_eyecatcher_string)); /* fill eyecatcher */ } } intermed_rc = blkmap_get_ctl_page ( agg_recptr->blkmp_ctlptr ); if( intermed_rc == FSCK_OK ) { cbblrecptr = &(agg_recptr->blkmp_ctlptr->cbblrec); } } if( cbblrecptr != NULL ) { memcpy( (void *) &(cbblrecptr->eyecatcher), (void *) "*unset**", 8 ); intermed_rc = blkmap_put_ctl_page ( agg_recptr->blkmp_ctlptr ); } fsck_send_msg( fsck_LVMFSNOWAVAIL, 0, 0 ); fsck_send_msg( fsck_LVMTRNSBBLKSTOJFS, 0, 0 ); /* * close the file system so clrbblks can get it */ //PS24072004 close_volume(); //PS21032004 kcbbl_rc = exec_clrbdblks( ); //PS21032004 Begin redeterm_rc = ujfs_redeterminemedia( Dev_IOPort ); sprintf( message_parm_0, "%ld", redeterm_rc ); msgprms[0] = message_parm_0; msgprmidx[0] = 0; fsck_send_msg( fsck_DEVREDETERMRC, 0, 1 ); kcbbl_rc = clrbblks( 0, 0, Dev_IOPort, Vol_Label); if(( !agg_recptr->parm_options[UFS_CHKDSK_AUTOCHECK] ) && ( !agg_recptr->parm_options[UFS_CHKDSK_CLRBDBLKLST] )) { // beginformat called unmount -> flush the JFS cache. redeterm_rc = ujfs_beginformat( Dev_IOPort ); sprintf( message_parm_0, "%ld", redeterm_rc ); msgprms[0] = message_parm_0; msgprmidx[0] = 0; fsck_send_msg( fsck_DEVBEGINFMTRC, 0, 1 ); } /* * open the file system and get the clrbblks * communication area */ //PS21032004 End //PS21032004 open_volume( Vol_Label ); intermed_rc = blkmap_get_ctl_page ( agg_recptr->blkmp_ctlptr ); if( intermed_rc == FSCK_OK ) { if( memcmp((void *)&(cbblrecptr->eyecatcher),(void *)"*unset**", 8) != 0 ) { /* * The eyecatcher field was reset. there is good reason to * believe that clrbblks processing did actually write to the * record. */ sprintf( message_parm_0, "%ld", cbblrecptr->cbbl_retcode ); msgprms[0] = message_parm_0; msgprmidx[0] = 0; fsck_send_msg( fsck_CLRBBLKSRC, 0, 1 ); sprintf( message_parm_0, "%ld", cbblrecptr->LVM_lists ); msgprms[0] = message_parm_0; msgprmidx[0] = 0; fsck_send_msg( fsck_CLRBBLVMNUMLISTS, 0, 1 ); sprintf( message_parm_0, "%lld", (cbblrecptr->fs_last_metablk+1) ); msgprms[0] = message_parm_0; msgprmidx[0] = 0; sprintf( message_parm_1, "%lld", (cbblrecptr->fs_first_wspblk-1) ); msgprms[1] = message_parm_1; msgprmidx[1] = 0; fsck_send_msg( fsck_CLRBBRANGE, 0, 2 ); sprintf( message_parm_0, "%ld", cbblrecptr->reloc_extents ); msgprms[0] = message_parm_0; msgprmidx[0] = 0; sprintf( message_parm_1, "%ld", cbblrecptr->reloc_blocks ); msgprms[1] = message_parm_1; msgprmidx[1] = 0; fsck_send_msg( fsck_CLRBBACTIVITY, 0, 2 ); sprintf( message_parm_0, "%ld", cbblrecptr->total_bad_blocks ); msgprms[0] = message_parm_0; msgprmidx[0] = 0; sprintf( message_parm_1, "%ld", cbblrecptr->resolved_blocks ); msgprms[1] = message_parm_1; msgprmidx[1] = 0; fsck_send_msg( fsck_CLRBBRESULTS, 0, 2 ); } } return( kcbbl_rc ); } /* end of ClrBdBlkLst_processing() */