示例#1
0
static errcode_t create_orphan_file(ocfs2_filesys *fs, uint16_t slot)
{
	errcode_t ret;
	uint64_t dir, tmp_blkno;
	char name[OCFS2_MAX_FILENAME_LEN];
	int namelen;

	ret = ocfs2_lookup_system_inode(fs, ORPHAN_DIR_SYSTEM_INODE,
					slot, &dir);
	if (ret)
		return ret;

	namelen = sprintf(name, "test%ld", random());

	ret = ocfs2_lookup(fs, dir, name, namelen, NULL, &tmp_blkno);
	if (!ret)
		return 0;
	else if (ret != OCFS2_ET_FILE_NOT_FOUND)
		return ret;

	ret = ocfs2_new_inode(fs, &tmp_blkno, S_IFREG | 0755);
	if (ret)
		return ret;

	ret = ocfs2_link(fs, dir, name,
			 tmp_blkno, OCFS2_FT_REG_FILE);
	if (ret)
		return ret;

	return 0;
}
static errcode_t orphan_dir_check(ocfs2_filesys *fs,
				  uint16_t new_slots)
{
	errcode_t ret = 0;
	uint64_t blkno;
	int i, has_orphan = 0;
	uint16_t max_slots = OCFS2_RAW_SB(fs->fs_super)->s_max_slots;

	for (i = new_slots ; i < max_slots; ++i) {
		ret = ocfs2_lookup_system_inode(fs, ORPHAN_DIR_SYSTEM_INODE,
						i, &blkno);
		if (ret) {
			verbosef(VL_APP,
				 "%s while looking up orphan dir for "
				 "slot %u during orphan dir check\n",
				 error_message(ret), i);
			break;
		}

		ret = ocfs2_dir_iterate(fs, blkno,
					OCFS2_DIRENT_FLAG_EXCLUDE_DOTS, NULL,
					orphan_iterate, &has_orphan);

		if (has_orphan) {
			ret = TUNEFS_ET_ORPHAN_DIR_NOT_EMPTY;
			verbosef(VL_APP,
				 "Entries found in orphan dir for slot %u\n",
				 i);
			break;
		}
	}

	return ret;
}
示例#3
0
static errcode_t check_journal_walk(o2fsck_state *ost,
				    errcode_t (*func)(o2fsck_state *ost,
						      ocfs2_cached_inode *ci,
						      struct journal_check_context *jc),
				    struct journal_check_context *jc)
{
	errcode_t ret = 0;
	uint64_t blkno;
	ocfs2_filesys *fs = ost->ost_fs;
	uint16_t i, max_slots = OCFS2_RAW_SB(fs->fs_super)->s_max_slots;
	ocfs2_cached_inode *ci = NULL;

	for (i = 0; i < max_slots; i++) {
		ret = ocfs2_lookup_system_inode(fs, JOURNAL_SYSTEM_INODE, i,
						&blkno);
		if (ret)
			break;

		ret = ocfs2_read_cached_inode(fs, blkno, &ci);
		if (ret)
			break;

		jc->jc_this_slot = i;
		ret = func(ost, ci, jc);
		if (ret)
			break;
	}

	if (ci)
		ocfs2_free_cached_inode(fs, ci);

