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

📄 reclaim.c

📁 MMI层OBJ不能完全编译
💻 C
📖 第 1 页 / 共 2 页
字号:

    // If the amount of free space is below RESERVED_LOW we MUST not reclaim
    // the youngest block because the youngest block does not necessarily
    // contain any lost space that can be freed and in some cases we needs free
    // space for a new journal file.
     if (reserved_ok == 0) {
        tw(tr(TR_FUNC, TrDReclaim, 
              "No reserved, reclaim most-lost block (%d)\n", brc_lost_b));
        result = data_block_reclaim(brc_lost_b, MOST_LOST);
    }
    else if (dage_max_reached(brc_young_dage, age_gain) > 0 ) {
        tw(tr(TR_FUNC, TrDReclaim, "Reclaiming youngest block (%d)\n",
              brc_young_b));
        result = data_block_reclaim(brc_young_b, YOUNGEST);
    }
    else {
        tw(tr(TR_FUNC, TrDReclaim, "Reclaiming most-lost block (%d)\n",
              brc_lost_b));
        result = data_block_reclaim(brc_lost_b, MOST_LOST);
    }

    tw(tr(TR_END, TrDReclaim, "} (data_reclaim_try) %d\n", result));

    return result;
}

iref_t data_block_reclaim(bref_t b, int candidate)
{
    // 1. If there are more objects in this block than there are remaining
    // free inodes, we have to make an inodes_reclaim() first.
    //
    // 2. Relocate each valid object from old block (to another block). An
    // object relocation is similar to a normal file update, e.g. similar to
    // fupdate().
    //
    // 3. set BF_CLEANING flag of old block.
    //
    // 4. ALL inodes (also invalid an erased ones) referring into reclaimed
    // block must now be totally wiped out.
    //
    // 5. Free (invalidate) old block.

    iref_t i, n, j;
    blocksize_t used_old, lost_old;
	int org_res_space, result = 0;
	iref_t org_block_files_reserved;
    offset_t lower, upper;
    struct inode_s *ip;

    tw(tr(TR_BEGIN, TrDReclaim, "data_block_reclaim(%d) {\n", b));

    // In case of no free blocks (after sudden power off) or if the file
    // system is near full we risk to be reentered (infinity recursively
    // loop) and we can not allow that, so just return.
	if (fs.is_reclaim_running == 1) {
		tw(tr(TR_END, TrDReclaim, "} (reenteret skip reclaim) 0\n"));
		return EFFS_RECLAIMLOOP;
	}
	fs.is_reclaim_running = 1;

    // If there are more objects in this block than there are remaining
    // free inodes, we have to make an inodes_reclaim() first.
    tw(tr(TR_FUNC, TrDReclaim,
          "block_objects, fs.inodes_max, inodes: used, free\n"));
    tw(tr(TR_FUNC, TrDReclaim,
          "%10d, %13d, %15d, %4d\n",
          bstat[b].objects,
          fs.inodes_max, bstat[fs.inodes].used,
          fs.inodes_max - (bstat[fs.inodes].used + bstat[fs.inodes].lost)));

    if (bstat[b].objects >= (fs.inodes_max - (bstat[fs.inodes].used + 
                                              bstat[fs.inodes].lost + 
                                              FFS_INODES_MARGIN))) {
        tw(tr(TR_FUNC, TrInode, "NOTE: Will run out of free inodes...\n"));
        inodes_reclaim();
    }

    // Allocate a new block. NOTE: we don't return an error because if we
	// get in the situation where we don't have any free blocks this is the
	// only way to recover.
    if ((block_alloc(1, BF_DATA)) < 0) {
        tw(tr(TR_FUNC, TrAll, "WARNING: block_alloc failed\n"));
    }

    // If there are any objects at all to reclaim...
    if (bstat[b].objects > 0)
    {
        // Save the current journal state
        if (journal_push() != EFFS_OK) {
			fs.is_reclaim_running = 0;       // NOTEME: change to goto?
			return EFFS_CORRUPTED;
		}

        // We simulate that this block is completely full, such that we
        // don't relocate files to the end of the block
        used_old = bstat[b].used;
        lost_old = bstat[b].lost;  // For statistics
        bstat[b].used = dev.blocksize - 1;


        // 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, "Block addr range = 0x%X..0x%X\n",
              location2offset(lower), location2offset(upper)));

		// This is the only time we are allowed to use the reserved 
		org_block_files_reserved= fs.block_files_reserved;
		fs.block_files_reserved = 0;

		org_res_space = fs.reserved_space;
        fs.reserved_space = RESERVED_NONE;

		ip = inode_addr(1);
        for (i = 1, n = 0; i < fs.inodes_max; i++, ip++)
        {
            // Ensure object is valid and within the block to be reclaimed
            if (is_object_valid(ip) &&
                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_ram.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_ram.repli || i == -fs.ojournal_ram.repli) {
                    fs.ojournal_ram.repli = (fs.ojournal_ram.repli < 0 ? -result : result);
                    tw(tr(TR_FUNC, TrDReclaim, 
                          "Updated ojournal: repli %d -> %d \n", 
                          i, fs.ojournal_ram.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) {
			fs.is_reclaim_running = 0;       // NOTEME: change to goto?
			return EFFS_CORRUPTED;
		}
    }

    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); 
    
        // Free the old block
        block_free(b);
    }

	fs.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, OTE_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, OTE_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. 
        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));

    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++;
        }
    }
	ttr(TTrTask, "b=%d" NL, b);
	// 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));
	ttr(TTrTask, "n = %d, free blocks=%d" NL, n, blocks_free);

    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;
    }

    // We must read block's age before we erase it.
    bhp = (struct block_header_s *) offset2addr(dev.binfo[b].offset);
    age = bhp->age;

    POWERFAIL_DOMAIN_BEGIN(PFM_ERASE | PFM_NEXTERASE);
    ffsdrv.erase(b);
    POWERFAIL_DOMAIN_END();

    block_preformat(b, age);

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

    return 0;
}

⌨️ 快捷键说明

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