Commit 8aefcd557d26d0023a36f9ec5afbf55e59f8f26b

Authored by Theodore Ts'o
1 parent 353eb83c14

ext4: dynamically allocate the jbd2_inode in ext4_inode_info as necessary

Replace the jbd2_inode structure (which is 48 bytes) with a pointer
and only allocate the jbd2_inode when it is needed --- that is, when
the file system has a journal present and the inode has been opened
for writing.  This allows us to further slim down the ext4_inode_info
structure.

Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>

Showing 7 changed files with 74 additions and 25 deletions Side-by-side Diff

... ... @@ -811,7 +811,7 @@
811 811 */
812 812 struct rw_semaphore i_data_sem;
813 813 struct inode vfs_inode;
814   - struct jbd2_inode jinode;
  814 + struct jbd2_inode *jinode;
815 815  
816 816 struct ext4_ext_cache i_cached_extent;
817 817 /*
... ... @@ -253,7 +253,7 @@
253 253 static inline int ext4_jbd2_file_inode(handle_t *handle, struct inode *inode)
254 254 {
255 255 if (ext4_handle_valid(handle))
256   - return jbd2_journal_file_inode(handle, &EXT4_I(inode)->jinode);
  256 + return jbd2_journal_file_inode(handle, EXT4_I(inode)->jinode);
257 257 return 0;
258 258 }
259 259  
... ... @@ -104,6 +104,7 @@
104 104 {
105 105 struct super_block *sb = inode->i_sb;
106 106 struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
  107 + struct ext4_inode_info *ei = EXT4_I(inode);
107 108 struct vfsmount *mnt = filp->f_path.mnt;
108 109 struct path path;
109 110 char buf[64], *cp;
... ... @@ -126,6 +127,27 @@
126 127 sizeof(sbi->s_es->s_last_mounted));
127 128 ext4_mark_super_dirty(sb);
128 129 }
  130 + }
  131 + /*
  132 + * Set up the jbd2_inode if we are opening the inode for
  133 + * writing and the journal is present
  134 + */
  135 + if (sbi->s_journal && !ei->jinode && (filp->f_mode & FMODE_WRITE)) {
  136 + struct jbd2_inode *jinode = jbd2_alloc_inode(GFP_KERNEL);
  137 +
  138 + spin_lock(&inode->i_lock);
  139 + if (!ei->jinode) {
  140 + if (!jinode) {
  141 + spin_unlock(&inode->i_lock);
  142 + return -ENOMEM;
  143 + }
  144 + ei->jinode = jinode;
  145 + jbd2_journal_init_jbd_inode(ei->jinode, inode);
  146 + jinode = NULL;
  147 + }
  148 + spin_unlock(&inode->i_lock);
  149 + if (unlikely(jinode != NULL))
  150 + jbd2_free_inode(jinode);
129 151 }
130 152 return dquot_file_open(inode, filp);
131 153 }
... ... @@ -55,10 +55,17 @@
55 55 loff_t new_size)
56 56 {
57 57 trace_ext4_begin_ordered_truncate(inode, new_size);
58   - return jbd2_journal_begin_ordered_truncate(
59   - EXT4_SB(inode->i_sb)->s_journal,
60   - &EXT4_I(inode)->jinode,
61   - new_size);
  58 + /*
  59 + * If jinode is zero, then we never opened the file for
  60 + * writing, so there's no need to call
  61 + * jbd2_journal_begin_ordered_truncate() since there's no
  62 + * outstanding writes we need to flush.
  63 + */
  64 + if (!EXT4_I(inode)->jinode)
  65 + return 0;
  66 + return jbd2_journal_begin_ordered_truncate(EXT4_JOURNAL(inode),
  67 + EXT4_I(inode)->jinode,
  68 + new_size);
62 69 }
63 70  
64 71 static void ext4_invalidatepage(struct page *page, unsigned long offset);
... ... @@ -4054,7 +4061,7 @@
4054 4061 if (ext4_should_journal_data(inode)) {
4055 4062 err = ext4_handle_dirty_metadata(handle, inode, bh);
4056 4063 } else {
4057   - if (ext4_should_order_data(inode))
  4064 + if (ext4_should_order_data(inode) && EXT4_I(inode)->jinode)
4058 4065 err = ext4_jbd2_file_inode(handle, inode);
4059 4066 mark_buffer_dirty(bh);
4060 4067 }
... ... @@ -818,12 +818,6 @@
818 818 memset(&ei->i_cached_extent, 0, sizeof(struct ext4_ext_cache));
819 819 INIT_LIST_HEAD(&ei->i_prealloc_list);
820 820 spin_lock_init(&ei->i_prealloc_lock);
821   - /*
822   - * Note: We can be called before EXT4_SB(sb)->s_journal is set,
823   - * therefore it can be null here. Don't check it, just initialize
824   - * jinode.
825   - */
826   - jbd2_journal_init_jbd_inode(&ei->jinode, &ei->vfs_inode);
827 821 ei->i_reserved_data_blocks = 0;
828 822 ei->i_reserved_meta_blocks = 0;
829 823 ei->i_allocated_meta_blocks = 0;
... ... @@ -832,6 +826,7 @@
832 826 #ifdef CONFIG_QUOTA
833 827 ei->i_reserved_quota = 0;
834 828 #endif
  829 + ei->jinode = NULL;
