Merge tag 'ext4_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso...
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 17 Dec 2012 01:33:01 +0000 (17:33 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 17 Dec 2012 01:33:01 +0000 (17:33 -0800)
Pull ext4 update from Ted Ts'o:
 "There are two major features for this merge window.  The first is
  inline data, which allows small files or directories to be stored in
  the in-inode extended attribute area.  (This requires that the file
  system use inodes which are at least 256 bytes or larger; 128 byte
  inodes do not have any room for in-inode xattrs.)

  The second new feature is SEEK_HOLE/SEEK_DATA support.  This is
  enabled by the extent status tree patches, and this infrastructure
  will be used to further optimize ext4 in the future.

  Beyond that, we have the usual collection of code cleanups and bug
  fixes."

* tag 'ext4_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4: (63 commits)
  ext4: zero out inline data using memset() instead of empty_zero_page
  ext4: ensure Inode flags consistency are checked at build time
  ext4: Remove CONFIG_EXT4_FS_XATTR
  ext4: remove unused variable from ext4_ext_in_cache()
  ext4: remove redundant initialization in ext4_fill_super()
  ext4: remove redundant code in ext4_alloc_inode()
  ext4: use sync_inode_metadata() when syncing inode metadata
  ext4: enable ext4 inline support
  ext4: let fallocate handle inline data correctly
  ext4: let ext4_truncate handle inline data correctly
  ext4: evict inline data out if we need to strore xattr in inode
  ext4: let fiemap work with inline data
  ext4: let ext4_rename handle inline dir
  ext4: let empty_dir handle inline dir
  ext4: let ext4_delete_entry() handle inline data
  ext4: make ext4_delete_entry generic
  ext4: let ext4_find_entry handle inline data
  ext4: create a new function search_dir
  ext4: let ext4_readdir handle inline data
  ext4: let add_dir_entry handle inline data properly
  ...

1  2 
fs/ext4/ext4.h
fs/jbd2/transaction.c

diff --combined fs/ext4/ext4.h
  #define ext4_debug(fmt, ...)  no_printk(fmt, ##__VA_ARGS__)
  #endif
  
+ /*
+  * Turn on EXT_DEBUG to get lots of info about extents operations.
+  */
+ #define EXT_DEBUG__
+ #ifdef EXT_DEBUG
+ #define ext_debug(fmt, ...)   printk(fmt, ##__VA_ARGS__)
+ #else
+ #define ext_debug(fmt, ...)   no_printk(fmt, ##__VA_ARGS__)
+ #endif
  #define EXT4_ERROR_INODE(inode, fmt, a...) \
        ext4_error_inode((inode), __func__, __LINE__, 0, (fmt), ## a)
  
@@@ -392,6 -402,7 +402,7 @@@ struct flex_groups 
  #define EXT4_EXTENTS_FL                       0x00080000 /* Inode uses extents */
  #define EXT4_EA_INODE_FL              0x00200000 /* Inode used for large EA */
  #define EXT4_EOFBLOCKS_FL             0x00400000 /* Blocks allocated beyond EOF */
+ #define EXT4_INLINE_DATA_FL           0x10000000 /* Inode has inline data. */
  #define EXT4_RESERVED_FL              0x80000000 /* reserved for ext4 lib */
  
  #define EXT4_FL_USER_VISIBLE          0x004BDFFF /* User visible flags */
@@@ -448,28 -459,26 +459,26 @@@ enum 
        EXT4_INODE_EXTENTS      = 19,   /* Inode uses extents */
        EXT4_INODE_EA_INODE     = 21,   /* Inode used for large EA */
        EXT4_INODE_EOFBLOCKS    = 22,   /* Blocks allocated beyond EOF */
+       EXT4_INODE_INLINE_DATA  = 28,   /* Data in inode. */
        EXT4_INODE_RESERVED     = 31,   /* reserved for ext4 lib */
  };
  
- #define TEST_FLAG_VALUE(FLAG) (EXT4_##FLAG##_FL == (1 << EXT4_INODE_##FLAG))
- #define CHECK_FLAG_VALUE(FLAG) if (!TEST_FLAG_VALUE(FLAG)) { \
-       printk(KERN_EMERG "EXT4 flag fail: " #FLAG ": %d %d\n", \
-               EXT4_##FLAG##_FL, EXT4_INODE_##FLAG); BUG_ON(1); }
- /*
-  * Since it's pretty easy to mix up bit numbers and hex values, and we
-  * can't do a compile-time test for ENUM values, we use a run-time
-  * test to make sure that EXT4_XXX_FL is consistent with respect to
-  * EXT4_INODE_XXX.  If all is well the printk and BUG_ON will all drop
-  * out so it won't cost any extra space in the compiled kernel image.
-  * But it's important that these values are the same, since we are
-  * using EXT4_INODE_XXX to test for the flag values, but EXT4_XX_FL
-  * must be consistent with the values of FS_XXX_FL defined in
-  * include/linux/fs.h and the on-disk values found in ext2, ext3, and
-  * ext4 filesystems, and of course the values defined in e2fsprogs.
+ /*
+  * Since it's pretty easy to mix up bit numbers and hex values, we use a
+  * build-time check to make sure that EXT4_XXX_FL is consistent with respect to
+  * EXT4_INODE_XXX. If all is well, the macros will be dropped, so, it won't cost
+  * any extra space in the compiled kernel image, otherwise, the build will fail.
+  * It's important that these values are the same, since we are using
+  * EXT4_INODE_XXX to test for flag values, but EXT4_XXX_FL must be consistent
+  * with the values of FS_XXX_FL defined in include/linux/fs.h and the on-disk
+  * values found in ext2, ext3 and ext4 filesystems, and of course the values
+  * defined in e2fsprogs.
   *
   * It's not paranoia if the Murphy's Law really *is* out to get you.  :-)
   */
+ #define TEST_FLAG_VALUE(FLAG) (EXT4_##FLAG##_FL == (1 << EXT4_INODE_##FLAG))
+ #define CHECK_FLAG_VALUE(FLAG) BUILD_BUG_ON(!TEST_FLAG_VALUE(FLAG))
  static inline void ext4_check_flag_values(void)
  {
        CHECK_FLAG_VALUE(SECRM);
        CHECK_FLAG_VALUE(EXTENTS);
        CHECK_FLAG_VALUE(EA_INODE);
        CHECK_FLAG_VALUE(EOFBLOCKS);
+       CHECK_FLAG_VALUE(INLINE_DATA);
        CHECK_FLAG_VALUE(RESERVED);
  }
  
@@@ -811,6 -821,8 +821,8 @@@ struct ext4_ext_cache 
        __u32           ec_len; /* must be 32bit to return holes */
  };
  
+ #include "extents_status.h"
  /*
   * fourth extended file system inode data in memory
   */
@@@ -833,7 -845,6 +845,6 @@@ struct ext4_inode_info 
  #endif
        unsigned long   i_flags;
  
- #ifdef CONFIG_EXT4_FS_XATTR
        /*
         * Extended attributes can be read independently of the main file
         * data. Taking i_mutex even when reading would cause contention
         * EAs.
         */
        struct rw_semaphore xattr_sem;
- #endif
  
        struct list_head i_orphan;      /* unlinked but open inodes */
  
        struct list_head i_prealloc_list;
        spinlock_t i_prealloc_lock;
  
+       /* extents status tree */
+       struct ext4_es_tree i_es_tree;
+       rwlock_t i_es_lock;
        /* ialloc */
        ext4_group_t    i_last_alloc_group;
  
        /* on-disk additional length */
        __u16 i_extra_isize;
  
+       /* Indicate the inline data space. */
+       u16 i_inline_off;
+       u16 i_inline_size;
  #ifdef CONFIG_QUOTA
        /* quota space reservation, managed internally by quota code */
        qsize_t i_reserved_quota;
@@@ -1360,6 -1378,7 +1378,7 @@@ enum 
        EXT4_STATE_DELALLOC_RESERVED,   /* blks already reserved for delalloc */
        EXT4_STATE_DIOREAD_LOCK,        /* Disable support for dio read
                                           nolocking */
+       EXT4_STATE_MAY_INLINE_DATA,     /* may have in-inode data */
  };
  
  #define EXT4_INODE_BIT_FNS(name, field, offset)                               \
