static void account_shadow(void *_shadow, unsigned long _sb, u64 ignore,
		size_t ignore2)
{
	struct logfs_shadow *shadow = _shadow;
	struct super_block *sb = (void *)_sb;
	struct logfs_super *super = logfs_super(sb);

	
	super->s_free_bytes	  -= shadow->new_len;
	super->s_used_bytes	  += shadow->new_len;
	super->s_dirty_used_bytes -= shadow->new_len;

	
	super->s_free_bytes	  += shadow->old_len;
	super->s_used_bytes	  -= shadow->old_len;
	super->s_dirty_free_bytes -= shadow->old_len;

	logfs_set_segment_used(sb, shadow->old_ofs, -shadow->old_len);
	logfs_set_segment_used(sb, shadow->new_ofs, shadow->new_len);

	log_journal("account_shadow(%llx, %llx, %x) %llx->%llx %x->%x\n",
			shadow->ino, shadow->bix, shadow->gc_level,
			shadow->old_ofs, shadow->new_ofs,
			shadow->old_len, shadow->new_len);
	mempool_free(shadow, super->s_shadow_pool);
}
Beispiel #2
0
void do_logfs_journal_wl_pass(struct super_block *sb)
{
	struct logfs_super *super = logfs_super(sb);
	struct logfs_area *area = super->s_journal_area;
	u32 segno, ec;
	int i, err;

	log_journal("Journal requires wear-leveling.\n");
	/* Drop old segments */
	journal_for_each(i)
		if (super->s_journal_seg[i]) {
			logfs_set_segment_unreserved(sb,
					super->s_journal_seg[i],
					super->s_journal_ec[i]);
			super->s_journal_seg[i] = 0;
			super->s_journal_ec[i] = 0;
		}
	/* Get new segments */
	for (i = 0; i < super->s_no_journal_segs; i++) {
		segno = get_best_cand(sb, &super->s_reserve_list, &ec);
		super->s_journal_seg[i] = segno;
		super->s_journal_ec[i] = ec;
		logfs_set_segment_reserved(sb, segno);
	}
	/* Manually move journal_area */
	area->a_segno = super->s_journal_seg[0];
	area->a_is_open = 0;
	area->a_used_bytes = 0;
	/* Write journal */
	logfs_write_anchor(sb);
	/* Write superblocks */
	err = logfs_write_sb(sb);
	BUG_ON(err);
}
void do_logfs_journal_wl_pass(struct super_block *sb)
{
    struct logfs_super *super = logfs_super(sb);
    struct logfs_area *area = super->s_journal_area;
    struct btree_head32 *head = &super->s_reserved_segments;
    u32 segno, ec;
    int i, err;

    log_journal("Journal requires wear-leveling.\n");
    /* Drop old segments */
    journal_for_each(i)
    if (super->s_journal_seg[i]) {
        btree_remove32(head, super->s_journal_seg[i]);
        logfs_set_segment_unreserved(sb,
                                     super->s_journal_seg[i],
                                     super->s_journal_ec[i]);
        super->s_journal_seg[i] = 0;
        super->s_journal_ec[i] = 0;
    }
    /* Get new segments */
    for (i = 0; i < super->s_no_journal_segs; i++) {
        segno = get_best_cand(sb, &super->s_reserve_list, &ec);
        super->s_journal_seg[i] = segno;
        super->s_journal_ec[i] = ec;
        logfs_set_segment_reserved(sb, segno);
        <<<<<<< HEAD
        err = btree_insert32(head, segno, (void *)1, GFP_NOFS);
        =======
static int logfs_read_segment(struct super_block *sb, u32 segno)
{
	struct logfs_super *super = logfs_super(sb);
	struct logfs_journal_header *jh = super->s_compressed_je;
	u64 ofs, seg_ofs = dev_ofs(sb, segno, 0);
	u32 h_ofs, last_ofs = 0;
	u16 len, datalen, last_len = 0;
	int i, err;

	
	for (h_ofs = 0; h_ofs < super->s_segsize; h_ofs += sizeof(*jh)) {
		ofs = seg_ofs + h_ofs;
		err = __read_je_header(sb, ofs, jh);
		if (err)
			continue;
		if (jh->h_type != cpu_to_be16(JE_COMMIT))
			continue;
		err = __read_je_payload(sb, ofs, jh);
		if (err)
			continue;
		len = be16_to_cpu(jh->h_len);
		datalen = be16_to_cpu(jh->h_datalen);
		if ((datalen > sizeof(super->s_je_array)) ||
				(datalen % sizeof(__be64)))
			continue;
		last_ofs = h_ofs;
		last_len = datalen;
		h_ofs += ALIGN(len, sizeof(*jh)) - sizeof(*jh);
	}
	
	if (last_ofs == 0)
		return -ENOENT;
	ofs = seg_ofs + last_ofs;
	log_journal("Read commit from %llx\n", ofs);
	err = __read_je(sb, ofs, jh);
	BUG_ON(err); 
	if (err)
		return err;
	
	unpack(jh, super->s_je_array);
	super->s_no_je = last_len / sizeof(__be64);
	
	for (i = 0; i < super->s_no_je; i++) {
		err = read_je(sb, be64_to_cpu(super->s_je_array[i]));
		if (err)
			return err;
	}
	super->s_journal_area->a_segno = segno;
	return 0;
}
static int logfs_write_obj_aliases(struct super_block *sb)
{
	struct logfs_super *super = logfs_super(sb);
	int err;

	log_journal("logfs_write_obj_aliases: %d aliases to write\n",
			super->s_no_object_aliases);
	super->s_je_fill = 0;
	err = logfs_write_obj_aliases_pagecache(sb);
	if (err)
		return err;

	if (super->s_je_fill)
		err = logfs_write_je_buf(sb, super->s_je, JE_OBJ_ALIAS,
				super->s_je_fill
				* sizeof(struct logfs_obj_alias));
	return err;
}
void do_logfs_journal_wl_pass(struct super_block *sb)
{
	struct logfs_super *super = logfs_super(sb);
	struct logfs_area *area = super->s_journal_area;
	struct btree_head32 *head = &super->s_reserved_segments;
	u32 segno, ec;
	int i, err;

	log_journal("Journal requires wear-leveling.\n");
	
	journal_for_each(i)
		if (super->s_journal_seg[i]) {
			btree_remove32(head, super->s_journal_seg[i]);
			logfs_set_segment_unreserved(sb,
					super->s_journal_seg[i],
					super->s_journal_ec[i]);
			super->s_journal_seg[i] = 0;
			super->s_journal_ec[i] = 0;
		}
	
	for (i = 0; i < super->s_no_journal_segs; i++) {
		segno = get_best_cand(sb, &super->s_reserve_list, &ec);
		super->s_journal_seg[i] = segno;
		super->s_journal_ec[i] = ec;
		logfs_set_segment_reserved(sb, segno);
		err = btree_insert32(head, segno, (void *)1, GFP_NOFS);
		BUG_ON(err); 
		err = logfs_erase_segment(sb, segno, 1);
		BUG_ON(err); 
	}
	
	freeseg(sb, area->a_segno);
	area->a_segno = super->s_journal_seg[0];
	area->a_is_open = 0;
	area->a_used_bytes = 0;
	
	logfs_write_anchor(sb);
	
	err = logfs_write_sb(sb);
	BUG_ON(err);
}
void do_logfs_journal_wl_pass(struct super_block *sb)
{
	struct logfs_super *super = logfs_super(sb);
	struct logfs_area *area = super->s_journal_area;
	struct btree_head32 *head = &super->s_reserved_segments;
	u32 segno, ec;
	int i, err;

	log_journal("Journal requires wear-leveling.\n");
	/* Drop old segments */
	journal_for_each(i)
		if (super->s_journal_seg[i]) {
			btree_remove32(head, super->s_journal_seg[i]);
			logfs_set_segment_unreserved(sb,
					super->s_journal_seg[i],
					super->s_journal_ec[i]);
			super->s_journal_seg[i] = 0;
			super->s_journal_ec[i] = 0;
		}
	/* Get new segments */
	for (i = 0; i < super->s_no_journal_segs; i++) {
		segno = get_best_cand(sb, &super->s_reserve_list, &ec);
		super->s_journal_seg[i] = segno;
		super->s_journal_ec[i] = ec;
		logfs_set_segment_reserved(sb, segno);
		err = btree_insert32(head, segno, (void *)1, GFP_KERNEL);
		BUG_ON(err); /* mempool should prevent this */
		err = logfs_erase_segment(sb, segno, 1);
		BUG_ON(err); /* FIXME: remount-ro would be nicer */
	}
	/* Manually move journal_area */
	freeseg(sb, area->a_segno);
	area->a_segno = super->s_journal_seg[0];
	area->a_is_open = 0;
	area->a_used_bytes = 0;
	/* Write journal */
	logfs_write_anchor(sb);
	/* Write superblocks */
	err = logfs_write_sb(sb);
	BUG_ON(err);
}
static void journal_get_free_segment(struct logfs_area *area)
{
	struct logfs_super *super = logfs_super(area->a_sb);
	int i;

	journal_for_each(i) {
		if (area->a_segno != super->s_journal_seg[i])
			continue;

		do {
			i++;
			if (i == LOGFS_JOURNAL_SEGS)
				i = 0;
		} while (!super->s_journal_seg[i]);

		area->a_segno = super->s_journal_seg[i];
		area->a_erase_count = ++(super->s_journal_ec[i]);
		log_journal("Journal now at %x (ec %x)\n", area->a_segno,
				area->a_erase_count);
		return;
	}
	BUG();
}
/*
 * Write all journal entries.  The goto logic ensures that all journal entries
 * are written whenever a new segment is used.  It is ugly and potentially a
 * bit wasteful, but robustness is more important.  With this we can *always*
 * erase all journal segments except the one containing the most recent commit.
 */
void logfs_write_anchor(struct super_block *sb)
{
	struct logfs_super *super = logfs_super(sb);
	struct logfs_area *area = super->s_journal_area;
	int i, err;

	if (!(super->s_flags & LOGFS_SB_FLAG_DIRTY))
		return;
	super->s_flags &= ~LOGFS_SB_FLAG_DIRTY;

	BUG_ON(super->s_flags & LOGFS_SB_FLAG_SHUTDOWN);
	mutex_lock(&super->s_journal_mutex);

	
	logfs_sync_segments(sb);
	account_shadows(sb);

again:
	super->s_no_je = 0;
	for_each_area(i) {
		if (!super->s_area[i]->a_is_open)
			continue;
		super->s_sum_index = i;
		err = logfs_write_je(sb, logfs_write_area);
		if (err)
			goto again;
	}
	err = logfs_write_obj_aliases(sb);
	if (err)
		goto again;
	err = logfs_write_je(sb, logfs_write_erasecount);
	if (err)
		goto again;
	err = logfs_write_je(sb, __logfs_write_anchor);
	if (err)
		goto again;
	err = logfs_write_je(sb, logfs_write_dynsb);
	if (err)
		goto again;
	/*
	 * Order is imperative.  First we sync all writes, including the
	 * non-committed journal writes.  Then we write the final commit and
	 * sync the current journal segment.
	 * There is a theoretical bug here.  Syncing the journal segment will
	 * write a number of journal entries and the final commit.  All these
	 * are written in a single operation.  If the device layer writes the
	 * data back-to-front, the commit will precede the other journal
	 * entries, leaving a race window.
	 * Two fixes are possible.  Preferred is to fix the device layer to
	 * ensure writes happen front-to-back.  Alternatively we can insert
	 * another logfs_sync_area() super->s_devops->sync() combo before
	 * writing the commit.
	 */
	super->s_devops->sync(sb);
	err = logfs_write_je(sb, logfs_write_commit);
	if (err)
		goto again;
	log_journal("Write commit to %llx\n",
			be64_to_cpu(super->s_je_array[super->s_no_je - 1]));
	logfs_sync_area(area);
	BUG_ON(area->a_used_bytes != area->a_written_bytes);
	super->s_devops->sync(sb);

	mutex_unlock(&super->s_journal_mutex);
	return;
}