Example #1
0
static PyObject *
fs_read_cached_inode (Filesystem *self,
                      PyObject   *args,
                      PyObject   *kwargs)
{
  errcode_t           ret;
  unsigned long long  blkno;
  ocfs2_cached_inode *cinode;
  PyObject           *dinode;

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

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

  CHECK_ERROR (ocfs2_read_cached_inode (self->fs, blkno, &cinode));

  dinode = dinode_new (self, cinode->ci_inode);

  /* XXX: error check */
  ocfs2_free_cached_inode (self->fs, cinode);

  return dinode;
}
Example #2
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;
}
Example #3
0
static errcode_t check_backup_offsets(ocfs2_filesys *fs)
{

	errcode_t ret;
	int i, num, val, failed = 0;
	ocfs2_cached_inode *chain_alloc = NULL;
	uint64_t blocks[OCFS2_MAX_BACKUP_SUPERBLOCKS];

	num = ocfs2_get_backup_super_offsets(fs, blocks,
					     ARRAY_SIZE(blocks));
	if (!num) {
		ret = 1;
		errorf("Volume on device \"%s\" is too small to contain "
		       "backup superblocks\n",
		       fs->fs_devname);
		goto bail;
	}

	ret = load_global_bitmap(fs, &chain_alloc);
	if (ret) {
		tcom_err(ret, "while loading the global bitmap");
		goto bail;
	}

	for (i = 0; i < num; i++) {
		ret = ocfs2_bitmap_test(chain_alloc->ci_chains,
					ocfs2_blocks_to_clusters(fs, blocks[i]),
					&val);
		if (ret) {
			tcom_err(ret,
				 "looking up backup superblock locations "
				 "in the global bitmap");
			goto bail;
		}

		if (val) {
			verbosef(VL_APP,
				 "Backup superblock location %d at block "
				 "%"PRIu64" is in use\n", i, blocks[i]);
			/* in order to verify all the block in the 'blocks',
			 * we don't stop the loop here.
			 */
			failed = 1;
		}
	}

	if (failed) {
		ret = 1;
		errorf("One or more backup superblock locations are "
		       "already in use\n");
	} else
		ret = 0;

	if (chain_alloc)
		ocfs2_free_cached_inode(fs, chain_alloc);

bail:
	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;
}
Example #5
0
errcode_t ocfs2_extend_allocation(ocfs2_filesys *fs, uint64_t ino,
				  uint32_t new_clusters)
{
	errcode_t ret;
	ocfs2_cached_inode *ci = NULL;

	ret = ocfs2_read_cached_inode(fs, ino, &ci);
	if (ret)
		goto bail;

	ret = ocfs2_cached_inode_extend_allocation(ci, new_clusters);
	if (ret)
		goto bail;

	ret = ocfs2_write_cached_inode(fs, ci);
bail:
	if (ci)
		ocfs2_free_cached_inode(fs, ci);

	return ret;
}
Example #6
0
/*
 * Insert an extent into an inode btree.
 */
errcode_t ocfs2_inode_insert_extent(ocfs2_filesys *fs, uint64_t ino,
				    uint32_t cpos, uint64_t c_blkno,
				    uint32_t clusters, uint16_t flag)
{
	errcode_t ret;
	ocfs2_cached_inode *ci = NULL;

	ret = ocfs2_read_cached_inode(fs, ino, &ci);
	if (ret)
		goto bail;

	ret = ocfs2_cached_inode_insert_extent(ci, cpos, c_blkno,
					       clusters, flag);
	if (ret)
		goto bail;

	ret = ocfs2_write_cached_inode(fs, ci);

bail:
	if (ci)
		ocfs2_free_cached_inode(fs, ci);

	return ret;
}
Example #7
0
/* XXX care about zeroing new clusters and final partially truncated 
 * clusters */
