Whamcloud - gitweb
Branch b1_8
[fs/lustre-release.git] / ldiskfs / kernel_patches / patches / ext4-fiemap-2.6-rhel5.patch
index 7163c94..b9468f8 100644 (file)
@@ -184,13 +184,13 @@ Index: linux-2.6.18-128.1.6/fs/ext4/ext4.h
 --- 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
@@ -203,277 +203,13 @@ Index: linux-2.6.18-128.1.6/fs/ext4/ext4.h
 @@ -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