Skip to content

Commit 7c8d469

Browse files
nicstangegregkh
authored andcommitted
debugfs: add support for more elaborate ->d_fsdata
Currently, the user provided fops, "real_fops", are stored directly into ->d_fsdata. In order to be able to store more per-file state and thus prepare for more granular file removal protection, wrap the real_fops into a dynamically allocated container struct, debugfs_fsdata. A struct debugfs_fsdata gets allocated at file creation and freed from the newly intoduced ->d_release(). Finally, move the implementation of debugfs_real_fops() out of the public debugfs header such that struct debugfs_fsdata's declaration can be kept private. Signed-off-by: Nicolai Stange <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 2ec1615 commit 7c8d469

File tree

4 files changed

+38
-20
lines changed

4 files changed

+38
-20
lines changed

fs/debugfs/file.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,18 @@ EXPORT_SYMBOL_GPL(debugfs_use_file_finish);
9797

9898
#define F_DENTRY(filp) ((filp)->f_path.dentry)
9999

100+
const struct file_operations *debugfs_real_fops(const struct file *filp)
101+
__must_hold(&debugfs_srcu)
102+
{
103+
struct debugfs_fsdata *fsd = F_DENTRY(filp)->d_fsdata;
104+
/*
105+
* Neither the pointer to the struct file_operations, nor its
106+
* contents ever change -- srcu_dereference() is not needed here.
107+
*/
108+
return fsd->real_fops;
109+
}
110+
EXPORT_SYMBOL_GPL(debugfs_real_fops);
111+
100112
static int open_proxy_open(struct inode *inode, struct file *filp)
101113
{
102114
const struct dentry *dentry = F_DENTRY(filp);

fs/debugfs/inode.c

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,11 @@ static const struct super_operations debugfs_super_operations = {
185185
.evict_inode = debugfs_evict_inode,
186186
};
187187

188+
static void debugfs_release_dentry(struct dentry *dentry)
189+
{
190+
kfree(dentry->d_fsdata);
191+
}
192+
188193
static struct vfsmount *debugfs_automount(struct path *path)
189194
{
190195
debugfs_automount_t f;
@@ -194,6 +199,7 @@ static struct vfsmount *debugfs_automount(struct path *path)
194199

195200
static const struct dentry_operations debugfs_dops = {
196201
.d_delete = always_delete_dentry,
202+
.d_release = debugfs_release_dentry,
197203
.d_automount = debugfs_automount,
198204
};
199205

@@ -341,24 +347,34 @@ static struct dentry *__debugfs_create_file(const char *name, umode_t mode,
341347
{
342348
struct dentry *dentry;
343349
struct inode *inode;
350+
struct debugfs_fsdata *fsd;
351+
352+
fsd = kmalloc(sizeof(*fsd), GFP_KERNEL);
353+
if (!fsd)
354+
return NULL;
344355

345356
if (!(mode & S_IFMT))
346357
mode |= S_IFREG;
347358
BUG_ON(!S_ISREG(mode));
348359
dentry = start_creating(name, parent);
349360

350-
if (IS_ERR(dentry))
361+
if (IS_ERR(dentry)) {
362+
kfree(fsd);
351363
return NULL;
364+
}
352365

353366
inode = debugfs_get_inode(dentry->d_sb);
354-
if (unlikely(!inode))
367+
if (unlikely(!inode)) {
368+
kfree(fsd);
355369
return failed_creating(dentry);
370+
}
356371

357372
inode->i_mode = mode;
358373
inode->i_private = data;
359374

360375
inode->i_fop = proxy_fops;
361-
dentry->d_fsdata = (void *)real_fops;
376+
fsd->real_fops = real_fops;
377+
dentry->d_fsdata = fsd;
362378

363379
d_instantiate(dentry, inode);
364380
fsnotify_create(d_inode(dentry->d_parent), dentry);

fs/debugfs/internal.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,8 @@ extern const struct file_operations debugfs_noop_file_operations;
1919
extern const struct file_operations debugfs_open_proxy_file_operations;
2020
extern const struct file_operations debugfs_full_proxy_file_operations;
2121

22+
struct debugfs_fsdata {
23+
const struct file_operations *real_fops;
24+
};
25+
2226
#endif /* _DEBUGFS_INTERNAL_H_ */

include/linux/debugfs.h

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -45,23 +45,6 @@ extern struct dentry *arch_debugfs_dir;
4545

4646
extern struct srcu_struct debugfs_srcu;
4747

48-
/**
49-
* debugfs_real_fops - getter for the real file operation
50-
* @filp: a pointer to a struct file
51-
*
52-
* Must only be called under the protection established by
53-
* debugfs_use_file_start().
54-
*/
55-
static inline const struct file_operations *debugfs_real_fops(const struct file *filp)
56-
__must_hold(&debugfs_srcu)
57-
{
58-
/*
59-
* Neither the pointer to the struct file_operations, nor its
60-
* contents ever change -- srcu_dereference() is not needed here.
61-
*/
62-
return filp->f_path.dentry->d_fsdata;
63-
}
64-
6548
#define DEFINE_DEBUGFS_ATTRIBUTE(__fops, __get, __set, __fmt) \
6649
static int __fops ## _open(struct inode *inode, struct file *file) \
6750
{ \
@@ -112,6 +95,9 @@ int debugfs_use_file_start(const struct dentry *dentry, int *srcu_idx)
11295

11396
void debugfs_use_file_finish(int srcu_idx) __releases(&debugfs_srcu);
11497

98+
const struct file_operations *debugfs_real_fops(const struct file *filp)
99+
__must_hold(&debugfs_srcu);
100+
115101
ssize_t debugfs_attr_read(struct file *file, char __user *buf,
116102
size_t len, loff_t *ppos);
117103
ssize_t debugfs_attr_write(struct file *file, const char __user *buf,

0 commit comments

Comments
 (0)