errcode_t ocfs2_truncate_full(ocfs2_filesys *fs, uint64_t ino,
			      uint64_t new_i_size,
			      errcode_t (*free_clusters)(ocfs2_filesys *fs,
							 uint32_t len,
							 uint64_t start,
							 void *free_data),
			      void *free_data)
{
	errcode_t ret;
	uint32_t new_clusters;
	ocfs2_cached_inode *ci = NULL;

	ret = ocfs2_read_cached_inode(fs, ino, &ci);
	if (ret)
		goto out;

	/* in case of dio crashed, force do trucate since blocks may already
	 * be allocated
	 */
	if (ci->ci_inode->i_flags & cpu_to_le32(OCFS2_DIO_ORPHANED_FL)) {
		ci->ci_inode->i_flags &= ~cpu_to_le32(OCFS2_DIO_ORPHANED_FL);
		ci->ci_inode->i_dio_orphaned_slot = 0;
		new_i_size = ci->ci_inode->i_size;
		goto truncate;
	}

	if (ci->ci_inode->i_size == new_i_size)
		goto out;

	if (ci->ci_inode->i_size < new_i_size) {
		ret = ocfs2_extend_file(fs, ino, new_i_size);
		goto out;
	}

truncate:
	if ((S_ISLNK(ci->ci_inode->i_mode) && !ci->ci_inode->i_clusters) ||
	    (ci->ci_inode->i_dyn_features & OCFS2_INLINE_DATA_FL))
		ret = ocfs2_truncate_inline(fs, ino, new_i_size);
	else {
		ret = ocfs2_zero_tail_and_truncate_full(fs, ci, new_i_size,
							&new_clusters,
							free_clusters,
							free_data);
		if (ret)
			goto out;

		ci->ci_inode->i_clusters = new_clusters;

		/* now all the clusters and extent blocks are freed.
		 * only when the file's content is empty, should the tree depth
		 * change.
		 */
		if (new_clusters == 0)
			ci->ci_inode->id2.i_list.l_tree_depth = 0;

		ci->ci_inode->i_size = new_i_size;
		ret = ocfs2_write_cached_inode(fs, ci);
	}

	if (!ret && !new_i_size && ci->ci_inode->i_refcount_loc &&
		(ci->ci_inode->i_dyn_features & OCFS2_HAS_REFCOUNT_FL))
		ret = ocfs2_detach_refcount_tree(fs, ino, ci->ci_inode->i_refcount_loc);
out:
	if (ci)
		ocfs2_free_cached_inode(fs, ci);
	return ret;
}
Example #8
0
/* Try and replay the slots journals if they're dirty.  This only returns
 * a non-zero error if the caller should not continue. */
