diff options
| -rw-r--r-- | fs/inode.c | 30 | ||||
| -rw-r--r-- | fs/xfs/xfs_iget.c | 17 | ||||
| -rw-r--r-- | include/linux/fs.h | 2 |
3 files changed, 23 insertions, 26 deletions
diff --git a/fs/inode.c b/fs/inode.c index 901bad1e5f12..af2c05235cc8 100644 --- a/fs/inode.c +++ b/fs/inode.c | |||
| @@ -120,12 +120,11 @@ static void wake_up_inode(struct inode *inode) | |||
| 120 | * These are initializations that need to be done on every inode | 120 | * These are initializations that need to be done on every inode |
| 121 | * allocation as the fields are not initialised by slab allocation. | 121 | * allocation as the fields are not initialised by slab allocation. |
| 122 | */ | 122 | */ |
| 123 | struct inode *inode_init_always(struct super_block *sb, struct inode *inode) | 123 | int inode_init_always(struct super_block *sb, struct inode *inode) |
| 124 | { | 124 | { |
| 125 | static const struct address_space_operations empty_aops; | 125 | static const struct address_space_operations empty_aops; |
| 126 | static struct inode_operations empty_iops; | 126 | static struct inode_operations empty_iops; |
| 127 | static const struct file_operations empty_fops; | 127 | static const struct file_operations empty_fops; |
| 128 | |||
| 129 | struct address_space *const mapping = &inode->i_data; | 128 | struct address_space *const mapping = &inode->i_data; |
| 130 | 129 | ||
| 131 | inode->i_sb = sb; | 130 | inode->i_sb = sb; |
| @@ -152,7 +151,7 @@ struct inode *inode_init_always(struct super_block *sb, struct inode *inode) | |||
| 152 | inode->dirtied_when = 0; | 151 | inode->dirtied_when = 0; |
| 153 | 152 | ||
| 154 | if (security_inode_alloc(inode)) | 153 | if (security_inode_alloc(inode)) |
| 155 | goto out_free_inode; | 154 | goto out; |
| 156 | 155 | ||
| 157 | /* allocate and initialize an i_integrity */ | 156 | /* allocate and initialize an i_integrity */ |
| 158 | if (ima_inode_alloc(inode)) | 157 | if (ima_inode_alloc(inode)) |
| @@ -198,16 +197,12 @@ struct inode *inode_init_always(struct super_block *sb, struct inode *inode) | |||
| 198 | inode->i_fsnotify_mask = 0; | 197 | inode->i_fsnotify_mask = 0; |
| 199 | #endif | 198 | #endif |
| 200 | 199 | ||
| 201 | return inode; | 200 | return 0; |
| 202 | 201 | ||
| 203 | out_free_security: | 202 | out_free_security: |
| 204 | security_inode_free(inode); | 203 | security_inode_free(inode); |
| 205 | out_free_inode: | 204 | out: |
| 206 | if (inode->i_sb->s_op->destroy_inode) | 205 | return -ENOMEM; |
| 207 | inode->i_sb->s_op->destroy_inode(inode); | ||
| 208 | else | ||
| 209 | kmem_cache_free(inode_cachep, (inode)); | ||
| 210 | return NULL; | ||
| 211 | } | 206 | } |
| 212 | EXPORT_SYMBOL(inode_init_always); | 207 | EXPORT_SYMBOL(inode_init_always); |
| 213 | 208 | ||
| @@ -220,9 +215,18 @@ static struct inode *alloc_inode(struct super_block *sb) | |||
| 220 | else | 215 | else |
| 221 | inode = kmem_cache_alloc(inode_cachep, GFP_KERNEL); | 216 | inode = kmem_cache_alloc(inode_cachep, GFP_KERNEL); |
| 222 | 217 | ||
| 223 | if (inode) | 218 | if (!inode) |
| 224 | return inode_init_always(sb, inode); | 219 | return NULL; |
| 225 | return NULL; | 220 | |
| 221 | if (unlikely(inode_init_always(sb, inode))) { | ||
| 222 | if (inode->i_sb->s_op->destroy_inode) | ||
| 223 | inode->i_sb->s_op->destroy_inode(inode); | ||
| 224 | else | ||
| 225 | kmem_cache_free(inode_cachep, inode); | ||
| 226 | return NULL; | ||
| 227 | } | ||
| 228 | |||
| 229 | return inode; | ||
| 226 | } | 230 | } |
| 227 | 231 | ||
| 228 | void destroy_inode(struct inode *inode) | 232 | void destroy_inode(struct inode *inode) |
diff --git a/fs/xfs/xfs_iget.c b/fs/xfs/xfs_iget.c index 5fcec6f020a7..719c85b155f4 100644 --- a/fs/xfs/xfs_iget.c +++ b/fs/xfs/xfs_iget.c | |||
| @@ -64,6 +64,10 @@ xfs_inode_alloc( | |||
| 64 | ip = kmem_zone_alloc(xfs_inode_zone, KM_SLEEP); | 64 | ip = kmem_zone_alloc(xfs_inode_zone, KM_SLEEP); |
| 65 | if (!ip) | 65 | if (!ip) |
| 66 | return NULL; | 66 | return NULL; |
| 67 | if (inode_init_always(mp->m_super, VFS_I(ip))) { | ||
| 68 | kmem_zone_free(xfs_inode_zone, ip); | ||
| 69 | return NULL; | ||
| 70 | } | ||
| 67 | 71 | ||
| 68 | ASSERT(atomic_read(&ip->i_iocount) == 0); | 72 | ASSERT(atomic_read(&ip->i_iocount) == 0); |
| 69 | ASSERT(atomic_read(&ip->i_pincount) == 0); | 73 | ASSERT(atomic_read(&ip->i_pincount) == 0); |
| @@ -105,17 +109,6 @@ xfs_inode_alloc( | |||
| 105 | #ifdef XFS_DIR2_TRACE | 109 | #ifdef XFS_DIR2_TRACE |
| 106 | ip->i_dir_trace = ktrace_alloc(XFS_DIR2_KTRACE_SIZE, KM_NOFS); | 110 | ip->i_dir_trace = ktrace_alloc(XFS_DIR2_KTRACE_SIZE, KM_NOFS); |
| 107 | #endif | 111 | #endif |
| 108 | /* | ||
| 109 | * Now initialise the VFS inode. We do this after the xfs_inode | ||
| 110 | * initialisation as internal failures will result in ->destroy_inode | ||
| 111 | * being called and that will pass down through the reclaim path and | ||
| 112 | * free the XFS inode. This path requires the XFS inode to already be | ||
| 113 | * initialised. Hence if this call fails, the xfs_inode has already | ||
| 114 | * been freed and we should not reference it at all in the error | ||
| 115 | * handling. | ||
| 116 | */ | ||
| 117 | if (!inode_init_always(mp->m_super, VFS_I(ip))) | ||
| 118 | return NULL; | ||
| 119 | 112 | ||
| 120 | /* prevent anyone from using this yet */ | 113 | /* prevent anyone from using this yet */ |
| 121 | VFS_I(ip)->i_state = I_NEW|I_LOCK; | 114 | VFS_I(ip)->i_state = I_NEW|I_LOCK; |
| @@ -167,7 +160,7 @@ xfs_iget_cache_hit( | |||
| 167 | * errors cleanly, then tag it so it can be set up correctly | 160 | * errors cleanly, then tag it so it can be set up correctly |
| 168 | * later. | 161 | * later. |
| 169 | */ | 162 | */ |
| 170 | if (!inode_init_always(mp->m_super, VFS_I(ip))) { | 163 | if (inode_init_always(mp->m_super, VFS_I(ip))) { |
| 171 | error = ENOMEM; | 164 | error = ENOMEM; |
| 172 | goto out_error; | 165 | goto out_error; |
| 173 | } | 166 | } |
diff --git a/include/linux/fs.h b/include/linux/fs.h index a36ffa5a77a4..0c3b5e58a986 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
| @@ -2137,7 +2137,7 @@ extern loff_t default_llseek(struct file *file, loff_t offset, int origin); | |||
| 2137 | 2137 | ||
| 2138 | extern loff_t vfs_llseek(struct file *file, loff_t offset, int origin); | 2138 | extern loff_t vfs_llseek(struct file *file, loff_t offset, int origin); |
| 2139 | 2139 | ||
| 2140 | extern struct inode * inode_init_always(struct super_block *, struct inode *); | 2140 | extern int inode_init_always(struct super_block *, struct inode *); |
| 2141 | extern void inode_init_once(struct inode *); | 2141 | extern void inode_init_once(struct inode *); |
| 2142 | extern void inode_add_to_lists(struct super_block *, struct inode *); | 2142 | extern void inode_add_to_lists(struct super_block *, struct inode *); |
| 2143 | extern void iput(struct inode *); | 2143 | extern void iput(struct inode *); |