	return ret;
}
static errcode_t truncate_orphan_dir(ocfs2_filesys *fs,
				     uint16_t removed_slot)
{
	errcode_t ret;
	uint64_t blkno;
	char fname[OCFS2_MAX_FILENAME_LEN];

	ocfs2_sprintf_system_inode_name(fname, OCFS2_MAX_FILENAME_LEN,
					ORPHAN_DIR_SYSTEM_INODE,
					removed_slot);
	verbosef(VL_APP, "Truncating orphan dir \"%s\"\n", fname);

	ret = ocfs2_lookup_system_inode(fs, ORPHAN_DIR_SYSTEM_INODE,
					removed_slot, &blkno);
	if (!ret) {
		ret = ocfs2_truncate(fs, blkno, 0);
		if (!ret)
			verbosef(VL_APP, "Orphan dir \"%s\" truncated\n",
				 fname);
		else
			verbosef(VL_APP,
				 "%s while truncating orphan dir \"%s\"\n",
				 error_message(ret), fname);
	} else
		verbosef(VL_APP,
			 "%s while looking up orphan dir \"%s\"\n",
			 error_message(ret), fname);

	return ret;
}
示例#5
0
static errcode_t create_local_alloc(ocfs2_filesys *fs, uint16_t slot)
{
	errcode_t ret;
	char *buf = NULL;
	struct ocfs2_dinode *di;
	struct ocfs2_local_alloc *la;
	uint32_t la_size, found;
	uint64_t la_off, blkno;

	ret = ocfs2_lookup_system_inode(fs, LOCAL_ALLOC_SYSTEM_INODE,
					slot, &blkno);
	if (ret)
		goto bail;

	ret = ocfs2_malloc_block(fs->fs_io, &buf);
	if (ret)
		goto bail;

	ret = ocfs2_read_inode(fs, blkno, buf);
	if (ret)
		goto bail;

	di = (struct ocfs2_dinode *)buf;

	if (!(di->i_flags & OCFS2_VALID_FL))
		goto bail;

	if (!(di->i_flags & OCFS2_LOCAL_ALLOC_FL))
		goto bail;

	if (di->id1.bitmap1.i_total > 0) {
		fprintf(stderr, "local alloc#%"PRIu64" file not empty."
			"Can't create a new one.\n", blkno);
		goto bail;
	}

	la_size = get_local_alloc_window_bits();

	ret = ocfs2_new_clusters(fs, 1, la_size, &la_off, &found);
	if (ret)
		goto bail;

	if(la_size != found)
		goto bail;

	la = &(di->id2.i_lab);

	la->la_bm_off = ocfs2_blocks_to_clusters(fs, la_off);
	di->id1.bitmap1.i_total = la_size;
	di->id1.bitmap1.i_used = 0;
	memset(la->la_bitmap, 0, la->la_size);
	
	ret = ocfs2_write_inode(fs, blkno, buf);

bail:
	if(buf)
		ocfs2_free(&buf);
	return ret;
}
static errcode_t truncate_log_check(ocfs2_filesys *fs,
				    uint16_t new_slots)
{
	errcode_t ret = 0;
	uint16_t i;
	uint64_t blkno;
	char *buf = NULL;
	struct ocfs2_dinode *di = NULL;

	uint16_t max_slots = OCFS2_RAW_SB(fs->fs_super)->s_max_slots;

	ret = ocfs2_malloc_block(fs->fs_io, &buf);
	if (ret) {
		verbosef(VL_APP,
			 "%s while allocating inode buffer for "
			 "truncate log check\n",
			 error_message(ret));
		goto bail;
	}

	for (i = new_slots; i < max_slots; ++i) {
		ret = ocfs2_lookup_system_inode(fs, TRUNCATE_LOG_SYSTEM_INODE,
						i, &blkno);
		if (ret) {
			verbosef(VL_APP,
				 "%s while looking up truncate log for "
				 "slot %u during truncate log check\n",
				 error_message(ret), i);
			goto bail;
		}

		ret = ocfs2_read_inode(fs, blkno, buf);
		if (ret) {
			verbosef(VL_APP,
				 "%s while reading inode %"PRIu64" "
				 "during truncate log check\n",
				 error_message(ret), blkno);
			goto bail;
		}

		di = (struct ocfs2_dinode *)buf;

		if (di->id2.i_dealloc.tl_used > 0) {
			ret = TUNEFS_ET_TRUNCATE_LOG_NOT_EMPTY;
			verbosef(VL_APP,
				 "Truncate log for slot %u is not empty\n",
				 i);
			goto bail;
		}
	}

bail:
	if (buf)
		ocfs2_free(&buf);
	return ret;
}
static errcode_t local_alloc_check(ocfs2_filesys *fs,
				   uint16_t new_slots)
{
	errcode_t ret = 0;
	uint16_t i;
	uint64_t blkno;
	char *buf = NULL;
	struct ocfs2_dinode *di = NULL;

	uint16_t max_slots = OCFS2_RAW_SB(fs->fs_super)->s_max_slots;

	ret = ocfs2_malloc_block(fs->fs_io, &buf);
	if (ret) {
		verbosef(VL_APP,
			 "%s while allocating inode buffer for local "
			 "alloc check\n",
			 error_message(ret));
		goto bail;
	}

	for (i = new_slots ; i < max_slots; ++i) {
		ret = ocfs2_lookup_system_inode(fs, LOCAL_ALLOC_SYSTEM_INODE,
						i, &blkno);
		if (ret) {
			verbosef(VL_APP,
				 "%s while looking up local alloc for "
				 "slot %u during local alloc check\n",
				 error_message(ret), i);
			break;
		}

		ret = ocfs2_read_inode(fs, blkno, buf);
		if (ret) {
			verbosef(VL_APP,
				 "%s while reading inode %"PRIu64" "
				 "during local alloc check\n",
				 error_message(ret), blkno);
			break;
		}

		di = (struct ocfs2_dinode *)buf;
		if (di->id1.bitmap1.i_total > 0) {
			ret = TUNEFS_ET_LOCAL_ALLOC_NOT_EMPTY;
			verbosef(VL_APP,
				 "Local alloc for slot %u is not empty\n",
				 i);
			break;
		}
	}

bail:
	if (buf)
		ocfs2_free(&buf);
	return ret;
}
static errcode_t empty_and_truncate_journal(ocfs2_filesys *fs,
					    uint16_t removed_slot)
{
	errcode_t ret;
	uint64_t blkno;
	ocfs2_cached_inode *ci = NULL;
	char fname[OCFS2_MAX_FILENAME_LEN];

	ocfs2_sprintf_system_inode_name(fname, OCFS2_MAX_FILENAME_LEN,
					JOURNAL_SYSTEM_INODE,
					removed_slot);
	verbosef(VL_APP, "Truncating journal \"%s\"\n", fname);

	ret = ocfs2_lookup_system_inode(fs, JOURNAL_SYSTEM_INODE,
					removed_slot, &blkno);
	if (ret) {
		verbosef(VL_APP, "%s while looking up journal \"%s\"\n",
			 error_message(ret), fname);
		goto bail;
	}

	ret = ocfs2_read_cached_inode(fs, blkno, &ci);
	if (ret) {
		verbosef(VL_APP,
			 "%s while reading journal inode %"PRIu64"\n",
			 error_message(ret), blkno);
		goto bail;
	}

	/* we have to empty the journal since it may contains some
	 * inode blocks which look like valid(except the i_blkno).
	 * So if this block range is used for future inode alloc
	 * files, fsck.ocfs2 may raise some error.
	 */
	ret = empty_journal(fs, ci);
	if (ret) {
		verbosef(VL_APP, "%s while emptying journal \"%s\"\n",
			 error_message(ret), fname);
		goto bail;
	}

	ret = ocfs2_truncate(fs, blkno, 0);
	if (ret) {
		verbosef(VL_APP, "%s while truncating journal \"%s\"\n",
			 error_message(ret), fname);
		goto bail;
	}

	verbosef(VL_APP, "Journal \"%s\" truncated\n", fname);

bail:
	if (ci)
		ocfs2_free_cached_inode(fs, ci);
	return ret;
}
示例#9
0
static errcode_t prep_journal_info(ocfs2_filesys *fs, int slot,
			           struct journal_info *ji)
{
	errcode_t err;


