Skip to content

Commit 41a0ecc

Browse files
Al Virogregkh
authored andcommitted
debugfs: get rid of dynamically allocation proxy_ops
All it takes is having full_proxy_open() collect the information about available methods and store it in debugfs_fsdata. Wrappers are called only after full_proxy_open() has succeeded calling debugfs_get_file(), so they are guaranteed to have ->d_fsdata already pointing to debugfs_fsdata. As the result, they can check if method is absent and bugger off early, without any atomic operations, etc. - same effect as what we'd have from NULL method. Which makes the entire proxy_fops contents unconditional, making it completely pointless - we can just put those methods (unconditionally) into debugfs_full_proxy_file_operations and forget about dynamic allocation, replace_fops, etc. Signed-off-by: Al Viro <[email protected]> Reviewed-by: Christian Brauner <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent bacaaf8 commit 41a0ecc

File tree

2 files changed

+61
-61
lines changed

2 files changed

+61
-61
lines changed

fs/debugfs/file.c

Lines changed: 52 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -95,13 +95,31 @@ static int __debugfs_file_get(struct dentry *dentry, enum dbgfs_get_mode mode)
9595
return -ENOMEM;
9696

9797
if (mode == DBGFS_GET_SHORT) {
98-
fsd->real_fops = NULL;
99-
fsd->short_fops = (void *)((unsigned long)d_fsd &
100-
~DEBUGFS_FSDATA_IS_REAL_FOPS_BIT);
98+
const struct debugfs_short_fops *ops;
99+
ops = (void *)((unsigned long)d_fsd &
100+
~DEBUGFS_FSDATA_IS_REAL_FOPS_BIT);
101+
fsd->short_fops = ops;
102+
if (ops->llseek)
103+
fsd->methods |= HAS_LSEEK;
104+
if (ops->read)
105+
fsd->methods |= HAS_READ;
106+
if (ops->write)
107+
fsd->methods |= HAS_WRITE;
101108
} else {
102-
fsd->real_fops = (void *)((unsigned long)d_fsd &
103-
~DEBUGFS_FSDATA_IS_REAL_FOPS_BIT);
104-
fsd->short_fops = NULL;
109+
const struct file_operations *ops;
110+
ops = (void *)((unsigned long)d_fsd &
111+
~DEBUGFS_FSDATA_IS_REAL_FOPS_BIT);
112+
fsd->real_fops = ops;
113+
if (ops->llseek)
114+
fsd->methods |= HAS_LSEEK;
115+
if (ops->read)
116+
fsd->methods |= HAS_READ;
117+
if (ops->write)
118+
fsd->methods |= HAS_WRITE;
119+
if (ops->unlocked_ioctl)
120+
fsd->methods |= HAS_IOCTL;
121+
if (ops->poll)
122+
fsd->methods |= HAS_POLL;
105123
}
106124
refcount_set(&fsd->active_users, 1);
107125
init_completion(&fsd->active_users_drained);
@@ -322,13 +340,16 @@ const struct file_operations debugfs_open_proxy_file_operations = {
322340
#define PROTO(args...) args
323341
#define ARGS(args...) args
324342

325-
#define FULL_PROXY_FUNC(name, ret_type, filp, proto, args) \
343+
#define FULL_PROXY_FUNC(name, ret_type, filp, proto, args, bit, ret) \
326344
static ret_type full_proxy_ ## name(proto) \
327345
{ \
328-
struct dentry *dentry = F_DENTRY(filp); \
346+
struct dentry *dentry = F_DENTRY(filp); \
347+
struct debugfs_fsdata *fsd = dentry->d_fsdata; \
329348
const struct file_operations *real_fops; \
330349
ret_type r; \
331350
\
351+
if (!(fsd->methods & bit)) \
352+
return ret; \
332353
r = debugfs_file_get(dentry); \
333354
if (unlikely(r)) \
334355
return r; \
@@ -338,17 +359,18 @@ static ret_type full_proxy_ ## name(proto) \
338359
return r; \
339360
}
340361

341-
#define FULL_PROXY_FUNC_BOTH(name, ret_type, filp, proto, args) \
362+
#define FULL_PROXY_FUNC_BOTH(name, ret_type, filp, proto, args, bit, ret) \
342363
static ret_type full_proxy_ ## name(proto) \
343364
{ \
344365
struct dentry *dentry = F_DENTRY(filp); \
345-
struct debugfs_fsdata *fsd; \
366+
struct debugfs_fsdata *fsd = dentry->d_fsdata; \
346367
ret_type r; \
347368
\
369+
if (!(fsd->methods & bit)) \
370+
return ret; \
348371
r = debugfs_file_get(dentry); \
349372
if (unlikely(r)) \
350373
return r; \
351-
fsd = dentry->d_fsdata; \
352374
if (fsd->real_fops) \
353375
r = fsd->real_fops->name(args); \
354376
else \
@@ -359,29 +381,32 @@ static ret_type full_proxy_ ## name(proto) \
359381

360382
FULL_PROXY_FUNC_BOTH(llseek, loff_t, filp,
361383
PROTO(struct file *filp, loff_t offset, int whence),
362-
ARGS(filp, offset, whence));
384+
ARGS(filp, offset, whence), HAS_LSEEK, -ESPIPE);
363385

364386
FULL_PROXY_FUNC_BOTH(read, ssize_t, filp,
365387
PROTO(struct file *filp, char __user *buf, size_t size,
366388
loff_t *ppos),
367-
ARGS(filp, buf, size, ppos));
389+
ARGS(filp, buf, size, ppos), HAS_READ, -EINVAL);
368390

369391
FULL_PROXY_FUNC_BOTH(write, ssize_t, filp,
370392
PROTO(struct file *filp, const char __user *buf,
371393
size_t size, loff_t *ppos),
372-
ARGS(filp, buf, size, ppos));
394+
ARGS(filp, buf, size, ppos), HAS_WRITE, -EINVAL);
373395

374396
FULL_PROXY_FUNC(unlocked_ioctl, long, filp,
375397
PROTO(struct file *filp, unsigned int cmd, unsigned long arg),
376-
ARGS(filp, cmd, arg));
398+
ARGS(filp, cmd, arg), HAS_IOCTL, -ENOTTY);
377399

378400
static __poll_t full_proxy_poll(struct file *filp,
379401
struct poll_table_struct *wait)
380402
{
381403
struct dentry *dentry = F_DENTRY(filp);
404+
struct debugfs_fsdata *fsd = dentry->d_fsdata;
382405
__poll_t r = 0;
383406
const struct file_operations *real_fops;
384407

408+
if (!(fsd->methods & HAS_POLL))
409+
return DEFAULT_POLLMASK;
385410
if (debugfs_file_get(dentry))
386411
return EPOLLHUP;
387412

@@ -393,9 +418,7 @@ static __poll_t full_proxy_poll(struct file *filp,
393418

394419
static int full_proxy_release(struct inode *inode, struct file *filp)
395420
{
396-
const struct dentry *dentry = F_DENTRY(filp);
397421
const struct file_operations *real_fops = debugfs_real_fops(filp);
398-
const struct file_operations *proxy_fops = filp->f_op;
399422
int r = 0;
400423

401424
/*
@@ -407,42 +430,15 @@ static int full_proxy_release(struct inode *inode, struct file *filp)
407430
if (real_fops && real_fops->release)
408431
r = real_fops->release(inode, filp);
409432

410-
replace_fops(filp, d_inode(dentry)->i_fop);
411-
kfree(proxy_fops);
412433
fops_put(real_fops);
413434
return r;
414435
}
415436

416-
static void __full_proxy_fops_init(struct file_operations *proxy_fops,
417-
struct debugfs_fsdata *fsd)
418-
{
419-
proxy_fops->release = full_proxy_release;
420-
421-
if ((fsd->real_fops && fsd->real_fops->llseek) ||
422-
(fsd->short_fops && fsd->short_fops->llseek))
423-
proxy_fops->llseek = full_proxy_llseek;
424-
425-
if ((fsd->real_fops && fsd->real_fops->read) ||
426-
(fsd->short_fops && fsd->short_fops->read))
427-
proxy_fops->read = full_proxy_read;
428-
429-
if ((fsd->real_fops && fsd->real_fops->write) ||
430-
(fsd->short_fops && fsd->short_fops->write))
431-
proxy_fops->write = full_proxy_write;
432-
433-
if (fsd->real_fops && fsd->real_fops->poll)
434-
proxy_fops->poll = full_proxy_poll;
435-
436-
if (fsd->real_fops && fsd->real_fops->unlocked_ioctl)
437-
proxy_fops->unlocked_ioctl = full_proxy_unlocked_ioctl;
438-
}
439-
440437
static int full_proxy_open(struct inode *inode, struct file *filp,
441438
enum dbgfs_get_mode mode)
442439
{
443440
struct dentry *dentry = F_DENTRY(filp);
444441
const struct file_operations *real_fops;
445-
struct file_operations *proxy_fops = NULL;
446442
struct debugfs_fsdata *fsd;
447443
int r;
448444

@@ -472,34 +468,20 @@ static int full_proxy_open(struct inode *inode, struct file *filp,
472468
goto out;
473469
}
474470

475-
proxy_fops = kzalloc(sizeof(*proxy_fops), GFP_KERNEL);
476-
if (!proxy_fops) {
477-
r = -ENOMEM;
478-
goto free_proxy;
479-
}
480-
__full_proxy_fops_init(proxy_fops, fsd);
481-
replace_fops(filp, proxy_fops);
482-
483471
if (!real_fops || real_fops->open) {
484472
if (real_fops)
485473
r = real_fops->open(inode, filp);
486474
else
487475
r = simple_open(inode, filp);
488476
if (r) {
489-
replace_fops(filp, d_inode(dentry)->i_fop);
490-
goto free_proxy;
491-
} else if (filp->f_op != proxy_fops) {
477+
fops_put(real_fops);
478+
} else if (filp->f_op != &debugfs_full_proxy_file_operations) {
492479
/* No protection against file removal anymore. */
493480
WARN(1, "debugfs file owner replaced proxy fops: %pd",
494481
dentry);
495-
goto free_proxy;
482+
fops_put(real_fops);
496483
}
497484
}
498-
499-
goto out;
500-
free_proxy:
501-
kfree(proxy_fops);
502-
fops_put(real_fops);
503485
out:
504486
debugfs_file_put(dentry);
505487
return r;
@@ -512,6 +494,12 @@ static int full_proxy_open_regular(struct inode *inode, struct file *filp)
512494

513495
const struct file_operations debugfs_full_proxy_file_operations = {
514496
.open = full_proxy_open_regular,
497+
.release = full_proxy_release,
498+
.llseek = full_proxy_llseek,
499+
.read = full_proxy_read,
500+
.write = full_proxy_write,
501+
.poll = full_proxy_poll,
502+
.unlocked_ioctl = full_proxy_unlocked_ioctl
515503
};
516504

517505
static int full_proxy_open_short(struct inode *inode, struct file *filp)
@@ -521,6 +509,9 @@ static int full_proxy_open_short(struct inode *inode, struct file *filp)
521509

522510
const struct file_operations debugfs_full_short_proxy_file_operations = {
523511
.open = full_proxy_open_short,
512+
.llseek = full_proxy_llseek,
513+
.read = full_proxy_read,
514+
.write = full_proxy_write,
524515
};
525516

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

fs/debugfs/internal.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,18 @@ struct debugfs_fsdata {
3939
/* protect cancellations */
4040
struct mutex cancellations_mtx;
4141
struct list_head cancellations;
42+
unsigned int methods;
4243
};
4344
};
4445

46+
enum {
47+
HAS_READ = 1,
48+
HAS_WRITE = 2,
49+
HAS_LSEEK = 4,
50+
HAS_POLL = 8,
51+
HAS_IOCTL = 16
52+
};
53+
4554
/*
4655
* A dentry's ->d_fsdata either points to the real fops or to a
4756
* dynamically allocated debugfs_fsdata instance.

0 commit comments

Comments
 (0)