@@@ -1481,7 -1500,7 +1500,7 @@@ static inline void ext4_clear_state_fla
  #define EXT4_FEATURE_INCOMPAT_DIRDATA         0x1000 /* data in dirent */
  #define EXT4_FEATURE_INCOMPAT_BG_USE_META_CSUM        0x2000 /* use crc32c for bg */
  #define EXT4_FEATURE_INCOMPAT_LARGEDIR                0x4000 /* >2GB or 3-lvl htree */
- #define EXT4_FEATURE_INCOMPAT_INLINEDATA      0x8000 /* data in inode */
+ #define EXT4_FEATURE_INCOMPAT_INLINE_DATA     0x8000 /* data in inode */
  
  #define EXT2_FEATURE_COMPAT_SUPP      EXT4_FEATURE_COMPAT_EXT_ATTR
  #define EXT2_FEATURE_INCOMPAT_SUPP    (EXT4_FEATURE_INCOMPAT_FILETYPE| \
                                         EXT4_FEATURE_INCOMPAT_EXTENTS| \
                                         EXT4_FEATURE_INCOMPAT_64BIT| \
                                         EXT4_FEATURE_INCOMPAT_FLEX_BG| \
-                                        EXT4_FEATURE_INCOMPAT_MMP)
+                                        EXT4_FEATURE_INCOMPAT_MMP |    \
+                                        EXT4_FEATURE_INCOMPAT_INLINE_DATA)
  #define EXT4_FEATURE_RO_COMPAT_SUPP   (EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER| \
                                         EXT4_FEATURE_RO_COMPAT_LARGE_FILE| \
                                         EXT4_FEATURE_RO_COMPAT_GDT_CSUM| \