	err = ocfs2_malloc_blocks(fs->fs_io, 1, &ji->ji_jsb);
	if (err)
		com_err(whoami, err, "while allocating space for slot %d's "
			    "journal superblock", slot);

	err = ocfs2_lookup_system_inode(fs, JOURNAL_SYSTEM_INODE,
					slot, &ji->ji_ino);
	if (err) {
		com_err(whoami, err, "while looking up the journal inode for "
			"slot %d", slot);
		goto out;
	}

	err = ocfs2_read_cached_inode(fs, ji->ji_ino, &ji->ji_cinode);
	if (err) {
		com_err(whoami, err, "while reading cached inode %"PRIu64" "
			"for slot %d's journal", ji->ji_ino, slot);
		goto out;
	}

	if (!(ji->ji_cinode->ci_inode->id1.journal1.ij_flags &
	      OCFS2_JOURNAL_DIRTY_FL))
		goto out;

	err = lookup_journal_block(fs, ji, 0, &ji->ji_jsb_block, 1);
	if (err)
		goto out;

	/* XXX be smarter about reading in the whole super block if it
	 * spans multiple blocks */
	err = ocfs2_read_journal_superblock(fs, ji->ji_jsb_block, 
					    (char *)ji->ji_jsb);
	if (err) {
		com_err(whoami, err, "while reading block %"PRIu64" as slot "
			"%d's journal super block", ji->ji_jsb_block,
			ji->ji_slot);
		goto out;
	}

