Skip to content

Commit f8f2589

Browse files
jmberg-intelgregkh
authored andcommitted
fs: debugfs: differentiate short fops with proxy ops
Geert reported that my previous short fops debugfs changes broke m68k, because it only has mandatory alignement of two, so we can't stash the "is it short" information into the pointer (as we already did with the "is it real" bit.) Instead, exploit the fact that debugfs_file_get() called on an already open file will already find that the fsdata is no longer the real fops but rather the allocated data that already distinguishes full/short ops, so only open() needs to be able to distinguish. We can achieve that by using two different open functions. Unfortunately this requires another set of full file ops, increasing the size by 536 bytes (x86-64), but that's still a reasonable trade-off given that only converting some of the wireless stack gained over 28k. This brings the total cost of this to around 1k, for wins of 28k (all x86-64). Reported-and-tested-by: Geert Uytterhoeven <geert@linux-m68k.org> Link: https://lore.kernel.org/CAMuHMdWu_9-L2Te101w8hU7H_2yobJFPXSwwUmGHSJfaPWDKiQ@mail.gmail.com Fixes: 8dc6d81 ("debugfs: add small file operations for most files") Signed-off-by: Johannes Berg <johannes.berg@intel.com> Tested-by: Geert Uytterhoeven <geert@linux-m68k.org> Link: https://lore.kernel.org/r/20241129121536.30989-2-johannes@sipsolutions.net Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 78d4f34 commit f8f2589

File tree

3 files changed

+55
-34
lines changed

3 files changed

+55
-34
lines changed

fs/debugfs/file.c

Lines changed: 50 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -64,22 +64,13 @@ const struct file_operations *debugfs_real_fops(const struct file *filp)
6464
}
6565
EXPORT_SYMBOL_GPL(debugfs_real_fops);
6666