@@@ -1592,6 -1612,11 +1612,11 @@@ struct ext4_dir_entry_tail 
        __le32  det_checksum;           /* crc32c(uuid+inum+dirblock) */
  };
  
+ #define EXT4_DIRENT_TAIL(block, blocksize) \
+       ((struct ext4_dir_entry_tail *)(((void *)(block)) + \
+                                       ((blocksize) - \
+                                        sizeof(struct ext4_dir_entry_tail))))
  /*
   * Ext4 directory file types.  Only the low 3 bits are used.  The
   * other bits are reserved for now.
@@@ -1936,14 -1961,42 +1961,42 @@@ ext4_fsblk_t ext4_inode_to_goal_block(s
  extern int __ext4_check_dir_entry(const char *, unsigned int, struct inode *,
                                  struct file *,
                                  struct ext4_dir_entry_2 *,
-                                 struct buffer_head *, unsigned int);
- #define ext4_check_dir_entry(dir, filp, de, bh, offset)                       \
+                                 struct buffer_head *, char *, int,
+                                 unsigned int);
+ #define ext4_check_dir_entry(dir, filp, de, bh, buf, size, offset)    \
        unlikely(__ext4_check_dir_entry(__func__, __LINE__, (dir), (filp), \
-                                       (de), (bh), (offset)))
+                                       (de), (bh), (buf), (size), (offset)))
  extern int ext4_htree_store_dirent(struct file *dir_file, __u32 hash,
                                    __u32 minor_hash,
                                    struct ext4_dir_entry_2 *dirent);
  extern void ext4_htree_free_dir_info(struct dir_private_info *p);
+ extern int ext4_find_dest_de(struct inode *dir, struct inode *inode,
+                            struct buffer_head *bh,
+                            void *buf, int buf_size,
+                            const char *name, int namelen,
+                            struct ext4_dir_entry_2 **dest_de);
+ void ext4_insert_dentry(struct inode *inode,
+                       struct ext4_dir_entry_2 *de,
+                       int buf_size,
+                       const char *name, int namelen);
+ static inline void ext4_update_dx_flag(struct inode *inode)
+ {
+       if (!EXT4_HAS_COMPAT_FEATURE(inode->i_sb,
+                                    EXT4_FEATURE_COMPAT_DIR_INDEX))
+               ext4_clear_inode_flag(inode, EXT4_INODE_INDEX);
+ }
+ static unsigned char ext4_filetype_table[] = {
+       DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK
+ };
+ static inline  unsigned char get_dtype(struct super_block *sb, int filetype)
+ {
+       if (!EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FILETYPE) ||
+           (filetype >= EXT4_FT_MAX))
+               return DT_UNKNOWN;
+       return ext4_filetype_table[filetype];
+ }
  
  /* fsync.c */
  extern int ext4_sync_file(struct file *, loff_t, loff_t, int);
