aboutsummaryrefslogtreecommitdiffstats
path: root/fs/debugfs/inode.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/debugfs/inode.c')
-rw-r--r--fs/debugfs/inode.c36
1 files changed, 19 insertions, 17 deletions
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c
index f587aded46b5..9dca4da059b3 100644
--- a/fs/debugfs/inode.c
+++ b/fs/debugfs/inode.c
@@ -184,7 +184,10 @@ static const struct super_operations debugfs_super_operations = {
184 184
185static void debugfs_release_dentry(struct dentry *dentry) 185static void debugfs_release_dentry(struct dentry *dentry)
186{ 186{
187 kfree(dentry->d_fsdata); 187 void *fsd = dentry->d_fsdata;
188
189 if (!((unsigned long)fsd & DEBUGFS_FSDATA_IS_REAL_FOPS_BIT))
190 kfree(dentry->d_fsdata);
188} 191}
189 192
190static struct vfsmount *debugfs_automount(struct path *path) 193static struct vfsmount *debugfs_automount(struct path *path)
@@ -344,35 +347,25 @@ static struct dentry *__debugfs_create_file(const char *name, umode_t mode,
344{ 347{
345 struct dentry *dentry; 348 struct dentry *dentry;
346 struct inode *inode; 349 struct inode *inode;
347 struct debugfs_fsdata *fsd;
348
349 fsd = kmalloc(sizeof(*fsd), GFP_KERNEL);
350 if (!fsd)
351 return NULL;
352 350
353 if (!(mode & S_IFMT)) 351 if (!(mode & S_IFMT))
354 mode |= S_IFREG; 352 mode |= S_IFREG;
355 BUG_ON(!S_ISREG(mode)); 353 BUG_ON(!S_ISREG(mode));
356 dentry = start_creating(name, parent); 354 dentry = start_creating(name, parent);
357 355
358 if (IS_ERR(dentry)) { 356 if (IS_ERR(dentry))
359 kfree(fsd);
360 return NULL; 357 return NULL;
361 }
362 358
363 inode = debugfs_get_inode(dentry->d_sb); 359 inode = debugfs_get_inode(dentry->d_sb);
364 if (unlikely(!inode)) { 360 if (unlikely(!inode))
365 kfree(fsd);
366 return failed_creating(dentry); 361 return failed_creating(dentry);
367 }
368 362
369 inode->i_mode = mode; 363 inode->i_mode = mode;
370 inode->i_private = data; 364 inode->i_private = data;
371 365
372 inode->i_fop = proxy_fops; 366 inode->i_fop = proxy_fops;
373 fsd->real_fops = real_fops; 367 dentry->d_fsdata = (void *)((unsigned long)real_fops |
374 refcount_set(&fsd->active_users, 1); 368 DEBUGFS_FSDATA_IS_REAL_FOPS_BIT);
375 dentry->d_fsdata = fsd;
376 369
377 d_instantiate(dentry, inode); 370 d_instantiate(dentry, inode);
378 fsnotify_create(d_inode(dentry->d_parent), dentry); 371 fsnotify_create(d_inode(dentry->d_parent), dentry);
@@ -635,8 +628,17 @@ static void __debugfs_remove_file(struct dentry *dentry, struct dentry *parent)
635 628
636 simple_unlink(d_inode(parent), dentry); 629 simple_unlink(d_inode(parent), dentry);
637 d_delete(dentry); 630 d_delete(dentry);
638 fsd = dentry->d_fsdata; 631
639 init_completion(&fsd->active_users_drained); 632 /*
633 * Paired with the closing smp_mb() implied by a successful
634 * cmpxchg() in debugfs_file_get(): either
635 * debugfs_file_get() must see a dead dentry or we must see a
636 * debugfs_fsdata instance at ->d_fsdata here (or both).
637 */
638 smp_mb();
639 fsd = READ_ONCE(dentry->d_fsdata);
640 if ((unsigned long)fsd & DEBUGFS_FSDATA_IS_REAL_FOPS_BIT)
641 return;
640 if (!refcount_dec_and_test(&fsd->active_users)) 642 if (!refcount_dec_and_test(&fsd->active_users))
641 wait_for_completion(&fsd->active_users_drained); 643 wait_for_completion(&fsd->active_users_drained);
642} 644}