⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 reclaim.c

📁 是一个手机功能的模拟程序
💻 C
📖 第 1 页 / 共 3 页
字号:
                lower <= ip->location && ip->location < upper)
            {
                if ((result = object_relocate(i)) < 0) {
                    tw(tr(TR_FUNC, TrAll, "FATAL object_relocate failed\n"));
                    break;
				}
                
                // If we reclaim a segment head or wch that is in use we must
                // update the file descriptor as well
                for (j = 0; j < fs.fd_max; j++) {
                    if (i == fs.fd[j].seghead) {
                        tw(tr(TR_FUNC, TrDReclaim, 
                              "Updated seghead %d -> %d \n",
                              fs.fd[j].seghead, result));
                        fs.fd[j].seghead = result;
                    }
                    if (i == fs.fd[j].wch) {
                        tw(tr(TR_FUNC, TrDReclaim, 
                              "Updated wch %d -> %d \n",
                              fs.fd[j].wch, result));
                        fs.fd[j].wch = result;
                    }
                }

                // If we have just reclaimed an object which we started on
                // updating we must also update ojournal
                if (i == fs.ojournal.oldi) {
                    struct inode_s *ip = inode_addr(result);
                    tw(tr(TR_FUNC, TrDReclaim, 
                          "Updated ojournal oldi %d -> %d \n",
                          fs.ojournal.oldi, result));
                    fs.ojournal.oldi     = result;
                    fs.ojournal.location = ip->location;
                }

                if (i == fs.ojournal.diri || i == -fs.ojournal.diri) {
                    fs.ojournal.diri = (fs.ojournal.diri < 0 ? -result : result);
                    tw(tr(TR_FUNC, TrDReclaim, 
                          "Updated ojournal: diri %d -> %d \n", 
                          i, fs.ojournal.diri));
                }

                if (i == fs.ojournal.repli || i == -fs.ojournal.repli) {
                    fs.ojournal.repli = (fs.ojournal.repli < 0 ? -result : result);
                    tw(tr(TR_FUNC, TrDReclaim, 
                          "Updated ojournal: repli %d -> %d \n", 
                          i, fs.ojournal.repli));
                }
 
                if (i == fs.i_backup || i == -fs.i_backup) {
                    fs.i_backup = (fs.i_backup < 0 ? -result : result);
                    tw(tr(TR_FUNC, TrDReclaim, 
                          "Updated i_backup: %d -> %d \n", i, fs.i_backup));
                }

                n++;
            }
        }

		fs.block_files_reserved = org_block_files_reserved; // Restore
		fs.reserved_space = org_res_space;

        tw(tr(TR_FUNC, TrDReclaim, "Reclaimed %d objects\n", n));
        if (result >= 0)
            result = n; // We return number of objects relocated

        if (i < fs.inodes_max) {
            // We did not finish, so restore the old bstat[].used of the block.
            bstat[b].used = used_old;
            tw(tr(TR_FUNC, TrAll,
                  "WARNING: data_block_reclaim() not completed\n"));
            result = EFFS_DBR;
		}

        // Restore the saved journal state
        if (journal_pop() != EFFS_OK) {
			is_reclaim_running = 0;       // NOTEME: change to goto?
			return EFFS_CORRUPTED;
		}
    }
	BLOCK_RECLAIM_TEST(BLOCK_RECLAIM_NO_CLEAN, "Oops before clean old data block");

    if (result >= 0) {
        // Clean the block (remove all inodes that refer to this block)
        block_flags_write(b, BF_CLEANING);
        block_clean(b);

        statistics_update_drec(used_old - lost_old, lost_old, candidate); 
    
		BLOCK_RECLAIM_TEST(BLOCK_RECLAIM_CLEANING, "Oops before free old data block");

        // Free the old block
        block_free(b);
    }

	is_reclaim_running = 0;

    tw(tr(TR_END, TrDReclaim, "} (data_block_reclaim) %d\n", result));
    ttw(ttr(TTrRec, "} %d" NL, result));

    return result;
}

// Relocate object represented by inode reference <i>. 
iref_t object_relocate(iref_t oldi)
{
    iref_t newi;
    struct inode_s *oldip;
    char *olddata, *oldname;
    int oldsize;

    tw(tr(TR_BEGIN, TrReclaimLow, "object_relocate(%d) {\n", oldi));

    journal_begin(oldi);

    oldip = inode_addr(oldi);

    oldsize = segment_datasize(oldip);
    olddata = offset2addr(location2offset(oldip->location));
    oldname = addr2name(olddata);
    olddata = addr2data(olddata, oldip);
    
    if (is_object(oldip, OT_SEGMENT))     
        newi = segment_create(olddata, oldsize, -oldi);   
    else {
        // root inode is a special case
        if (*oldname == '/')
            newi = object_create(oldname, olddata, oldsize, 0);
        else 
            newi = object_create(oldname, olddata, oldsize, oldi);
    }

    if (newi < 0) {
        tw(tr(TR_END, TrReclaimLow, "} %d\n", newi));
        return newi;
    }

    // root inode is a special case
    if ((*oldname == '/') && !is_object(oldip, OT_SEGMENT)) {
        tw(tr(TR_FUNC, TrDReclaim, "Relocating fs.root: %d->%d\n", oldi, newi));
        fs.root = newi;
    }

    journal_end(0);

    tw(tr(TR_END, TrReclaimLow, "} %d\n", newi));

    return newi;
}