	ji->ji_replay = 1;

	verbosef("slot: %d jsb start %u maxlen %u\n", slot,
		 ji->ji_jsb->s_start, ji->ji_jsb->s_maxlen);
out:
	return err;
}
示例#10
0
errcode_t handle_slots_system_file(ocfs2_filesys *fs,
                                   int type,
                                   errcode_t (*func)(ocfs2_filesys *fs,
                                           struct ocfs2_dinode *di,
                                           int slot))
{
    errcode_t ret;
    uint64_t blkno;
    int slot, max_slots;
    char *buf = NULL;
    struct ocfs2_dinode *di;

    ret = ocfs2_malloc_block(fs->fs_io, &buf);
    if (ret)
        goto bail;

    di = (struct ocfs2_dinode *)buf;

    max_slots = OCFS2_RAW_SB(fs->fs_super)->s_max_slots;

    for (slot = 0; slot < max_slots; slot++) {
        ret = ocfs2_lookup_system_inode(fs,
                                        type,
                                        slot, &blkno);
        if (ret)
            goto bail;

        ret = ocfs2_read_inode(fs, blkno, buf);
        if (ret)
            goto bail;

        if (func) {
            ret = func(fs, di, slot);
            if (ret)
                goto bail;
        }
    }

bail:

    if (buf)
        ocfs2_free(&buf);
    return ret;
}
示例#11
0
static errcode_t load_global_bitmap(ocfs2_filesys *fs,
				    ocfs2_cached_inode** inode)
{
	errcode_t ret;
	uint64_t blkno;

	ret = ocfs2_lookup_system_inode(fs, GLOBAL_BITMAP_SYSTEM_INODE,
					0, &blkno);
	if (ret)
		goto bail;

	ret = ocfs2_read_cached_inode(fs, blkno, inode);
	if (ret)
		goto bail;

	ret = ocfs2_load_chain_allocator(fs, *inode);

bail:
	return ret;
}
示例#12
0
static PyObject *
fs_lookup_system_inode (Filesystem *self,
                        PyObject   *args,
                        PyObject   *kwargs)
{
  errcode_t ret;
  int       type, slot_num = OCFS2_INVALID_SLOT;
  uint64_t  blkno;

  static char *kwlist[] = { "type", "slot_num", NULL };

  if (!PyArg_ParseTupleAndKeywords (args, kwargs,
				    "i|i:lookup_system_inode", kwlist,
				    &type, &slot_num))
    return NULL;

  CHECK_ERROR (ocfs2_lookup_system_inode(self->fs, type, slot_num, &blkno));

  return PyLong_FromUnsignedLongLong (blkno);
}
示例#13
0
void mess_up_dup_clusters(ocfs2_filesys *fs, enum fsck_type type,
			  uint64_t blkno)
{
	errcode_t err;
	char *buf = NULL;
	uint64_t inode1_blkno, inode2_blkno;
	struct ocfs2_dinode *di1, *di2;
	struct ocfs2_extent_list *el1, *el2;

	err = ocfs2_malloc_blocks(fs->fs_io, 2, &buf);
	if (err)
		FSWRK_COM_FATAL(progname, err);

	create_file(fs, blkno, &inode1_blkno);

	di1 = (struct ocfs2_dinode *)buf;
	err = ocfs2_read_inode(fs, inode1_blkno, (char *)di1);
	if (err)
		FSWRK_COM_FATAL(progname, err);

	if (ocfs2_support_inline_data(OCFS2_RAW_SB(fs->fs_super))) {
		if (di1->i_dyn_features & OCFS2_INLINE_DATA_FL) {
			di1->i_dyn_features &= ~OCFS2_INLINE_DATA_FL;
			err = ocfs2_write_inode(fs, inode1_blkno, (char *)di1);
			if (err)
				FSWRK_COM_FATAL(progname, err);
		}
	}

	if (type != DUP_CLUSTERS_SYSFILE_CLONE) {

		create_file(fs, blkno, &inode2_blkno);
		di2 = (struct ocfs2_dinode *)(buf + fs->fs_blocksize);
		err = ocfs2_read_inode(fs, inode2_blkno, (char *)di2);
		if (err)
			FSWRK_COM_FATAL(progname, err);

		if (ocfs2_support_inline_data(OCFS2_RAW_SB(fs->fs_super))) {
			if (di2->i_dyn_features & OCFS2_INLINE_DATA_FL) {
				di2->i_dyn_features &= ~OCFS2_INLINE_DATA_FL;
				err = ocfs2_write_inode(fs, inode2_blkno,
							(char *)di2);
				if (err)
					FSWRK_COM_FATAL(progname, err);
			}
		}

		err = ocfs2_extend_allocation(fs, inode2_blkno, 1);
		if (err)
			FSWRK_COM_FATAL(progname, err);

		/* Re-read the inode with the allocation */
		err = ocfs2_read_inode(fs, inode2_blkno, (char *)di2);
		if (err)
			FSWRK_COM_FATAL(progname, err);

		/* Set i_size to non-zero so that the allocation is valid */
		di2->i_size = fs->fs_clustersize;
		err = ocfs2_write_inode(fs, inode2_blkno, (char *)di2);
		if (err)
			FSWRK_COM_FATAL(progname, err);

		if (type == DUP_CLUSTERS_CLONE)
			fprintf(stdout, "DUP_CLUSTERS_CLONE: "
				"Create two inodes #%"PRIu64" and #%"PRIu64
				" by allocating same cluster to them.\n",
				inode1_blkno, inode2_blkno);
		else
			fprintf(stdout, "DUP_CLUSTERS_DELETE: "
				"Create two inodes #%"PRIu64" and #%"PRIu64
				" by allocating same cluster to them.\n",
				inode1_blkno, inode2_blkno);
	} else {
		/* Here use journal file*/
		err = ocfs2_lookup_system_inode(fs, JOURNAL_SYSTEM_INODE, 0,
						&inode2_blkno);
		if (err)
			FSWRK_COM_FATAL(progname, err);

		di2 = (struct ocfs2_dinode *)(buf + fs->fs_blocksize);
		err = ocfs2_read_inode(fs, inode2_blkno, (char *)di2);
		if (err)
			FSWRK_COM_FATAL(progname, err);

		if (di2->id2.i_list.l_tree_depth)
			FSWRK_FATAL("Journal inode has non-zero tree "
				    "depth.  fswreck can't use it for "
				    "DUP_CLUSTERS_SYSFILE_CLONE\n");

		fprintf(stdout, "DUP_CLUSTERS_SYSFILE_CLONE: "
			"Allocate same cluster to journal file "
			"#%"PRIu64" and regular file #%"PRIu64".\n",
			inode1_blkno, inode2_blkno);
	}

	el1 = &(di1->id2.i_list);
	el2 = &(di2->id2.i_list);


	el1->l_next_free_rec = 1;
	el1->l_recs[0] = el2->l_recs[0];

	di1->i_size =
		ocfs2_clusters_to_bytes(fs, el1->l_recs[0].e_leaf_clusters);
	di1->i_clusters = di2->i_clusters;

	err = ocfs2_write_inode(fs, inode1_blkno, (char *)di1);
	if (err)
		FSWRK_COM_FATAL(progname, err);

	ocfs2_free(&buf);
}
示例#14
0
static errcode_t create_truncate_log(ocfs2_filesys *fs, uint16_t slot)
{
	errcode_t ret;
	char *buf = NULL;
	struct ocfs2_dinode *di;
	struct ocfs2_truncate_log *tl;
	uint16_t i, used = 10;
	uint32_t found, clusters = 10;
	uint64_t begin, blkno;

	ret = ocfs2_lookup_system_inode(fs, TRUNCATE_LOG_SYSTEM_INODE,
					slot, &blkno);
	if (ret)
		goto bail;
	
	ret = ocfs2_malloc_block(fs->fs_io, &buf);
	if (ret)
		goto bail;

	ret = ocfs2_read_inode(fs, blkno, buf);
	if (ret)
		goto bail;

	di = (struct ocfs2_dinode *)buf;

	if (!(di->i_flags & OCFS2_VALID_FL)) {
		fprintf(stderr,"not a valid file\n");
		goto bail;
	}

	if (!(di->i_flags & OCFS2_DEALLOC_FL)) {
		fprintf(stderr,"not a valid truncate log\n");
		goto bail;
	}
	
	tl = &di->id2.i_dealloc;

	if (le16_to_cpu(tl->tl_used) > 0) {
		fprintf(stderr,"truncate log#%"PRIu64" file not empty."
			"Can't create a new one.\n", blkno);
		goto bail;
	}

	tl->tl_used = used;

	for (i = 0; i < tl->tl_used; i++) {
		ret = ocfs2_new_clusters(fs, 1, clusters, &begin, &found);
		if (ret)
			goto bail;
		
		tl->tl_recs[i].t_start = 
			ocfs2_blocks_to_clusters(fs, begin);
		tl->tl_recs[i].t_clusters = found;
	}

	ret = ocfs2_write_inode(fs, blkno, buf);

bail:
	if(buf)
		ocfs2_free(&buf);
	return ret;
}
示例#15
0
/*
 * We only need to replay the journals if the inode's flag is set and s_start
 * indicates that there is actually pending data in the journals.
 *
 * In the simple case of an unclean shutdown we don't want to have to build up
 * enough state to be able to truncate the inodes waiting in the orphan dir.
 * ocfs2 in the kernel only fixes up the orphan dirs if the journal dirty flag
 * is set.  So after replaying the journals we clear s_startin the journals to
 * stop a second journal replay but leave the dirty bit set so that the kernel
 * will truncate the orphaned inodes. 
 */
