Exemple #1
0
static void fix_dirent_inode(o2fsck_state *ost, o2fsck_dirblock_entry *dbe,
			     struct ocfs2_dir_entry *dirent, int offset,
			     unsigned int *flags)
{
	if (ocfs2_block_out_of_range(ost->ost_fs, dirent->inode) &&
	    prompt(ost, PY, PR_DIRENT_INODE_RANGE,
		   "Directory entry '%.*s' refers to inode "
		   "number %"PRIu64" which is out of range, clear the entry?",
		   dirent->name_len, dirent->name, (uint64_t)dirent->inode)) {

		dirent->inode = 0;
		*flags |= OCFS2_DIRENT_CHANGED;
		goto out;
	}

	if (!o2fsck_test_inode_allocated(ost, dirent->inode) &&
	    prompt(ost, PY, PR_DIRENT_INODE_FREE,
		   "Directory entry '%.*s' refers to inode number "
		   "%"PRIu64" which isn't allocated, clear the entry?", 
		   dirent->name_len, dirent->name, (uint64_t)dirent->inode)) {
		dirent->inode = 0;
		*flags |= OCFS2_DIRENT_CHANGED;
	}
out:
	return;
}
Exemple #2
0
static errcode_t count_tags(ocfs2_filesys *fs, journal_superblock_t *jsb,
			    char *buf, uint64_t *nr_ret)
{
	char *tagp, *last;
	journal_block_tag_t *tag;
	int tag_bytes = ocfs2_journal_tag_bytes(jsb);
	uint64_t nr = 0;

	if (jsb->s_blocksize < sizeof(journal_header_t) + tag_bytes)
		return OCFS2_ET_BAD_JOURNAL_TAG;

	tagp = &buf[sizeof(journal_header_t)];
	last = &buf[jsb->s_blocksize - tag_bytes];

	for(; tagp <= last; tagp += tag_bytes) {
		tag = (journal_block_tag_t *)tagp;
		nr++;
		if (ocfs2_block_out_of_range(fs, 
					     ocfs2_journal_tag_block(tag, tag_bytes)))
			return OCFS2_ET_BAD_JOURNAL_TAG;

		if (tag->t_flags & cpu_to_be32(JBD2_FLAG_LAST_TAG))
			break;
		if (!(tag->t_flags & cpu_to_be32(JBD2_FLAG_SAME_UUID)))
			tagp += 16;
	}

	*nr_ret = nr;
	return 0;
}
Exemple #3
0
static PyObject *
fs_block_out_of_range (Filesystem *self,
		       PyObject   *args,
		       PyObject   *kwargs)
{
  unsigned long long block;
  int                ret;

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

  if (!PyArg_ParseTupleAndKeywords (args, kwargs,
				    "K:block_out_of_range", kwlist,
				    &block))
    return NULL;

  ret = ocfs2_block_out_of_range(self->fs, block);

  return PyBool_FromLong (ret);
}
Exemple #4
0
errcode_t check_el(o2fsck_state *ost, struct extent_info *ei,
			  struct ocfs2_dinode *di,
			  struct ocfs2_extent_list *el,
			  uint16_t max_recs, int *changed)
{
	int trust_next_free = 1;
	struct ocfs2_extent_rec *er;
	uint64_t max_size;
	uint16_t i;
	uint32_t clusters;
	size_t cpy;

	verbosef("depth %u count %u next_free %u\n", el->l_tree_depth,
		 el->l_count, el->l_next_free_rec);

	if (ei->ei_expect_depth && 
	    el->l_tree_depth != ei->ei_expected_depth &&
	    prompt(ost, PY, PR_EXTENT_LIST_DEPTH,
		   "Extent list in inode %"PRIu64" is recorded as "
		   "being at depth %u but we expect it to be at depth %u. "
		   "update the list?", (uint64_t)di->i_blkno, el->l_tree_depth,
		   ei->ei_expected_depth)) {

		el->l_tree_depth = ei->ei_expected_depth;
		*changed = 1;
	}

	if (el->l_count > max_recs &&
	    prompt(ost, PY, PR_EXTENT_LIST_COUNT,
		   "Extent list in inode %"PRIu64" claims to have %u "
		   "records, but the maximum is %u. Fix the list's count?",
		   (uint64_t)di->i_blkno, el->l_count, max_recs)) {

		el->l_count = max_recs;
		*changed = 1;
	}

	if (max_recs > el->l_count)
		max_recs = el->l_count;

	if (el->l_next_free_rec > max_recs) {
		if (prompt(ost, PY, PR_EXTENT_LIST_FREE,
		  	   "Extent list in inode %"PRIu64" claims %u "
			   "as the next free chain record, but fsck believes "
			   "the largest valid value is %u.  Clamp the next "
			   "record value?", (uint64_t)di->i_blkno,
			   el->l_next_free_rec, max_recs)) {

			el->l_next_free_rec = el->l_count;
			*changed = 1;
		} else {
			trust_next_free = 0;
		}
	}

	if (trust_next_free)
		max_recs = el->l_next_free_rec;

	for (i = 0; i < max_recs; i++) {
		er = &el->l_recs[i];
		clusters = ocfs2_rec_clusters(el->l_tree_depth, er);

		/*
		 * For a sparse file, we may find an empty record
		 * in the left most record. Just skip it.
		 */
		if ((OCFS2_RAW_SB(ost->ost_fs->fs_super)->s_feature_incompat
		     & OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC) &&
		    el->l_tree_depth && !i && !clusters)
			continue;

		/* returns immediately if blkno is out of range.
		 * descends into eb.  checks that data er doesn't
		 * reference past the volume or anything crazy. */
		check_er(ost, ei, di, el, er, changed);

		/* offer to remove records that point to nowhere */
		if (ocfs2_block_out_of_range(ost->ost_fs, er->e_blkno) && 
		    prompt(ost, PY, PR_EXTENT_BLKNO_RANGE,
			   "Extent record %u in inode %"PRIu64" "
			   "refers to a block that is out of range.  Remove "
			   "this record from the extent list?", i,
			   (uint64_t)di->i_blkno)) {

			if (!trust_next_free) {
				printf("Can't remove the record becuase "
				       "next_free_rec hasn't been fixed\n");
				continue;
			}
			cpy = (max_recs - i - 1) * sizeof(*er);
			/* shift the remaining recs into this ones place */
			if (cpy != 0) {
				memcpy(er, er + 1, cpy);
				memset(&el->l_recs[max_recs - 1], 0, 
				       sizeof(*er));
				i--;
			}
			el->l_next_free_rec--;
			max_recs--;
			*changed = 1;
			continue;
		}


		/* we've already accounted for the extent block as part of
		 * the extent block chain groups */
		if (el->l_tree_depth)
			continue;

		/* mark the data clusters as used */
		o2fsck_mark_clusters_allocated(ost,
			ocfs2_blocks_to_clusters(ost->ost_fs, er->e_blkno),
			clusters);

		ei->ei_clusters += clusters;

		max_size = (er->e_cpos + clusters) <<
			   OCFS2_RAW_SB(ost->ost_fs->fs_super)->s_clustersize_bits;
		if (max_size > ei->ei_max_size)
			ei->ei_max_size = max_size;
	}

	return 0;
}
Exemple #5
0
/* the caller will check if er->e_blkno is out of range to determine if it
 * should try removing the record */
