aboutsummaryrefslogtreecommitdiffstats
path: root/fs/inode.c
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2019-04-10 14:43:44 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2019-05-01 22:37:39 -0400
commitfdb0da89f4ba0c74d7d3b9e6f471e96a5766820b (patch)
tree3c82eb1fe04568315a76d03ec86617e206b12a41 /fs/inode.c
parentad7999cd701e4e058765d35cf5274ee16801e986 (diff)
new inode method: ->free_inode()
A lot of ->destroy_inode() instances end with call_rcu() of a callback that does RCU-delayed part of freeing. Introduce a new method for doing just that, with saner signature. Rules: ->destroy_inode ->free_inode f g immediate call of f(), RCU-delayed call of g() f NULL immediate call of f(), no RCU-delayed calls NULL g RCU-delayed call of g() NULL NULL RCU-delayed default freeing IOW, NULL ->free_inode gives the same behaviour as now. Note that NULL, NULL is equivalent to NULL, free_inode_nonrcu; we could mandate the latter form, but that would have very little benefit beyond making rules a bit more symmetric. It would break backwards compatibility, require extra boilerplate and expected semantics for (NULL, NULL) pair would have no use whatsoever... Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/inode.c')
-rw-r--r--fs/inode.c56
1 files changed, 34 insertions, 22 deletions
diff --git a/fs/inode.c b/fs/inode.c
index e9d97add2b36..627e1766503a 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -202,12 +202,28 @@ out:
202} 202}
203EXPORT_SYMBOL(inode_init_always); 203EXPORT_SYMBOL(inode_init_always);
204 204
205void free_inode_nonrcu(struct inode *inode)
206{
207 kmem_cache_free(inode_cachep, inode);
208}
209EXPORT_SYMBOL(free_inode_nonrcu);
210
211static void i_callback(struct rcu_head *head)
212{
213 struct inode *inode = container_of(head, struct inode, i_rcu);
214 if (inode->free_inode)
215 inode->free_inode(inode);
216 else
217 free_inode_nonrcu(inode);
218}
219
205static struct inode *alloc_inode(struct super_block *sb) 220static struct inode *alloc_inode(struct super_block *sb)
206{ 221{
222 const struct super_operations *ops = sb->s_op;
207 struct inode *inode; 223 struct inode *inode;
208 224
209 if (sb->s_op->alloc_inode) 225 if (ops->alloc_inode)
210 inode = sb->s_op->alloc_inode(sb); 226 inode = ops->alloc_inode(sb);
211 else 227 else
212 inode = kmem_cache_alloc(inode_cachep, GFP_KERNEL); 228 inode = kmem_cache_alloc(inode_cachep, GFP_KERNEL);
213 229
@@ -215,22 +231,19 @@ static struct inode *alloc_inode(struct super_block *sb)
215 return NULL; 231 return NULL;
216 232
217 if (unlikely(inode_init_always(sb, inode))) { 233 if (unlikely(inode_init_always(sb, inode))) {
218 if (inode->i_sb->s_op->destroy_inode) 234 if (ops->destroy_inode) {
219 inode->i_sb->s_op->destroy_inode(inode); 235 ops->destroy_inode(inode);
220 else 236 if (!ops->free_inode)
221 kmem_cache_free(inode_cachep, inode); 237 return NULL;
238 }
239 inode->free_inode = ops->free_inode;
240 i_callback(&inode->i_rcu);
222 return NULL; 241 return NULL;
223 } 242 }
224 243
225 return inode; 244 return inode;
226} 245}
227 246
228void free_inode_nonrcu(struct inode *inode)
229{
230 kmem_cache_free(inode_cachep, inode);
231}
232EXPORT_SYMBOL(free_inode_nonrcu);
233
234void __destroy_inode(struct inode *inode) 247void __destroy_inode(struct inode *inode)
235{ 248{
236 BUG_ON(inode_has_buffers(inode)); 249 BUG_ON(inode_has_buffers(inode));
@@ -253,20 +266,19 @@ void __destroy_inode(struct inode *inode)
253} 266}
254EXPORT_SYMBOL(__destroy_inode); 267EXPORT_SYMBOL(__destroy_inode);
255 268
256static void i_callback(struct rcu_head *head)
257{
258 struct inode *inode = container_of(head, struct inode, i_rcu);
259 kmem_cache_free(inode_cachep, inode);
260}
261
262static void destroy_inode(struct inode *inode) 269static void destroy_inode(struct inode *inode)
263{ 270{
271 const struct super_operations *ops = inode->i_sb->s_op;
272
264 BUG_ON(!list_empty(&inode->i_lru)); 273 BUG_ON(!list_empty(&inode->i_lru));
265 __destroy_inode(inode); 274 __destroy_inode(inode);
266 if (inode->i_sb->s_op->destroy_inode) 275 if (ops->destroy_inode) {
267 inode->i_sb->s_op->destroy_inode(inode); 276 ops->destroy_inode(inode);
268 else 277 if (!ops->free_inode)
269 call_rcu(&inode->i_rcu, i_callback); 278 return;
279 }
280 inode->free_inode = ops->free_inode;
281 call_rcu(&inode->i_rcu, i_callback);
270} 282}
271 283
272/** 284/**