--- linux-2.6.18-128.1.6.orig/fs/ext4/ext4.h
+++ linux-2.6.18-128.1.6/fs/ext4/ext4.h
@@ -300,6 +300,7 @@ struct ext4_new_group_data {
- #define EXT4_IOC_GETRSVSZ _IOR('f', 5, long)
- #define EXT4_IOC_SETRSVSZ _IOW('f', 6, long)
- #define EXT4_IOC_MIGRATE _IO('f', 7)
+ #define EXT4_IOC_GROUP_EXTEND _IOW('f', 7, unsigned long)
+ #define EXT4_IOC_GROUP_ADD _IOW('f', 8, struct ext4_new_group_input)
+ #define EXT4_IOC_MIGRATE _IO('f', 9)
+#define EXT4_IOC_FIEMAP _IOWR('f', 11, struct fiemap)
+ /* note ioctl 11 reserved for filesystem-independent FIEMAP ioctl */
/*
- * ioctl commands in 32 bit emulation
@@ -317,6 +318,8 @@ struct ext4_new_group_data {
#define EXT4_IOC32_GETVERSION_OLD FS_IOC32_GETVERSION
#define EXT4_IOC32_SETVERSION_OLD FS_IOC32_SETVERSION
@@ -1117,6 +1120,9 @@ extern int ext4_page_mkwrite(struct vm_a
/* ioctl.c */
extern long ext4_ioctl(struct file *, unsigned int, unsigned long);
- extern long ext4_compat_ioctl (struct file *, unsigned int, unsigned long);
+ extern long ext4_compat_ioctl(struct file *, unsigned int, unsigned long);
+struct fiemap_extent_info;
+extern int ext4_fiemap(struct inode *, struct fiemap_extent_info *, __u64,
+ __u64);
/* migrate.c */
extern int ext4_ext_migrate(struct inode *, struct file *, unsigned int,
-Index: linux-2.6.18-128.1.6/fs/ext4/ext4_extents.h
-===================================================================
---- linux-2.6.18-128.1.6.orig/fs/ext4/ext4_extents.h
-+++ linux-2.6.18-128.1.6/fs/ext4/ext4_extents.h
-@@ -128,6 +128,22 @@ struct ext4_ext_path {
- #define EXT_MAX_BLOCK 0xffffffff
-
- /*
-+ * 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 *,
-+ struct ext4_extent *, void *);
-+
-+#define HAVE_EXT_PREPARE_CB_EXTENT
-+
-+#define EXT_CONTINUE 0
-+#define EXT_BREAK 1
-+#define EXT_REPEAT 2
-+
-+/*
- * EXT_INIT_MAX_LEN is the maximum number of blocks we can have in an
- * initialized extent. This is 2^15 and not (2^16 - 1), since we use the
- * MSB of ee_len field in the extent datastructure to signify if this
-@@ -223,6 +239,8 @@ 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 *,
-Index: linux-2.6.18-128.1.6/fs/ext4/extents.c
-===================================================================
---- linux-2.6.18-128.1.6.orig/fs/ext4/extents.c
-+++ linux-2.6.18-128.1.6/fs/ext4/extents.c
-@@ -44,7 +44,7 @@
- #include <asm/uaccess.h>
- #include "ext4_jbd2.h"
- #include "ext4_extents.h"
--
-+#include "fiemap.h"
-
- /*
- * ext_pblock:
-@@ -1597,6 +1597,113 @@ 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, ex, 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)
-@@ -2953,3 +3060,100 @@ retry:
- return ret > 0 ? ret2 : ret;
- }
- #endif
-+
-+/*
-+ * Callback function called for each extent to gather FIEMAP information.
-+ */
-+int ext4_ext_fiemap_cb(struct inode *inode, struct ext4_ext_path *path,
-+ struct ext4_ext_cache *newex, struct ext4_extent *ex,
-+ void *data)
-+{
-+ struct fiemap_extent_info *fieinfo = data;
-+ unsigned char blksize_bits = inode->i_sb->s_blocksize_bits;
-+ __u64 logical;
-+ __u64 physical;
-+ __u64 length;
-+ __u32 flags = 0;
-+ int error;
-+
-+ logical = (__u64)newex->ec_block << blksize_bits;
-+
-+ if (newex->ec_type == EXT4_EXT_CACHE_GAP) {
-+ pgoff_t offset;
-+ struct page *page;
-+ struct buffer_head *bh = NULL;
-+
-+ offset = logical >> PAGE_SHIFT;
-+ page = find_get_page(inode->i_mapping, offset);
-+ if (!page || !page_has_buffers(page))
-+ return EXT_CONTINUE;
-+
-+ bh = page_buffers(page);
-+
-+ if (!bh)
-+ return EXT_CONTINUE;
-+
-+ if (buffer_delay(bh)) {
-+ flags |= FIEMAP_EXTENT_DELALLOC;
-+ page_cache_release(page);
-+ } else {
-+ page_cache_release(page);
-+ return EXT_CONTINUE;
-+ }
-+ }
-+
-+ physical = (__u64)newex->ec_start << blksize_bits;
-+ length = (__u64)newex->ec_len << blksize_bits;
-+
-+ if (ex && ext4_ext_is_uninitialized(ex))
-+ flags |= FIEMAP_EXTENT_UNWRITTEN;
-+
-+ /*
-+ * If this extent reaches EXT_MAX_BLOCK, it must be last.
-+ *
-+ * Or if ext4_ext_next_allocated_block is EXT_MAX_BLOCK,
-+ * this indicates no more allocated blocks.
-+ *
-+ * XXX this might miss a single-block extent at EXT_MAX_BLOCK
-+ */
-+ if (ext4_ext_next_allocated_block(path) == EXT_MAX_BLOCK ||
-+ newex->ec_block + newex->ec_len - 1 == EXT_MAX_BLOCK)
-+ flags |= FIEMAP_EXTENT_LAST;
-+
-+ error = fiemap_fill_next_extent(fieinfo, logical, physical,
-+ length, flags, inode->i_sb->s_dev);
-+ if (error < 0)
-+ return error;
-+ if (error == 1)
-+ return EXT_BREAK;
-+
-+ return EXT_CONTINUE;
-+}
-+
-+int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
-+ __u64 start, __u64 len)
-+{
-+ ext4_fsblk_t start_blk;
-+ ext4_fsblk_t len_blks;
-+ int error = 0;
-+
-+ if (!(EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL))
-+ return -EOPNOTSUPP;
-+
-+ if (fiemap_check_flags(fieinfo, EXT4_FIEMAP_FLAGS_COMPAT))
-+ return -EBADR;
-+
-+ start_blk = start >> inode->i_sb->s_blocksize_bits;
-+ len_blks = (len + inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits;
-+
-+ /*
-+ * Walk the extent tree gathering extent information.
-+ * ext4_ext_fiemap_cb will push extents back to user.
-+ */
-+ down_write(&EXT4_I(inode)->i_data_sem);
-+ error = ext4_ext_walk_space(inode, start_blk, len_blks,
-+ ext4_ext_fiemap_cb, fieinfo);
-+ up_write(&EXT4_I(inode)->i_data_sem);
-+
-+ return error;
-+}
Index: linux-2.6.18-128.1.6/fs/ext4/fiemap.h
===================================================================
--- /dev/null