Skip to content

Commit

Permalink
Merge tag 'driver-core-6.13-rc7' of git://git.kernel.org/pub/scm/linu…
Browse files Browse the repository at this point in the history
…x/kernel/git/gregkh/driver-core

Pull driver core and debugfs fixes from Greg KH:
 "Here are some small driver core and debugfs fixes that resolve some
  reported problems:

   - debugfs runtime error reporting fixes

   - topology cpumask race-condition fix

   - MAINTAINERS file email update

  All of these have been in linux-next this week with no reported
  issues"

* tag 'driver-core-6.13-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core:
  fs: debugfs: fix open proxy for unsafe files
  MAINTAINERS: align Danilo's maintainer entries
  topology: Keep the cpumask unchanged when printing cpumap
  debugfs: fix missing mutex_destroy() in short_fops case
  fs: debugfs: differentiate short fops with proxy ops
  • Loading branch information
Linus Torvalds committed Jan 12, 2025
2 parents 91fff6f + 67510d7 commit 083f9fa
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 40 deletions.
24 changes: 20 additions & 4 deletions drivers/base/topology.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,35 @@ static ssize_t name##_read(struct file *file, struct kobject *kobj, \
loff_t off, size_t count) \
{ \
struct device *dev = kobj_to_dev(kobj); \
cpumask_var_t mask; \
ssize_t n; \
\
return cpumap_print_bitmask_to_buf(buf, topology_##mask(dev->id), \
off, count); \
if (!alloc_cpumask_var(&mask, GFP_KERNEL)) \
return -ENOMEM; \
\
cpumask_copy(mask, topology_##mask(dev->id)); \
n = cpumap_print_bitmask_to_buf(buf, mask, off, count); \
free_cpumask_var(mask); \
\
return n; \
} \
\
static ssize_t name##_list_read(struct file *file, struct kobject *kobj, \
const struct bin_attribute *attr, char *buf, \
loff_t off, size_t count) \
{ \
struct device *dev = kobj_to_dev(kobj); \
cpumask_var_t mask; \
ssize_t n; \
\
if (!alloc_cpumask_var(&mask, GFP_KERNEL)) \
return -ENOMEM; \
\
cpumask_copy(mask, topology_##mask(dev->id)); \
n = cpumap_print_list_to_buf(buf, mask, off, count); \
free_cpumask_var(mask); \
\
return cpumap_print_list_to_buf(buf, topology_##mask(dev->id), \
off, count); \
return n; \
}

define_id_show_func(physical_package_id, "%d");
Expand Down
74 changes: 51 additions & 23 deletions fs/debugfs/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,22 +64,13 @@ const struct file_operations *debugfs_real_fops(const struct file *filp)
}
EXPORT_SYMBOL_GPL(debugfs_real_fops);

/**
* debugfs_file_get - mark the beginning of file data access
* @dentry: the dentry object whose data is being accessed.
*
* Up to a matching call to debugfs_file_put(), any successive call
* into the file removing functions debugfs_remove() and
* debugfs_remove_recursive() will block. Since associated private
* file data may only get freed after a successful return of any of
* the removal functions, you may safely access it after a successful
* call to debugfs_file_get() without worrying about lifetime issues.
*
* If -%EIO is returned, the file has already been removed and thus,
* it is not safe to access any of its data. If, on the other hand,
* it is allowed to access the file data, zero is returned.
*/
int debugfs_file_get(struct dentry *dentry)
enum dbgfs_get_mode {
DBGFS_GET_ALREADY,
DBGFS_GET_REGULAR,
DBGFS_GET_SHORT,
};