67-
/**
68-
* debugfs_file_get - mark the beginning of file data access
69-
* @dentry: the dentry object whose data is being accessed.
70-
*
71-
* Up to a matching call to debugfs_file_put(), any successive call
72-
* into the file removing functions debugfs_remove() and
73-
* debugfs_remove_recursive() will block. Since associated private
74-
* file data may only get freed after a successful return of any of
75-
* the removal functions, you may safely access it after a successful
76-
* call to debugfs_file_get() without worrying about lifetime issues.
77-
*
78-
* If -%EIO is returned, the file has already been removed and thus,
79-
* it is not safe to access any of its data. If, on the other hand,
80-
* it is allowed to access the file data, zero is returned.
81-
*/
82-
int debugfs_file_get(struct dentry *dentry)
67+
enum dbgfs_get_mode {
68+
DBGFS_GET_ALREADY,
69+
DBGFS_GET_REGULAR,
70+
DBGFS_GET_SHORT,
71+
};
72+
73+
static int __debugfs_file_get(struct dentry *dentry, enum dbgfs_get_mode mode)
8374
{
8475
struct debugfs_fsdata *fsd;
8576
void *d_fsd;
@@ -96,15 +87,17 @@ int debugfs_file_get(struct dentry *dentry)
9687
if (!((unsigned long)d_fsd & DEBUGFS_FSDATA_IS_REAL_FOPS_BIT)) {
9788
fsd = d_fsd;
9889
} else {
90+
if (WARN_ON(mode == DBGFS_GET_ALREADY))
91+
return -EINVAL;
92+
9993
fsd = kmalloc(sizeof(*fsd), GFP_KERNEL);
10094
if (!fsd)
10195
return -ENOMEM;
10296

103-
if ((unsigned long)d_fsd & DEBUGFS_FSDATA_IS_SHORT_FOPS_BIT) {
97+
if (mode == DBGFS_GET_SHORT) {
10498
fsd->real_fops = NULL;
10599
fsd->short_fops = (void *)((unsigned long)d_fsd &
106-
~(DEBUGFS_FSDATA_IS_REAL_FOPS_BIT |
107-
DEBUGFS_FSDATA_IS_SHORT_FOPS_BIT));
100+
~DEBUGFS_FSDATA_IS_REAL_FOPS_BIT);
108101
} else {
109102
fsd->real_fops = (void *)((unsigned long)d_fsd &
110103
~DEBUGFS_FSDATA_IS_REAL_FOPS_BIT);
@@ -138,6 +131,26 @@ int debugfs_file_get(struct dentry *dentry)
138131

139132
return 0;
140133
}
134+
135+
/**
136+
* debugfs_file_get - mark the beginning of file data access
137+
* @dentry: the dentry object whose data is being accessed.
138+
*
139+
* Up to a matching call to debugfs_file_put(), any successive call
140+
* into the file removing functions debugfs_remove() and
141+
* debugfs_remove_recursive() will block. Since associated private
142+
* file data may only get freed after a successful return of any of
143+
* the removal functions, you may safely access it after a successful
144+
* call to debugfs_file_get() without worrying about lifetime issues.
145+
*
146+
* If -%EIO is returned, the file has already been removed and thus,
147+
* it is not safe to access any of its data. If, on the other hand,
148+
* it is allowed to access the file data, zero is returned.
149+
*/
150+
int debugfs_file_get(struct dentry *dentry)
151+
{
152+
return __debugfs_file_get(dentry, DBGFS_GET_ALREADY);
153+
}
141154
EXPORT_SYMBOL_GPL(debugfs_file_get);
142155

143156
/**
@@ -424,15 +437,16 @@ static void __full_proxy_fops_init(struct file_operations *proxy_fops,
424437
proxy_fops->unlocked_ioctl = full_proxy_unlocked_ioctl;
425438
}
426439

427-
static int full_proxy_open(struct inode *inode, struct file *filp)
440+
static int full_proxy_open(struct inode *inode, struct file *filp,
441+
enum dbgfs_get_mode mode)
428442
{
429443
struct dentry *dentry = F_DENTRY(filp);
430444
const struct file_operations *real_fops;
431445
struct file_operations *proxy_fops = NULL;
432446
struct debugfs_fsdata *fsd;
433447
int r;
434448

435-
r = debugfs_file_get(dentry);
449+
r = __debugfs_file_get(dentry, mode);
436450
if (r)
437451
return r == -EIO ? -ENOENT : r;
438452

@@ -491,8 +505,22 @@ static int full_proxy_open(struct inode *inode, struct file *filp)
491505
return r;
492506
}
493507

508+
static int full_proxy_open_regular(struct inode *inode, struct file *filp)
509+
{
510+
return full_proxy_open(inode, filp, DBGFS_GET_REGULAR);
511+
}
512+
494513
const struct file_operations debugfs_full_proxy_file_operations = {
495-
.open = full_proxy_open,
514+
.open = full_proxy_open_regular,
515+
};
516+
517+
static int full_proxy_open_short(struct inode *inode, struct file *filp)
518+
{
519+
return full_proxy_open(inode, filp, DBGFS_GET_SHORT);
520+
}
521+
522+
const struct file_operations debugfs_full_short_proxy_file_operations = {
523+
.open = full_proxy_open_short,
496524
};
497525

498526
ssize_t debugfs_attr_read(struct file *file, char __user *buf,

fs/debugfs/inode.c

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -455,8 +455,7 @@ struct dentry *debugfs_create_file_full(const char *name, umode_t mode,
455455
const struct file_operations *fops)
456456
{
457457
if (WARN_ON((unsigned long)fops &
458-
(DEBUGFS_FSDATA_IS_SHORT_FOPS_BIT |
459-
DEBUGFS_FSDATA_IS_REAL_FOPS_BIT)))
458+
DEBUGFS_FSDATA_IS_REAL_FOPS_BIT))
460459
return ERR_PTR(-EINVAL);
461460

462461
return __debugfs_create_file(name, mode, parent, data,
@@ -471,15 +470,13 @@ struct dentry *debugfs_create_file_short(const char *name, umode_t mode,
471470
const struct debugfs_short_fops *fops)
472471
{
473472
if (WARN_ON((unsigned long)fops &
474-
(DEBUGFS_FSDATA_IS_SHORT_FOPS_BIT |
475-
DEBUGFS_FSDATA_IS_REAL_FOPS_BIT)))
473+
DEBUGFS_FSDATA_IS_REAL_FOPS_BIT))
476474
return ERR_PTR(-EINVAL);
477475

478476
return __debugfs_create_file(name, mode, parent, data,
479-
fops ? &debugfs_full_proxy_file_operations :
477+
fops ? &debugfs_full_short_proxy_file_operations :
480478
&debugfs_noop_file_operations,
481-
(const void *)((unsigned long)fops |
482-
DEBUGFS_FSDATA_IS_SHORT_FOPS_BIT));
479+
fops);
483480
}
484481
EXPORT_SYMBOL_GPL(debugfs_create_file_short);
485482

fs/debugfs/internal.h

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ struct file_operations;
1515
extern const struct file_operations debugfs_noop_file_operations;
1616
extern const struct file_operations debugfs_open_proxy_file_operations;
1717
extern const struct file_operations debugfs_full_proxy_file_operations;
18+
extern const struct file_operations debugfs_full_short_proxy_file_operations;
1819

1920
struct debugfs_fsdata {
2021
const struct file_operations *real_fops;
@@ -40,11 +41,6 @@ struct debugfs_fsdata {
4041
* pointer gets its lowest bit set.
4142
*/
4243
#define DEBUGFS_FSDATA_IS_REAL_FOPS_BIT BIT(0)
43-
/*
44-
* A dentry's ->d_fsdata, when pointing to real fops, is with
45-
* short fops instead of full fops.
46-
*/
47-
#define DEBUGFS_FSDATA_IS_SHORT_FOPS_BIT BIT(1)
4844

4945
/* Access BITS */
5046
#define DEBUGFS_ALLOW_API BIT(0)

0 commit comments

Comments
 (0)