errcode_t o2fsck_should_replay_journals(ocfs2_filesys *fs, int *should,
					int *has_dirty)
{
	uint16_t i, max_slots;
	char *buf = NULL;
	uint64_t blkno;
	errcode_t ret;
	ocfs2_cached_inode *cinode = NULL;
	int is_dirty;
	uint64_t contig;
	journal_superblock_t *jsb;

	*should = 0;
	max_slots = OCFS2_RAW_SB(fs->fs_super)->s_max_slots;

	ret = ocfs2_malloc_block(fs->fs_io, &buf);
	if (ret) {
		com_err(whoami, ret, "while allocating room to read journal "
			    "blocks");
		goto out;
	}

	jsb = (journal_superblock_t *)buf;

	for (i = 0; i < max_slots; i++) {
		ret = ocfs2_lookup_system_inode(fs, JOURNAL_SYSTEM_INODE, i,
						&blkno);
		if (ret) {
			com_err(whoami, ret, "while looking up the journal "
				"inode for slot %d", i);
			goto out;
		}

		if (cinode) {
			ocfs2_free_cached_inode(fs, cinode);
			cinode = NULL;
		}
		ret = ocfs2_read_cached_inode(fs, blkno, &cinode);
		if (ret) {
			com_err(whoami, ret, "while reading cached inode "
				"%"PRIu64" for slot %d's journal", blkno, i);
			goto out;
		}

		is_dirty = cinode->ci_inode->id1.journal1.ij_flags &
			   OCFS2_JOURNAL_DIRTY_FL;
		verbosef("slot %d JOURNAL_DIRTY_FL: %d\n", i, is_dirty);
		if (!is_dirty)
			continue;
		else
			*has_dirty = 1;

		ret = ocfs2_extent_map_get_blocks(cinode, 0, 1, &blkno,
						  &contig, NULL);
		if (ret) {
			com_err(whoami, ret, "while looking up the journal "
				"super block in slot %d's journal", i);
			goto out;
		}

		/* XXX be smarter about reading in the whole super block if it
		 * spans multiple blocks */
		ret = ocfs2_read_journal_superblock(fs, blkno, buf);
		if (ret) {
			com_err(whoami, ret, "while reading the journal "
				"super block in slot %d's journal", i);
			goto out;
		}

		if (jsb->s_start)
			*should = 1;
	}

out:
	if (buf)
		ocfs2_free(&buf);
	if (cinode)
		ocfs2_free_cached_inode(fs, cinode);
	return ret;
	
}
示例#16
0
static errcode_t relink_system_alloc(ocfs2_filesys *fs,
				     uint16_t removed_slot,
				     uint16_t new_slots,
				     int inode_type)
{
	errcode_t ret;
	int16_t i;
	uint64_t blkno;
	struct ocfs2_dinode *di = NULL;
	struct ocfs2_chain_list *cl = NULL;
	struct relink_ctxt ctxt;
	char fname[OCFS2_MAX_FILENAME_LEN];

	memset(&ctxt, 0, sizeof(ctxt));

	ocfs2_sprintf_system_inode_name(fname, OCFS2_MAX_FILENAME_LEN,
					inode_type, removed_slot);
	verbosef(VL_APP, "Relinking system allocator \"%s\"\n", fname);

	ret = ocfs2_lookup_system_inode(fs, inode_type,
					removed_slot, &blkno);
	if (ret) {
		verbosef(VL_APP, "%s while looking up the allocator\n",
			 error_message(ret));
		goto bail;
	}

	ret = ocfs2_malloc_block(fs->fs_io, &ctxt.src_inode);
	if (ret) {
		verbosef(VL_APP,
			 "%s while allocating the inode buffer\n",
			 error_message(ret));
		goto bail;
	}

	ret = ocfs2_read_inode(fs, blkno, ctxt.src_inode);
	if (ret) {
		verbosef(VL_APP,
			 "%s while reading allocator inode %"PRIu64"\n",
			 error_message(ret), blkno);
		goto bail;
	}

	di = (struct ocfs2_dinode *)ctxt.src_inode;

	if (!(di->i_flags & OCFS2_VALID_FL) ||
	    !(di->i_flags & OCFS2_BITMAP_FL) ||
	    !(di->i_flags & OCFS2_CHAIN_FL)) {
		verbosef(VL_APP, "Allocator inode %"PRIu64" is corrupt.\n",
			 blkno);
		goto bail;
	}

	if (di->id1.bitmap1.i_total == 0)
		goto bail;

	/* Iterate all the groups and modify the group descriptors accordingly. */
	ret = ocfs2_malloc_block(fs->fs_io, &ctxt.ex_buf);
	if (ret) {
		verbosef(VL_APP,
			 "%s while allocating an extent block buffer\n",
			 error_message(ret));
		goto bail;
	}

	ret = ocfs2_malloc_block(fs->fs_io, &ctxt.dst_inode);
	if (ret) {
		verbosef(VL_APP,
			 "%s while allocating the destination inode buffer\n",
			 error_message(ret));
		goto bail;
	}

	cl = &di->id2.i_chain;
	ctxt.inode_type = inode_type;

	/*iterate all the chain record and move them to the new slots. */
	for (i = cl->cl_next_free_rec - 1; i >= 0; i--) {
		ctxt.new_slot = i % new_slots;
		ret = ocfs2_lookup_system_inode(fs, inode_type,
						ctxt.new_slot,
						&ctxt.dst_blkno);
		if (ret) {
			verbosef(VL_APP,
				 "%s while finding the target allocator "
				 "for slot %d\n",
				 error_message(ret), ctxt.new_slot);
			goto bail;
		}

		ret = ocfs2_read_inode(fs, ctxt.dst_blkno, ctxt.dst_inode);
		if (ret) {
			verbosef(VL_APP,
				 "%s while reading target allocator inode "
				 "%"PRIu64"\n",
				 error_message(ret), ctxt.dst_blkno);
			goto bail;
		}

		ctxt.cr = &cl->cl_recs[i];

		ret = move_chain_rec(fs, &ctxt);
		if (ret) {
			verbosef(VL_APP,
				"%s while trying to move a chain record "
				"to the allocator in slot %d\n",
				error_message(ret), ctxt.new_slot);
			goto bail;
		}
	}


	/* emtpy the original alloc files. */
	di->id1.bitmap1.i_used = 0;
	di->id1.bitmap1.i_total = 0;
	di->i_clusters = 0;
	di->i_size = 0;

	cl = &di->id2.i_chain;
	cl->cl_next_free_rec = 0;
	memset(cl->cl_recs, 0, sizeof(struct ocfs2_chain_rec) * cl->cl_count);

	ret = ocfs2_write_inode(fs, blkno, ctxt.src_inode);
	if (ret)
		verbosef(VL_APP,
			 "%s while writing out the empty allocator inode\n",
			 error_message(ret));

bail:
	if (ctxt.ex_buf)
		ocfs2_free(&ctxt.ex_buf);
	if (ctxt.dst_inode)
		ocfs2_free(&ctxt.dst_inode);
	if (ctxt.src_inode)
		ocfs2_free(&ctxt.src_inode);

	if (!ret)
		verbosef(VL_APP, "Successfully relinked allocator \"%s\"\n",
			 fname);
	return ret;
}