static errcode_t check_er(o2fsck_state *ost, struct extent_info *ei,
			  struct ocfs2_dinode *di,
			  struct ocfs2_extent_list *el,
			  struct ocfs2_extent_rec *er, int *changed)
{
	errcode_t ret = 0;
	uint64_t first_block;
	uint32_t last_cluster, clusters;

	clusters = ocfs2_rec_clusters(el->l_tree_depth, er);
	verbosef("cpos %u clusters %u blkno %"PRIu64"\n", er->e_cpos,
		 clusters, (uint64_t)er->e_blkno);

	if (ocfs2_block_out_of_range(ost->ost_fs, er->e_blkno))
		goto out;

	if (el->l_tree_depth) {
		int is_valid = 0;
		/* we only expect a given depth when we descend to extent blocks
		 * from a previous depth.  these start at 0 when the inode
		 * is checked */
		ei->ei_expect_depth = 1;
		ei->ei_expected_depth = el->l_tree_depth - 1;
		check_eb(ost, ei, di, er->e_blkno, &is_valid);
		if (!is_valid && 
		    prompt(ost, PY, PR_EXTENT_EB_INVALID,
			   "The extent record for cluster offset "
			   "%"PRIu32" in inode %"PRIu64" refers to an invalid "
			   "extent block at %"PRIu64".  Clear the reference "
			   "to this invalid block?", er->e_cpos,
			   (uint64_t)di->i_blkno, (uint64_t)er->e_blkno)) {

			er->e_blkno = 0;
			*changed = 1;
		}
		ret = 0;
		goto out;
	}