errcode_t o2fsck_replay_journals(ocfs2_filesys *fs, int *replayed)
{
	errcode_t err = 0, ret = 0;
	struct journal_info *jis = NULL, *ji;
	journal_superblock_t *jsb;
	char *buf = NULL;
	int journal_trouble = 0;
	uint16_t i, max_slots;
	ocfs2_bitmap *used_blocks = NULL;

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

	ret = ocfs2_block_bitmap_new(fs, "journal blocks",
				     &used_blocks);
	if (ret) {
		com_err(whoami, ret, "while allocating journal block bitmap"); 
		goto out;
	}

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

	ret = ocfs2_malloc0(sizeof(struct journal_info) * max_slots, &jis);
	if (ret) {
		com_err(whoami, ret, "while allocating an array of block "
			 "numbers for journal replay");
		goto out;
	}

	printf("Checking each slot's journal.\n");

	for (i = 0, ji = jis; i < max_slots; i++, ji++) {
		ji->ji_used_blocks = used_blocks;
		ji->ji_revoke = RB_ROOT;
		ji->ji_slot = i;

		/* sets ji->ji_replay */
		err = prep_journal_info(fs, i, ji);
		if (err) {
			printf("Slot %d seems to have a corrupt journal.\n",
			       i);
			journal_trouble = 1;
			continue;
		}

		if (!ji->ji_replay) {
			verbosef("slot %d is clean\n", i);
			continue;
		}

		err = walk_journal(fs, i, ji, buf, 0);
		if (err) {
			printf("Slot %d's journal can not be replayed.\n", i);
			journal_trouble = 1;
		}
	}

	for (i = 0, ji = jis; i < max_slots; i++, ji++) {
		if (!ji->ji_replay)
			continue;

		printf("Replaying slot %d's journal.\n", i);

		err = walk_journal(fs, i, ji, buf, 1);
		if (err) {
			journal_trouble = 1;
			continue;
		} 

		jsb = ji->ji_jsb;
		/* reset the journal */
		jsb->s_start = 0;

		if (ji->ji_set_final_seq)
			jsb->s_sequence = ji->ji_final_seq + 1;

		/* we don't write back a clean 'mounted' bit here.  That would
		 * have to also include having recovered the orphan dir.  we
		 * updated s_start, though, so we won't replay the journal
		 * again. */
		err = ocfs2_write_journal_superblock(fs,
						     ji->ji_jsb_block,
						     (char *)ji->ji_jsb);
		if (err) {
			com_err(whoami, err, "while writing slot %d's journal "
				"super block", i);
			journal_trouble = 1;
		} else {
			printf("Slot %d's journal replayed successfully.\n",
			       i);
			*replayed = 1;
		}
	}

	/* this is awkward, but we want fsck -n to tell us as much as it
	 * can so we don't want to ask to proceed here.  */
	if (journal_trouble)
		printf("*** There were problems replaying journals.  Be "
		       "careful in telling fsck to make repairs to this "
		       "filesystem.\n");

	ret = 0;

out:
	if (jis) {
		for (i = 0, ji = jis; i < max_slots; i++, ji++) {
			if (ji->ji_jsb)
				ocfs2_free(&ji->ji_jsb);
			if (ji->ji_cinode)
				ocfs2_free_cached_inode(fs, 
							ji->ji_cinode);
			revoke_free_all(&ji->ji_revoke);
		}
		ocfs2_free(&jis);
	}

	if (buf)
		ocfs2_free(&buf);
	if (used_blocks)
		ocfs2_bitmap_free(used_blocks);

	return ret;
}
Example #9
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;
	
}
Example #10
0
errcode_t read_journal(ocfs2_filesys *fs, uint64_t blkno, FILE *out)
{
	char *buf = NULL;
	char *jsb_buf = NULL;
	char *p;
	uint64_t blocknum;
	uint64_t len;
	uint64_t offset;
	uint32_t got;
	uint64_t last_unknown = 0;
	uint32_t buflen = 1024 * 1024;
	int buflenbits;
	ocfs2_cached_inode *ci = NULL;
	errcode_t ret;
	journal_superblock_t *jsb;

	ret = ocfs2_read_cached_inode(fs, blkno, &ci);
	if (ret) {
		com_err(gbls.cmd, ret, "while reading inode %"PRIu64, blkno);
		goto bail;
	}

	ret = ocfs2_malloc_block(fs->fs_io, &jsb_buf);
	if (ret) {
		com_err(gbls.cmd, ret,
			"while allocating journal superblock buffer");
		goto bail;
	}

	buflenbits = buflen >>
			OCFS2_RAW_SB(gbls.fs->fs_super)->s_blocksize_bits;
	ret = ocfs2_malloc_blocks(fs->fs_io, buflenbits, &buf);
	if (ret) {
		com_err(gbls.cmd, ret, "while allocating %u bytes", buflen);
		goto bail;
	}

	offset = 0;
	blocknum = 0;
	jsb = (journal_superblock_t *)jsb_buf;
	while (1) {
		ret = ocfs2_file_read(ci, buf, buflen, offset, &got);
		if (ret) {
			com_err(gbls.cmd, ret, "while reading journal");
			goto bail;
		};

		if (got == 0)
			break;

		p = buf;
		len = got;

		if (offset == 0) {
			memcpy(jsb_buf, buf, fs->fs_blocksize);
			dump_jbd_superblock(out, jsb);
			ocfs2_swap_journal_superblock(jsb);
			blocknum++;
			p += fs->fs_blocksize;
			len -= fs->fs_blocksize;
		}

		scan_journal(out, jsb, p, len, &blocknum, &last_unknown);

		if (got < buflen)
			break;
		offset += got;
	}

	if (last_unknown) {
		dump_jbd_unknown(out, last_unknown, blocknum);
		last_unknown = 0;
	}

bail:
	if (jsb_buf)
		ocfs2_free(&jsb_buf);
	if (buf)
		ocfs2_free(&buf);
	if (ci)
		ocfs2_free_cached_inode(fs, ci);

	return ret;
}
Example #11
0
static errcode_t ocfs2_file_block_write(ocfs2_cached_inode *ci,
					void *buf, uint32_t count,
					uint64_t offset, uint32_t *wrote)
{
	ocfs2_filesys	*fs = ci->ci_fs;
	errcode_t	ret = 0;
	char		*ptr = (char *) buf;
	uint32_t	wanted_blocks;
	uint64_t	contig_blocks;
	uint64_t	v_blkno;
	uint64_t	p_blkno, p_start, p_end;
	uint64_t	begin_blocks = 0, end_blocks = 0;
	uint32_t	tmp;
	uint64_t	num_blocks;
	int		bs_bits = OCFS2_RAW_SB(fs->fs_super)->s_blocksize_bits;
	uint64_t	ino = ci->ci_blkno;
	uint32_t	n_clusters, cluster_begin, cluster_end;
	uint64_t	bpc = fs->fs_clustersize/fs->fs_blocksize;
	int		insert = 0;
	uint16_t	extent_flags = 0;

	/* o_direct requires aligned io */
	tmp = fs->fs_blocksize - 1;
	if ((count & tmp) || (offset & (uint64_t)tmp) ||
	    ((unsigned long)ptr & tmp))
		return OCFS2_ET_INVALID_ARGUMENT;

	wanted_blocks = count >> bs_bits;
	v_blkno = offset >> bs_bits;
	*wrote = 0;

	num_blocks = (ci->ci_inode->i_size + fs->fs_blocksize - 1) >> bs_bits;

	if (v_blkno >= num_blocks)
		return 0;

	if (v_blkno + wanted_blocks > num_blocks)
		wanted_blocks = (uint32_t) (num_blocks - v_blkno);

	while(wanted_blocks) {
		ret = ocfs2_extent_map_get_blocks(ci, v_blkno, 1,
						  &p_blkno, &contig_blocks,
						  &extent_flags);
		if (ret)
			return ret;

		if (contig_blocks > wanted_blocks)
			contig_blocks = wanted_blocks;

		begin_blocks = 0;
		end_blocks = 0;
		p_end = 0;
	 	if (!p_blkno) {
			/*
			 * We meet with a hole here, so we allocate clusters
			 * and empty the both ends in case.
			 *
			 * We will postpone the extent insertion after we
			 * successfully write the extent block, so that and
			 * problems happens in block writing would not affect
			 * the file.
			 */
			cluster_begin = ocfs2_blocks_to_clusters(fs, v_blkno);
			cluster_end = ocfs2_blocks_to_clusters(fs,
						v_blkno + contig_blocks -1);
			n_clusters = cluster_end - cluster_begin + 1;
			ret = ocfs2_new_clusters(fs, 1, n_clusters, &p_start,
						 &n_clusters);
			if (ret || n_clusters == 0)
				return ret;

			begin_blocks = v_blkno & (bpc - 1);
			p_blkno = p_start + begin_blocks;
			contig_blocks = n_clusters * bpc - begin_blocks;
			if (contig_blocks > wanted_blocks) {
				end_blocks = contig_blocks - wanted_blocks;
				contig_blocks = wanted_blocks;
				p_end = p_blkno + wanted_blocks;
			}

			insert = 1;
		} else if (extent_flags & OCFS2_EXT_UNWRITTEN) {
			begin_blocks = v_blkno & (bpc - 1);
			p_start = p_blkno - begin_blocks;
			p_end = p_blkno + wanted_blocks;
			end_blocks = (p_end & (bpc - 1)) ?
						 bpc - (p_end & (bpc - 1 )) : 0;
		}

		if (begin_blocks) {
			/*
			 * The user don't write the first blocks,
			 * so we have to empty them.
			 */
			ret = empty_blocks(fs, p_start, begin_blocks);
			if (ret)
				return ret;
		}

		if (end_blocks) {
			/*
			 * we don't need to write that many blocks,
			 * so empty the blocks at the bottom.
			 */
			ret = empty_blocks(fs, p_end, end_blocks);
			if (ret)
				return ret;
		}

		ret = io_write_block(fs->fs_io, p_blkno, contig_blocks, ptr);
		if (ret)
			return ret;

		if (insert) {
			ret = ocfs2_cached_inode_insert_extent(ci,
					ocfs2_blocks_to_clusters(fs,v_blkno),
					p_start, n_clusters, 0);
			if (ret) {
				/*
				 * XXX: We don't wan't to overwrite the error
				 * from insert_extent().  But we probably need
				 * to BE LOUDLY UPSET.
				 */
				ocfs2_free_clusters(fs, n_clusters, p_start);
				return ret;
			}

			/* save up what we have done. */
			ret = ocfs2_write_cached_inode(fs, ci);
			if (ret)
				return ret;

			ret = ocfs2_extent_map_get_blocks(ci, v_blkno, 1,
						&p_blkno, NULL, NULL);
			/* now we shouldn't find a hole. */
			if (!p_blkno || p_blkno != p_start + begin_blocks)
				ret = OCFS2_ET_INTERNAL_FAILURE;
			if (ret)
				return ret;

			insert = 0;
		} else if (extent_flags & OCFS2_EXT_UNWRITTEN) {
			cluster_begin = ocfs2_blocks_to_clusters(fs, v_blkno);
			cluster_end = ocfs2_blocks_to_clusters(fs,
						v_blkno + contig_blocks -1);
			n_clusters = cluster_end - cluster_begin + 1;
			ret = ocfs2_mark_extent_written(fs, ci->ci_inode,
					cluster_begin, n_clusters,
					p_blkno & ~(bpc - 1));
			if (ret)
				return ret;
			ocfs2_free_cached_inode(fs, ci);
			ocfs2_read_cached_inode(fs,ino, &ci);
		}

		*wrote += (contig_blocks << bs_bits);
		wanted_blocks -= contig_blocks;

		if (wanted_blocks) {
			ptr += (contig_blocks << bs_bits);
			v_blkno += (uint64_t)contig_blocks;
		} else {
			if (*wrote + offset > ci->ci_inode->i_size)
				*wrote = (uint32_t) (ci->ci_inode->i_size - offset);
			/* break */
		}

	}

	return ret;
}
Example #12
0
int main(int argc, char *argv[])
{
	errcode_t ret;
	uint64_t blkno, contig, blkoff = 0;
	uint16_t ext_flags;
	int count = 0;
	int c, op = 0;
	char *filename;
	ocfs2_filesys *fs;
	ocfs2_cached_inode *cinode;

	blkno = OCFS2_SUPER_BLOCK_BLKNO;

	initialize_ocfs_error_table();

	while ((c = getopt(argc, argv, "i:b:")) != EOF) {
		switch (c) {
			case 'i':
				blkno = read_number(optarg);
				if (blkno <= OCFS2_SUPER_BLOCK_BLKNO) {
					fprintf(stderr,
						"Invalid inode block: %s\n",
						optarg);
					print_usage();
					return 1;
				}
				break;

			case 'b':
				if (op) {
					fprintf(stderr, "Cannot specify more than one operation\n");
					print_usage();
					return 1;
				}
				if (read_b_numbers(optarg,
						   &blkoff, &count)) {
					fprintf(stderr, "Invalid block range: %s\n", optarg);
					print_usage();
					return 1;
				}
				op = OP_LOOKUP_BLOCK;
				break;

			default:
				print_usage();
				return 1;
				break;
		}
	}

	if (!op) {
		fprintf(stderr, "Missing operation\n");
		print_usage();
		return 1;
	}

	if (optind >= argc) {
		fprintf(stderr, "Missing filename\n");
		print_usage();
		return 1;
	}
	filename = argv[optind];

	ret = ocfs2_open(filename, OCFS2_FLAG_RO, 0, 0, &fs);
	if (ret) {
		com_err(argv[0], ret,
			"while opening file \"%s\"", filename);
		goto out;
	}

	ret = ocfs2_read_cached_inode(fs, blkno, &cinode);
	if (ret) {
		com_err(argv[0], ret, "while reading inode %"PRIu64, blkno);
		goto out_close;
	}

	fprintf(stdout, "OCFS2 inode %"PRIu64" on \"%s\" has depth %"PRId16"\n",
		blkno, filename,
		cinode->ci_inode->id2.i_list.l_tree_depth);

	ret = ocfs2_extent_map_get_blocks(cinode,
					  blkoff,
					  count,
					  &blkno,
					  &contig,
					  &ext_flags);
	if (ret) {
		com_err(argv[0], ret,
			"looking up block range %"PRIu64":%d", blkoff, count);
		goto out_free;
	}
	fprintf(stdout, "Lookup of block range %"PRIu64":%d returned %"PRIu64":%"PRIu64"\n",
		blkoff, count, blkno, contig);

out_free:
	ocfs2_free_cached_inode(fs, cinode);

out_close:
	ret = ocfs2_close(fs);
	if (ret) {
		com_err(argv[0], ret,
			"while closing file \"%s\"", filename);
	}

out:
	return 0;
}
Example #13
0
errcode_t ocfs2_allocate_unwritten_extents(ocfs2_filesys *fs, uint64_t ino,
					   uint64_t offset, uint64_t len)
{
	errcode_t ret = 0;
	uint32_t n_clusters = 0, cpos;
	uint64_t p_blkno = 0, v_blkno, v_end, contig_blocks, wanted_blocks;
	ocfs2_cached_inode *ci = NULL;

	if (!(fs->fs_flags & OCFS2_FLAG_RW))
		return OCFS2_ET_RO_FILESYS;

	if (!ocfs2_writes_unwritten_extents(OCFS2_RAW_SB(fs->fs_super)))
		return OCFS2_ET_RO_UNSUPP_FEATURE;

	ret = ocfs2_read_cached_inode(fs, ino, &ci);
	if (ret)
		goto out;

	if (!(ci->ci_inode->i_flags & OCFS2_VALID_FL))
		return OCFS2_ET_INODE_NOT_VALID;

	if (ci->ci_inode->i_flags & OCFS2_SYSTEM_FL)
		return OCFS2_ET_INVALID_ARGUMENT;

	if (!S_ISREG(ci->ci_inode->i_mode))
		return OCFS2_ET_INVALID_ARGUMENT;

	v_blkno = offset / fs->fs_blocksize;
	v_end = (offset + len - 1) / fs->fs_blocksize;

	while (v_blkno <= v_end) {
		ret = ocfs2_extent_map_get_blocks(ci, v_blkno, 1,
						  &p_blkno, &contig_blocks,
						  NULL);
		if (ret)
			continue;

		if (p_blkno) {
			v_blkno += contig_blocks;
			continue;
		}

		/*
		 * There is a hole, so we have to allocate the space and
		 * insert the unwritten extents.
		 */
		wanted_blocks = ocfs2_min(contig_blocks, v_end - v_blkno + 1);
		n_clusters = ocfs2_clusters_in_blocks(fs, wanted_blocks);
		ret = ocfs2_new_clusters(fs, 1, n_clusters, &p_blkno,
					 &n_clusters);
		if (ret || n_clusters == 0)
			break;

		cpos = ocfs2_blocks_to_clusters(fs, v_blkno);
		ret = ocfs2_cached_inode_insert_extent(ci, cpos,
						       p_blkno, n_clusters,
						       OCFS2_EXT_UNWRITTEN);
		if (ret) {
			/*
			 * XXX: We don't wan't to overwrite the error
			 * from insert_extent().  But we probably need
			 * to BE LOUDLY UPSET.
			 */
			ocfs2_free_clusters(fs, n_clusters, p_blkno);
			goto out;
		}

		/* save up what we have done. */
		ret = ocfs2_write_cached_inode(fs, ci);
		if (ret)
			goto out;

		v_blkno = ocfs2_clusters_to_blocks(fs, cpos + n_clusters);
	}

	if (ci->ci_inode->i_size <= offset + len) {
		ci->ci_inode->i_size = offset + len;
		ret = ocfs2_write_cached_inode(fs, ci);
	}

out:
	if (ci)
		ocfs2_free_cached_inode(fs, ci);

	return ret;
}