static int __debugfs_file_get(struct dentry *dentry, enum dbgfs_get_mode mode)
{
struct debugfs_fsdata *fsd;
void *d_fsd;
Expand All @@ -96,15 +87,17 @@ int debugfs_file_get(struct dentry *dentry)
if (!((unsigned long)d_fsd & DEBUGFS_FSDATA_IS_REAL_FOPS_BIT)) {
fsd = d_fsd;
} else {
if (WARN_ON(mode == DBGFS_GET_ALREADY))
return -EINVAL;

fsd = kmalloc(sizeof(*fsd), GFP_KERNEL);
if (!fsd)
return -ENOMEM;

if ((unsigned long)d_fsd & DEBUGFS_FSDATA_IS_SHORT_FOPS_BIT) {
if (mode == DBGFS_GET_SHORT) {
fsd->real_fops = NULL;
fsd->short_fops = (void *)((unsigned long)d_fsd &
~(DEBUGFS_FSDATA_IS_REAL_FOPS_BIT |
DEBUGFS_FSDATA_IS_SHORT_FOPS_BIT));
~DEBUGFS_FSDATA_IS_REAL_FOPS_BIT);
} else {
fsd->real_fops = (void *)((unsigned long)d_fsd &
~DEBUGFS_FSDATA_IS_REAL_FOPS_BIT);
Expand Down Expand Up @@ -138,6 +131,26 @@ int debugfs_file_get(struct dentry *dentry)

return 0;
}

/**
* debugfs_file_get - mark the beginning of file data access
* @dentry: the dentry object whose data is being accessed.
*
* Up to a matching call to debugfs_file_put(), any successive call
* into the file removing functions debugfs_remove() and
* debugfs_remove_recursive() will block. Since associated private
* file data may only get freed after a successful return of any of
* the removal functions, you may safely access it after a successful
* call to debugfs_file_get() without worrying about lifetime issues.
*
* If -%EIO is returned, the file has already been removed and thus,
* it is not safe to access any of its data. If, on the other hand,
* it is allowed to access the file data, zero is returned.
*/
int debugfs_file_get(struct dentry *dentry)
{
return __debugfs_file_get(dentry, DBGFS_GET_ALREADY);
}
EXPORT_SYMBOL_GPL(debugfs_file_get);

/**
Expand Down Expand Up @@ -267,7 +280,7 @@ static int open_proxy_open(struct inode *inode, struct file *filp)
const struct file_operations *real_fops = NULL;
int r;

r = debugfs_file_get(dentry);
r = __debugfs_file_get(dentry, DBGFS_GET_REGULAR);
if (r)
return r == -EIO ? -ENOENT : r;

Expand Down Expand Up @@ -424,15 +437,16 @@ static void __full_proxy_fops_init(struct file_operations *proxy_fops,
proxy_fops->unlocked_ioctl = full_proxy_unlocked_ioctl;
}

static int full_proxy_open(struct inode *inode, struct file *filp)
static int full_proxy_open(struct inode *inode, struct file *filp,
enum dbgfs_get_mode mode)
{
struct dentry *dentry = F_DENTRY(filp);
const struct file_operations *real_fops;
struct file_operations *proxy_fops = NULL;
struct debugfs_fsdata *fsd;
int r;

r = debugfs_file_get(dentry);
r = __debugfs_file_get(dentry, mode);
if (r)
return r == -EIO ? -ENOENT : r;

Expand Down Expand Up @@ -491,8 +505,22 @@ static int full_proxy_open(struct inode *inode, struct file *filp)
return r;
}

static int full_proxy_open_regular(struct inode *inode, struct file *filp)
{
return full_proxy_open(inode, filp, DBGFS_GET_REGULAR);
}

const struct file_operations debugfs_full_proxy_file_operations = {
.open = full_proxy_open,
.open = full_proxy_open_regular,
};

static int full_proxy_open_short(struct inode *inode, struct file *filp)
{
return full_proxy_open(inode, filp, DBGFS_GET_SHORT);
}

const struct file_operations debugfs_full_short_proxy_file_operations = {
.open = full_proxy_open_short,
};

ssize_t debugfs_attr_read(struct file *file, char __user *buf,
Expand Down
13 changes: 5 additions & 8 deletions fs/debugfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ static void debugfs_release_dentry(struct dentry *dentry)
return;

/* check it wasn't a dir (no fsdata) or automount (no real_fops) */
if (fsd && fsd->real_fops) {
if (fsd && (fsd->real_fops || fsd->short_fops)) {
WARN_ON(!list_empty(&fsd->cancellations));
mutex_destroy(&fsd->cancellations_mtx);
}
Expand Down Expand Up @@ -455,8 +455,7 @@ struct dentry *debugfs_create_file_full(const char *name, umode_t mode,
const struct file_operations *fops)
{
if (WARN_ON((unsigned long)fops &
(DEBUGFS_FSDATA_IS_SHORT_FOPS_BIT |
DEBUGFS_FSDATA_IS_REAL_FOPS_BIT)))
DEBUGFS_FSDATA_IS_REAL_FOPS_BIT))
return ERR_PTR(-EINVAL);

return __debugfs_create_file(name, mode, parent, data,
Expand All @@ -471,15 +470,13 @@ struct dentry *debugfs_create_file_short(const char *name, umode_t mode,
const struct debugfs_short_fops *fops)
{
if (WARN_ON((unsigned long)fops &
(DEBUGFS_FSDATA_IS_SHORT_FOPS_BIT |
DEBUGFS_FSDATA_IS_REAL_FOPS_BIT)))
DEBUGFS_FSDATA_IS_REAL_FOPS_BIT))
return ERR_PTR(-EINVAL);

return __debugfs_create_file(name, mode, parent, data,
fops ? &debugfs_full_proxy_file_operations :
fops ? &debugfs_full_short_proxy_file_operations :
&debugfs_noop_file_operations,
(const void *)((unsigned long)fops |
DEBUGFS_FSDATA_IS_SHORT_FOPS_BIT));
fops);
}
EXPORT_SYMBOL_GPL(debugfs_create_file_short);

Expand Down
6 changes: 1 addition & 5 deletions fs/debugfs/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ struct file_operations;
extern const struct file_operations debugfs_noop_file_operations;
extern const struct file_operations debugfs_open_proxy_file_operations;
extern const struct file_operations debugfs_full_proxy_file_operations;
extern const struct file_operations debugfs_full_short_proxy_file_operations;

struct debugfs_fsdata {
const struct file_operations *real_fops;
Expand All @@ -40,11 +41,6 @@ struct debugfs_fsdata {
* pointer gets its lowest bit set.
*/
#define DEBUGFS_FSDATA_IS_REAL_FOPS_BIT BIT(0)
/*
* A dentry's ->d_fsdata, when pointing to real fops, is with
* short fops instead of full fops.
*/
#define DEBUGFS_FSDATA_IS_SHORT_FOPS_BIT BIT(1)

/* Access BITS */
#define DEBUGFS_ALLOW_API BIT(0)
Expand Down

0 comments on commit 083f9fa

Please sign in to comment.