	if (!ocfs2_writes_unwritten_extents(OCFS2_RAW_SB(ost->ost_fs->fs_super)) &&
	    (er->e_flags & OCFS2_EXT_UNWRITTEN) &&
	    prompt(ost, PY, PR_EXTENT_MARKED_UNWRITTEN,
		   "The extent record for cluster offset %"PRIu32" "
		   "in inode %"PRIu64" has the UNWRITTEN flag set, but "
		   "this filesystem does not support unwritten extents.  "
		   "Clear the UNWRITTEN flag?", er->e_cpos,
		   (uint64_t)di->i_blkno)) {
		er->e_flags &= ~OCFS2_EXT_UNWRITTEN;
	}

	first_block = ocfs2_blocks_to_clusters(ost->ost_fs, er->e_blkno);
	first_block = ocfs2_clusters_to_blocks(ost->ost_fs, first_block);

	if (first_block != er->e_blkno &&
	    prompt(ost, PY, PR_EXTENT_BLKNO_UNALIGNED,
		   "The extent record for cluster offset %"PRIu32" "
		   "in inode %"PRIu64" refers to block %"PRIu64" which isn't "
		   "aligned with the start of a cluster.  Point the extent "
		   "record at block %"PRIu64" which starts this cluster?",
		   er->e_cpos, (uint64_t)di->i_blkno,
		   (uint64_t)er->e_blkno, first_block)) {

		er->e_blkno = first_block;
		*changed = 1;
	}

	/* imagine blkno 0, 1 er_clusters.  last_cluster is 1 and 
	 * fs_clusters is 1, which is ok.. */
	last_cluster = ocfs2_blocks_to_clusters(ost->ost_fs, er->e_blkno) +
		       clusters;

	if (last_cluster > ost->ost_fs->fs_clusters &&
	    prompt(ost, PY, PR_EXTENT_CLUSTERS_OVERRUN,
		   "The extent record for cluster offset %"PRIu32" "
		   "in inode %"PRIu64" refers to an extent that goes beyond "
		   "the end of the volume.  Truncate the extent by %"PRIu32" "
		   "clusters to fit it in the volume?", er->e_cpos,
		   (uint64_t)di->i_blkno,
		   last_cluster - ost->ost_fs->fs_clusters)) {

		clusters -= last_cluster - ost->ost_fs->fs_clusters;
		ocfs2_set_rec_clusters(el->l_tree_depth, er, clusters);
		*changed = 1;
	}
	
	/* XXX offer to remove leaf records with er_clusters set to 0? */

	/* XXX check that the blocks that are referenced aren't already 
	 * used */

out:
	return ret;
}