// Clean a block, eg. erase all inodes that refer to this block.
iref_t block_clean(bref_t b)
{
    iref_t i, n;
    struct inode_s *ip;
    offset_t lower, upper;

    tw(tr(TR_FUNC, TrDReclaim, "block_clean(%d) { ", b));

    // Compute lower (inclusive) and upper (exclusive) bounds of the
    // location of files in this block
    lower = offset2location(dev.binfo[b].offset);
    upper = offset2location(dev.binfo[b].offset + dev.blocksize);

    tw(tr(TR_FUNC, TrDReclaim, "offset range = 0x%X..0x%X: ", lower, upper));

    ip = inode_addr(1);
    for (i = 1, n = 0; i < fs.inodes_max; i++, ip++)
    {
        // Ensure object is within the block to be reclaimed. Note: if ffs
        // is conf. with 1MB or above will all not used inodes default have
        // the location to FFFF which will trigger a clean and make a error!
        if (lower <= ip->location && upper > ip->location)
        {
            tw(tr(TR_NULL, TrReclaimLow, "%d ", i));
            // Set the size to zero so it won't be counted in ffs_initialize()
            ffsdrv.write_halfword((uint16 *) &ip->size, 0);
            n++;
        }
    }
    tw(tr(TR_NULL, TrDReclaim, "} %d\n", n));

    return n;
}


/******************************************************************************
 * Main and block reclaim
 ******************************************************************************/

// Reclaim (erase) all blocks that are marked as invalid/reclaimable. Each
// time a block is erased, its age is incremented so as to support wear
// levelling. Also, the global age limits are updated.  FIXME: Should we
// avoid having ffs_initialize() do a block_reclaim() because it delays reboot?.
int blocks_reclaim(void)
{
    bref_t b, n, b_lost_space;
	int blocks_free = 0, lost_space;

	int free_space, b_free_space;

    tw(tr(TR_BEGIN, TrBlock, "blocks_reclaim() {\n"));
    ttw(str(TTrRec, "blocks_reclaim() {" NL));

    // Testing of fs.testflags is for the sake of testing block_commit()
    if ((fs.testflags & BLOCK_COMMIT_BASE) != 0) {
        tw(tr(TR_FUNC, TrBlock, "Bailing out because fs.testflags = 0x%X\n",
              fs.testflags));
    }
    else {
        for (b = 0, n = 0; b < dev.numblocks; b++) {
            if (is_block_flag(b, BF_LOST)) {
                block_reclaim(b);
                n++;
            }
			if (is_block(b, BF_IS_FREE)) {
				blocks_free++;
			}
        }
    }

	// If the number of free blocks is less than fs.blocks_free_min we
	// call data_block_reclaim(). We will reclaim the block with most lost
	// space. This should only happend if we got a sudden power off/reset
	// while we reclaimed a block.
	if (blocks_free < fs.blocks_free_min) {
		lost_space = 0;
		free_space = 0;

		// We most never reclaim the block with most free space because this
		// is the only block we can relocate the objects to.
		for (b = 0; b < dev.numblocks; b++) {
			if (is_block_flag(b, BF_DATA)) {
				if ((dev.blocksize - bstat[b].used) > free_space) {
					free_space = dev.blocksize - bstat[b].used;
					b_free_space = b;
				}
			}
		}
		tw(tr(TR_FUNC, TrBlock, "most free space: %d in block: %d \n", 
			  free_space, b_free_space));

		for (b = 0; b < dev.numblocks; b++) {
			if (is_block_flag(b, BF_DATA) && b != b_free_space) {
				if (bstat[b].lost > lost_space) {
					lost_space = bstat[b].lost;
					b_lost_space = b;
				}
			}
		}
		tw(tr(TR_FUNC, TrBlock, "most lost space: %d in block: %d \n", 
			  lost_space, b_lost_space));

		data_block_reclaim(b_lost_space, MOST_LOST);
	}
    tw(tr(TR_END, TrBlock, "} %d\n", n));
    ttw(ttr(TTrRec, "} %d" NL, n));

    return n;
}

int block_reclaim(bref_t b)
{
    age_t age;
    struct block_header_s *bhp;

    tw(tr(TR_BEGIN, TrBlock, "block_reclaim(%d) {\n", b));

    // In ffs_initialize() we set fs.initerror = EFFS_INVALID while we call
    // blocks_fsck(). We test for that condition now, in order to avoid
    // doing sector erases that will delay the whole target boot process.
    if (fs.initerror == EFFS_INVALID) {
        tw(tr(TR_END, TrBlock, "} %d\n", fs.initerror));
        return fs.initerror;
    }

    // Testing of fs.testflags is for the sake of testing block_commit()
    if ((fs.testflags & BLOCK_COMMIT_BASE) != 0 && 
		fs.testflags != BLOCK_COMMIT_OLD_FREE) {
        tw(tr(TR_FUNC, TrBlock, "Bailing out because fs.testflags = 0x%X\n",
              fs.testflags));
    }
    else {
        // We must read block's age before we erase it.
        bhp = (struct block_header_s *) offset2addr(dev.binfo[b].offset);
        age = bhp->age;
        ffsdrv.erase(b);
        block_preformat(b, age);
    }

    tw(tr(TR_END, TrBlock, "} %d\n", 0));

    return 0;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -