[Ocfs2-tools-devel] [PATCH 2/4] defrag.ocfs2: Pass 1: Defrag individual files and directories
Joel Becker
Joel.Becker at oracle.com
Mon Jul 19 11:11:40 PDT 2010
On Tue, May 11, 2010 at 11:02:34PM -0500, Goldwyn Rodrigues wrote:
> Defragging file -
> Allocate the maximum possible extent and copy the file into the
> newly allocated extent. If the allocated extent is smaller than
> the extent read from the file, write the collected data, and
> re-use the file extent. At any point, if the number of extents
> in the new inode increases than in the existing inode, abort.
Finally, files.
> +static errcode_t calc_num_extents(ocfs2_filesys *fs,
> + struct ocfs2_extent_list *el,
> + uint32_t *ne)
> +{
> + struct ocfs2_extent_block *eb;
> + struct ocfs2_extent_rec *rec;
> + errcode_t ret = 0;
> + char *buf = NULL;
> + int i;
> + uint32_t clusters;
> + uint32_t extents = 0;
> +
> + *ne = 0;
> + for (i = 0; i < el->l_next_free_rec; ++i) {
> + rec = &(el->l_recs[i]);
> + clusters = ocfs2_rec_clusters(el->l_tree_depth, rec);
> +
> + /*
> + * In a unsuccessful insertion, we may shift a tree
> + * add a new branch for it and do no insertion. So we
> + * may meet a extent block which have
> + * clusters == 0, this should only be happen
> + * in the last extent rec. */
> + if (!clusters && i == el->l_next_free_rec - 1)
> + break;
> +
> + extents = 1;
> +
> + if (el->l_tree_depth) {
> + ret = ocfs2_malloc_block(fs->fs_io, &buf);
> + if (ret)
> + goto bail;
You've got a memory leak here. You allocate a buffer for every
i, but only free the last buf at function exit.
> +static errcode_t copy_clusters(ocfs2_filesys *fs,
> + uint64_t from, uint64_t to, int n)
> +{
> + char *buf = NULL;
> + int i, c = ocfs2_clusters_in_blocks(fs, 1);
> + errcode_t ret = ocfs2_malloc_blocks(fs->fs_io, c, &buf);
> + verbosef("Writing %d clusters to %"PRIu64" from %"PRIu64"\n", n,
> + to, from);
> + if (ret)
> + return ret;
> + for (i=0; i < n; i++) {
> + ret = ocfs2_read_blocks(fs, from + i*c, c, buf);
> + if (ret)
> + goto out;
> + ret = io_write_block(fs->fs_io, to + i*c, c, buf);
> + if (ret)
> + goto out;
> + }
> +out:
> + ocfs2_free(&buf);
> + return ret;
> +}
This will definitely be helped by running in BUFFERED mode ;-)
> + /* Handle holes */
> + if (c->expected_cpos < rec->e_cpos) {
> + verbosef("Hole detected expected/rec cpos %d/%d\n",
> + c->expected_cpos, rec->e_cpos);
> +
> + if (c->c_offset) {
> + verbosef("Adding collected extent rec p %d blk %"
> + PRIu64"l %d\n", c->cpos, c->blkno, c->c_offset);
> + ret = ocfs2_cached_inode_insert_extent(c->new_inode,
> + c->cpos, c->blkno, c->c_offset, 0);
> + if (ret) {
> + com_err(whoami, ret,
> + "while adding extent rec\n");
> + c->status = DEFRAG_ERROR;
> + return OCFS2_EXTENT_ABORT;
> + }
> + c->num_extents++;
> + c->c_offset = 0;
> + }
> + c->expected_cpos = rec->e_cpos;
> + c->clusters_left -= rec->e_cpos - c->expected_cpos;
> + if (!c->clusters_left)
> + return 0;
> + ret = free_clusters(c);
> + if (ret) {
> + com_err(whoami, ret, "while freeing clusters\n");
> + c->status = DEFRAG_ERROR;
> + return OCFS2_EXTENT_ABORT;
> + }
> + }
> +
> + c->expected_cpos += rec->e_leaf_clusters;
> +
> + if (!c->c_end) {
> + ret = alloc_clusters(c);
> + if (ret) {
> + com_err(whoami, ret, "while allocating clusters\n");
> + c->status = DEFRAG_ERROR;
> + return OCFS2_EXTENT_ABORT;
> + }
> +
> + }
> +
> + /* Reuse clusters if they are bigger than allocated cluster */
> + if (c->c_end <= rec->e_leaf_clusters) {
> + if (c->c_offset) {
> + verbosef("Adding collected extent rec p %d blk %"
> + PRIu64"l %d\n", c->cpos, c->blkno, c->c_offset);
> + ret = ocfs2_cached_inode_insert_extent(c->new_inode,
> + c->cpos, c->blkno, c->c_offset, 0);
> + if (ret) {
> + com_err(whoami, ret,
> + "while adding extent rec\n");
> + c->status = DEFRAG_ERROR;
> + return OCFS2_EXTENT_ABORT;
> + }
> + c->num_extents++;
> + }
> + verbosef("Adding old extent rec %d b %"PRIu64" l %d\n",
> + rec->e_cpos, (uint64_t)rec->e_blkno, rec->e_leaf_clusters);
> + ret = ocfs2_cached_inode_insert_extent(c->new_inode,
> + rec->e_cpos, rec->e_blkno, rec->e_leaf_clusters, 0);
> + if (ret) {
> + com_err(whoami, ret, "while adding extent\n");
> + c->status = DEFRAG_ERROR;
> + return OCFS2_EXTENT_ABORT;
> + }
> + c->num_extents++;
> + c->sc.rec[c->sc.num_recs].start = rec->e_blkno;
> + c->sc.rec[c->sc.num_recs++].len = rec->e_leaf_clusters;
> + if (c->sc.num_recs > MAX_RECS) {
> + verbosef("Exceeded MAX_RECS limit %d\n",
> + c->sc.num_recs);
> + c->status = DEFRAG_ERROR;
> + return OCFS2_EXTENT_ABORT;
> + }
> + c->cpos = rec->e_cpos + rec->e_leaf_clusters;
> + c->clusters_left -= rec->e_leaf_clusters;
> + ret = free_clusters(c);
> + if (ret) {
> + com_err(whoami, ret, "while freeing clusters\n");
> + c->status = DEFRAG_ERROR;
> + return OCFS2_EXTENT_ABORT;
> + }
> + return 0;
> + }
> +
> + /* Remaining clusters short. Fill allocated clusters and write */
> + nc = 0;
> + left = rec->e_leaf_clusters;
> + while (c->c_end < c->c_offset + left) {
> + /* Copy enough to fill the rest of the block */
> + nc = c->c_end - c->c_offset;
> + if (nc) {
> + ret = copy_clusters(c->dst->dst_fs, rec->e_blkno,
> + c->blkno + b*c->c_offset, nc);
Can we get better names than 'b'? Also, please use parenthesis
in expressions like "while (c->c_end < (c->c_offset + left))" and such.
It makes it easier to read.
Joel
--
Life's Little Instruction Book #347
"Never waste the oppourtunity to tell someone you love them."
Joel Becker
Consulting Software Developer
Oracle
E-mail: joel.becker at oracle.com
Phone: (650) 506-8127
More information about the Ocfs2-tools-devel
mailing list