@@@ -1994,8 -2047,23 +2047,23 @@@ struct buffer_head *ext4_getblk(handle_
                                                ext4_lblk_t, int, int *);
  struct buffer_head *ext4_bread(handle_t *, struct inode *,
                                                ext4_lblk_t, int, int *);
+ int ext4_get_block_write(struct inode *inode, sector_t iblock,
+                        struct buffer_head *bh_result, int create);
  int ext4_get_block(struct inode *inode, sector_t iblock,
                                struct buffer_head *bh_result, int create);
+ int ext4_da_get_block_prep(struct inode *inode, sector_t iblock,
+                          struct buffer_head *bh, int create);
+ int ext4_walk_page_buffers(handle_t *handle,
+                          struct buffer_head *head,
+                          unsigned from,
+                          unsigned to,
+                          int *partial,
+                          int (*fn)(handle_t *handle,
+                                    struct buffer_head *bh));
+ int do_journal_get_write_access(handle_t *handle,
+                               struct buffer_head *bh);
+ #define FALL_BACK_TO_NONDELALLOC 1
+ #define CONVERT_INLINE_DATA    2
  
  extern struct inode *ext4_iget(struct super_block *, unsigned long);
  extern int  ext4_write_inode(struct inode *, struct writeback_control *);
@@@ -2050,6 -2118,20 +2118,20 @@@ extern int ext4_orphan_add(handle_t *, 
  extern int ext4_orphan_del(handle_t *, struct inode *);
  extern int ext4_htree_fill_tree(struct file *dir_file, __u32 start_hash,
                                __u32 start_minor_hash, __u32 *next_hash);
+ extern int search_dir(struct buffer_head *bh,
+                     char *search_buf,
+                     int buf_size,
+                     struct inode *dir,
+                     const struct qstr *d_name,
+                     unsigned int offset,
+                     struct ext4_dir_entry_2 **res_dir);
+ extern int ext4_generic_delete_entry(handle_t *handle,
+                                    struct inode *dir,
+                                    struct ext4_dir_entry_2 *de_del,
+                                    struct buffer_head *bh,
+                                    void *entry_buf,
+                                    int buf_size,
+                                    int csum_size);
  
  /* resize.c */
  extern int ext4_group_add(struct super_block *sb,
@@@ -2376,6 -2458,15 +2458,15 @@@ extern void ext4_unwritten_wait(struct 
  extern const struct inode_operations ext4_dir_inode_operations;
  extern const struct inode_operations ext4_special_inode_operations;
  extern struct dentry *ext4_get_parent(struct dentry *child);
+ extern struct ext4_dir_entry_2 *ext4_init_dot_dotdot(struct inode *inode,
+                                struct ext4_dir_entry_2 *de,
+                                int blocksize, int csum_size,
+                                unsigned int parent_ino, int dotdot_real_len);
+ extern void initialize_dirent_tail(struct ext4_dir_entry_tail *t,
+                                  unsigned int blocksize);
+ extern int ext4_handle_dirty_dirent_node(handle_t *handle,
+                                        struct inode *inode,
+                                        struct buffer_head *bh);
  
  /* symlink.c */
  extern const struct inode_operations ext4_symlink_inode_operations;
@@@ -2393,6 -2484,9 +2484,9 @@@ extern int ext4_check_blockref(const ch
                               struct inode *, __le32 *, unsigned int);
  
  /* extents.c */
+ struct ext4_ext_path;
+ struct ext4_extent;
  extern int ext4_ext_tree_init(handle_t *handle, struct inode *);
  extern int ext4_ext_writepage_trans_blocks(struct inode *, int);
  extern int ext4_ext_index_trans_blocks(struct inode *inode, int nrblocks,
@@@ -2410,8 -2504,27 +2504,27 @@@ extern int ext4_convert_unwritten_exten
                          ssize_t len);
  extern int ext4_map_blocks(handle_t *handle, struct inode *inode,
                           struct ext4_map_blocks *map, int flags);
+ extern int ext4_ext_calc_metadata_amount(struct inode *inode,
+                                        ext4_lblk_t lblocks);
+ extern int ext4_extent_tree_init(handle_t *, struct inode *);
+ extern int ext4_ext_calc_credits_for_single_extent(struct inode *inode,
+                                                  int num,
+                                                  struct ext4_ext_path *path);
+ extern int ext4_can_extents_be_merged(struct inode *inode,
+                                     struct ext4_extent *ex1,
+                                     struct ext4_extent *ex2);
+ extern int ext4_ext_insert_extent(handle_t *, struct inode *,
+                                 struct ext4_ext_path *,
+                                 struct ext4_extent *, int);
+ extern struct ext4_ext_path *ext4_ext_find_extent(struct inode *, ext4_lblk_t,
+                                                 struct ext4_ext_path *);
+ extern void ext4_ext_drop_refs(struct ext4_ext_path *);
+ extern int ext4_ext_check_inode(struct inode *inode);
+ extern int ext4_find_delalloc_cluster(struct inode *inode, ext4_lblk_t lblk);
  extern int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
                        __u64 start, __u64 len);
  /* move_extent.c */
  extern int ext4_move_extents(struct file *o_filp, struct file *d_filp,
                             __u64 start_orig, __u64 start_donor,
@@@ -2445,17 -2558,13 +2558,13 @@@ enum ext4_state_bits 
                                 * never, ever appear in a buffer_head's state
                                 * flag. See EXT4_MAP_FROM_CLUSTER to see where
                                 * this is used. */
-       BH_Da_Mapped,   /* Delayed allocated block that now has a mapping. This
-                        * flag is set when ext4_map_blocks is called on a
-                        * delayed allocated block to get its real mapping. */
  };
  
  BUFFER_FNS(Uninit, uninit)
  TAS_BUFFER_FNS(Uninit, uninit)
- BUFFER_FNS(Da_Mapped, da_mapped)
  
  /*
 - * Add new method to test wether block and inode bitmaps are properly
 + * Add new method to test whether block and inode bitmaps are properly
   * initialized. With uninit_bg reading the block from disk is not enough
   * to mark the bitmap uptodate. We need to also zero-out the bitmap
   */
@@@ -2503,6 -2612,4 +2612,4 @@@ extern void ext4_resize_end(struct supe
  
  #endif        /* __KERNEL__ */
  
- #include "ext4_extents.h"
  #endif        /* _EXT4_H */
diff --combined fs/jbd2/transaction.c
@@@ -1207,17 -1207,6 +1207,6 @@@ out
        return ret;
  }
  
- /*
-  * jbd2_journal_release_buffer: undo a get_write_access without any buffer
-  * updates, if the update decided in the end that it didn't need access.
-  *
-  */
- void
- jbd2_journal_release_buffer(handle_t *handle, struct buffer_head *bh)
- {
-       BUFFER_TRACE(bh, "entry");
- }
  /**
   * void jbd2_journal_forget() - bforget() for potentially-journaled buffers.
   * @handle: transaction handle
@@@ -1261,7 -1250,7 +1250,7 @@@ int jbd2_journal_forget (handle_t *hand
                goto not_jbd;
        }
  
 -      /* keep track of wether or not this transaction modified us */
 +      /* keep track of whether or not this transaction modified us */
        was_modified = jh->b_modified;
  
        /*