835 830 INIT_LIST_HEAD(&ei->i_completed_io_list);
836 831 spin_lock_init(&ei->i_completed_io_lock);
837 832 ei->cur_aio_dio = NULL;
... ... @@ -900,9 +895,12 @@
900 895 end_writeback(inode);
901 896 dquot_drop(inode);
902 897 ext4_discard_preallocations(inode);
903   - if (EXT4_JOURNAL(inode))
904   - jbd2_journal_release_jbd_inode(EXT4_SB(inode->i_sb)->s_journal,
905   - &EXT4_I(inode)->jinode);
  898 + if (EXT4_I(inode)->jinode) {
  899 + jbd2_journal_release_jbd_inode(EXT4_JOURNAL(inode),
  900 + EXT4_I(inode)->jinode);
  901 + jbd2_free_inode(EXT4_I(inode)->jinode);
  902 + EXT4_I(inode)->jinode = NULL;
  903 + }
906 904 }
907 905  
908 906 static inline void ext4_show_quota_options(struct seq_file *seq,
... ... @@ -94,6 +94,7 @@
94 94 EXPORT_SYMBOL(jbd2_journal_init_jbd_inode);
95 95 EXPORT_SYMBOL(jbd2_journal_release_jbd_inode);
96 96 EXPORT_SYMBOL(jbd2_journal_begin_ordered_truncate);
  97 +EXPORT_SYMBOL(jbd2_inode_cache);
97 98  
98 99 static int journal_convert_superblock_v1(journal_t *, journal_superblock_t *);
99 100 static void __journal_abort_soft (journal_t *journal, int errno);
100 101  
101 102  
102 103  
... ... @@ -2286,19 +2287,21 @@
2286 2287  
2287 2288 #endif
2288 2289  
2289   -struct kmem_cache *jbd2_handle_cache;
  2290 +struct kmem_cache *jbd2_handle_cache, *jbd2_inode_cache;
2290 2291  
2291 2292 static int __init journal_init_handle_cache(void)
2292 2293 {
2293   - jbd2_handle_cache = kmem_cache_create("jbd2_journal_handle",
2294   - sizeof(handle_t),
2295   - 0, /* offset */
2296   - SLAB_TEMPORARY, /* flags */
2297   - NULL); /* ctor */
  2294 + jbd2_handle_cache = KMEM_CACHE(jbd2_journal_handle, SLAB_TEMPORARY);
2298 2295 if (jbd2_handle_cache == NULL) {
2299   - printk(KERN_EMERG "JBD: failed to create handle cache\n");
  2296 + printk(KERN_EMERG "JBD2: failed to create handle cache\n");
2300 2297 return -ENOMEM;
2301 2298 }
  2299 + jbd2_inode_cache = KMEM_CACHE(jbd2_inode, 0);
  2300 + if (jbd2_inode_cache == NULL) {
  2301 + printk(KERN_EMERG "JBD2: failed to create inode cache\n");
  2302 + kmem_cache_destroy(jbd2_handle_cache);
  2303 + return -ENOMEM;
  2304 + }
2302 2305 return 0;
2303 2306 }
2304 2307  
... ... @@ -2306,6 +2309,9 @@
2306 2309 {
2307 2310 if (jbd2_handle_cache)
2308 2311 kmem_cache_destroy(jbd2_handle_cache);
  2312 + if (jbd2_inode_cache)
  2313 + kmem_cache_destroy(jbd2_inode_cache);
  2314 +
2309 2315 }
2310 2316  
2311 2317 /*
include/linux/jbd2.h
... ... @@ -94,7 +94,7 @@
94 94 *
95 95 * This is an opaque datatype.
96 96 **/
97   -typedef struct handle_s handle_t; /* Atomic operation type */
  97 +typedef struct jbd2_journal_handle handle_t; /* Atomic operation type */
98 98  
99 99  
100 100 /**
... ... @@ -416,7 +416,7 @@
416 416 * in so it can be fixed later.
417 417 */
418 418  
419   -struct handle_s
  419 +struct jbd2_journal_handle
420 420 {
421 421 /* Which compound transaction is this update a part of? */
422 422 transaction_t *h_transaction;
... ... @@ -1156,6 +1156,22 @@
1156 1156 static inline void jbd2_free_handle(handle_t *handle)
1157 1157 {
1158 1158 kmem_cache_free(jbd2_handle_cache, handle);
  1159 +}
  1160 +
  1161 +/*
  1162 + * jbd2_inode management (optional, for those file systems that want to use
  1163 + * dynamically allocated jbd2_inode structures)
  1164 + */
  1165 +extern struct kmem_cache *jbd2_inode_cache;
  1166 +
  1167 +static inline struct jbd2_inode *jbd2_alloc_inode(gfp_t gfp_flags)
  1168 +{
  1169 + return kmem_cache_alloc(jbd2_inode_cache, gfp_flags);
  1170 +}
  1171 +
  1172 +static inline void jbd2_free_inode(struct jbd2_inode *jinode)
  1173 +{
  1174 + kmem_cache_free(jbd2_inode_cache, jinode);
1159 1175 }
1160 1176  
1161 1177 /* Primary revoke support */