On Mar 26, 2008 10:42 -0500, Eric Sandeen wrote: > the ext4 fiemap call needs this helper function. > > I need to dig for the original author to see what signed-off-by > lines should be here. This was originally written by Alex and was in the extents patches but later removed. > Index: linux-2.6.25-rc1/fs/ext4/extents.c > =================================================================== > --- linux-2.6.25-rc1.orig/fs/ext4/extents.c > +++ linux-2.6.25-rc1/fs/ext4/extents.c > @@ -1588,6 +1588,112 @@ cleanup: > return err; > } > > +int ext4_ext_walk_space(struct inode *inode, ext4_lblk_t block, > + ext4_lblk_t num, ext_prepare_callback func, > + void *cbdata) > +{ > + struct ext4_ext_path *path = NULL; > + struct ext4_ext_cache cbex; > + struct ext4_extent *ex; > + ext4_lblk_t next, start = 0, end = 0; > + ext4_lblk_t last = block + num; > + int depth, exists, err = 0; > + > + BUG_ON(func == NULL); > + BUG_ON(inode == NULL); > + > + while (block < last && block != EXT_MAX_BLOCK) { > + num = last - block; > + /* find extent for this block */ > + path = ext4_ext_find_extent(inode, block, path); > + if (IS_ERR(path)) { > + err = PTR_ERR(path); > + path = NULL; > + break; > + } > + > + depth = ext_depth(inode); > + BUG_ON(path[depth].p_hdr == NULL); > + ex = path[depth].p_ext; > + next = ext4_ext_next_allocated_block(path); > + > + exists = 0; > + if (!ex) { > + /* there is no extent yet, so try to allocate > + * all requested space */ > + start = block; > + end = block + num; > + } else if (le32_to_cpu(ex->ee_block) > block) { > + /* need to allocate space before found extent */ > + start = block; > + end = le32_to_cpu(ex->ee_block); > + if (block + num < end) > + end = block + num; > + } else if (block >= le32_to_cpu(ex->ee_block) > + + ext4_ext_get_actual_len(ex)) { > + /* need to allocate space after found extent */ > + start = block; > + end = block + num; > + if (end >= next) > + end = next; > + } else if (block >= le32_to_cpu(ex->ee_block)) { > + /* > + * some part of requested space is covered > + * by found extent > + */ > + start = block; > + end = le32_to_cpu(ex->ee_block) > + + ext4_ext_get_actual_len(ex); > + if (block + num < end) > + end = block + num; > + exists = 1; > + } else { > + BUG(); > + } > + BUG_ON(end <= start); > + > + if (!exists) { > + cbex.ec_block = start; > + cbex.ec_len = end - start; > + cbex.ec_start = 0; > + cbex.ec_type = EXT4_EXT_CACHE_GAP; > + } else { > + cbex.ec_block = le32_to_cpu(ex->ee_block); > + cbex.ec_len = ext4_ext_get_actual_len(ex); > + cbex.ec_start = ext_pblock(ex); > + cbex.ec_type = EXT4_EXT_CACHE_EXTENT; > + } > + > + BUG_ON(cbex.ec_len == 0); > + err = func(inode, path, &cbex, cbdata); > + ext4_ext_drop_refs(path); > + > + if (err < 0) > + break; > + if (err == EXT_REPEAT) > + continue; > + else if (err == EXT_BREAK) { > + err = 0; > + break; > + } > + > + if (ext_depth(inode) != depth) { > + /* depth was changed. we have to realloc path */ > + kfree(path); > + path = NULL; > + } > + > + block = cbex.ec_block + cbex.ec_len; > + } > + > + if (path) { > + ext4_ext_drop_refs(path); > + kfree(path); > + } > + > + return err; > +} > + > static void > ext4_ext_put_in_cache(struct inode *inode, ext4_lblk_t block, > __u32 len, ext4_fsblk_t start, int type) > Index: linux-2.6.25-rc1/include/linux/ext4_fs_extents.h > =================================================================== > --- linux-2.6.25-rc1.orig/include/linux/ext4_fs_extents.h > +++ linux-2.6.25-rc1/include/linux/ext4_fs_extents.h > @@ -124,6 +124,19 @@ struct ext4_ext_path { > #define EXT4_EXT_CACHE_GAP 1 > #define EXT4_EXT_CACHE_EXTENT 2 > > +/* > + * to be called by ext4_ext_walk_space() > + * negative retcode - error > + * positive retcode - signal for ext4_ext_walk_space(), see below > + * callback must return valid extent (passed or newly created) > + */ > +typedef int (*ext_prepare_callback)(struct inode *, struct ext4_ext_path *, > + struct ext4_ext_cache *, > + void *); > + > +#define EXT_CONTINUE 0 > +#define EXT_BREAK 1 > +#define EXT_REPEAT 2 > > #define EXT_MAX_BLOCK 0xffffffff > > @@ -221,6 +234,7 @@ extern int ext4_ext_try_to_merge(struct > struct ext4_extent *); > extern unsigned int ext4_ext_check_overlap(struct inode *, struct ext4_extent *, struct ext4_ext_path *); > extern int ext4_ext_insert_extent(handle_t *, struct inode *, struct ext4_ext_path *, struct ext4_extent *); > +extern int ext4_ext_walk_space(struct inode *, ext4_lblk_t, ext4_lblk_t, ext_prepare_callback, void *); > extern struct ext4_ext_path *ext4_ext_find_extent(struct inode *, ext4_lblk_t, > struct ext4_ext_path *); > extern int ext4_ext_search_left(struct inode *, struct ext4_ext_path *, > > -- > To unsubscribe from this list: send the line "unsubscribe linux-ext4" in > the body of a message to majordomo@xxxxxxxxxxxxxxx > More majordomo info at http://vger.kernel.org/majordomo-info.html Cheers, Andreas -- Andreas Dilger Sr. Staff Engineer, Lustre Group Sun Microsystems of Canada, Inc. -- To unsubscribe from this list: send the line "unsubscribe linux-ext4" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html