mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-01 10:45:49 +00:00
eventfs: Stop using dcache_readdir() for getdents()
The eventfs creates dynamically allocated dentries and inodes. Using the dcache_readdir() logic for its own directory lookups requires hiding the cursor of the dcache logic and playing games to allow the dcache_readdir() to still have access to the cursor while the eventfs saved what it created and what it needs to release. Instead, just have eventfs have its own iterate_shared callback function that will fill in the dent entries. This simplifies the code quite a bit. Link: https://lore.kernel.org/linux-trace-kernel/20240104015435.682218477@goodmis.org Cc: Masami Hiramatsu <mhiramat@kernel.org> Cc: Mark Rutland <mark.rutland@arm.com> Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Ajay Kaher <akaher@vmware.com> Cc: Al Viro <viro@ZenIV.linux.org.uk> Cc: Christian Brauner <brauner@kernel.org> Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
This commit is contained in:
parent
b0f7e2d739
commit
493ec81a8f
@ -52,9 +52,7 @@ enum {
|
|||||||
static struct dentry *eventfs_root_lookup(struct inode *dir,
|
static struct dentry *eventfs_root_lookup(struct inode *dir,
|
||||||
struct dentry *dentry,
|
struct dentry *dentry,
|
||||||
unsigned int flags);
|
unsigned int flags);
|
||||||
static int dcache_dir_open_wrapper(struct inode *inode, struct file *file);
|
static int eventfs_iterate(struct file *file, struct dir_context *ctx);
|
||||||
static int dcache_readdir_wrapper(struct file *file, struct dir_context *ctx);
|
|
||||||
static int eventfs_release(struct inode *inode, struct file *file);
|
|
||||||
|
|
||||||
static void update_attr(struct eventfs_attr *attr, struct iattr *iattr)
|
static void update_attr(struct eventfs_attr *attr, struct iattr *iattr)
|
||||||
{
|
{
|
||||||
@ -148,11 +146,9 @@ static const struct inode_operations eventfs_file_inode_operations = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const struct file_operations eventfs_file_operations = {
|
static const struct file_operations eventfs_file_operations = {
|
||||||
.open = dcache_dir_open_wrapper,
|
|
||||||
.read = generic_read_dir,
|
.read = generic_read_dir,
|
||||||
.iterate_shared = dcache_readdir_wrapper,
|
.iterate_shared = eventfs_iterate,
|
||||||
.llseek = generic_file_llseek,
|
.llseek = generic_file_llseek,
|
||||||
.release = eventfs_release,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Return the evenfs_inode of the "events" directory */
|
/* Return the evenfs_inode of the "events" directory */
|
||||||
@ -643,128 +639,87 @@ static struct dentry *eventfs_root_lookup(struct inode *dir,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct dentry_list {
|
/*
|
||||||
void *cursor;
|
* Walk the children of a eventfs_inode to fill in getdents().
|
||||||
struct dentry **dentries;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* eventfs_release - called to release eventfs file/dir
|
|
||||||
* @inode: inode to be released
|
|
||||||
* @file: file to be released (not used)
|
|
||||||
*/
|
*/
|
||||||
static int eventfs_release(struct inode *inode, struct file *file)
|
static int eventfs_iterate(struct file *file, struct dir_context *ctx)
|
||||||
{
|
|
||||||
struct tracefs_inode *ti;
|
|
||||||
struct dentry_list *dlist = file->private_data;
|
|
||||||
void *cursor;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
ti = get_tracefs(inode);
|
|
||||||
if (!(ti->flags & TRACEFS_EVENT_INODE))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (WARN_ON_ONCE(!dlist))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
for (i = 0; dlist->dentries && dlist->dentries[i]; i++) {
|
|
||||||
dput(dlist->dentries[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
cursor = dlist->cursor;
|
|
||||||
kfree(dlist->dentries);
|
|
||||||
kfree(dlist);
|
|
||||||
file->private_data = cursor;
|
|
||||||
return dcache_dir_close(inode, file);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int add_dentries(struct dentry ***dentries, struct dentry *d, int cnt)
|
|
||||||
{
|
|
||||||
struct dentry **tmp;
|
|
||||||
|
|
||||||
tmp = krealloc(*dentries, sizeof(d) * (cnt + 2), GFP_NOFS);
|
|
||||||
if (!tmp)
|
|
||||||
return -1;
|
|
||||||
tmp[cnt] = d;
|
|
||||||
tmp[cnt + 1] = NULL;
|
|
||||||
*dentries = tmp;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* dcache_dir_open_wrapper - eventfs open wrapper
|
|
||||||
* @inode: not used
|
|
||||||
* @file: dir to be opened (to create it's children)
|
|
||||||
*
|
|
||||||
* Used to dynamic create file/dir with-in @file, all the
|
|
||||||
* file/dir will be created. If already created then references
|
|
||||||
* will be increased
|
|
||||||
*/
|
|
||||||
static int dcache_dir_open_wrapper(struct inode *inode, struct file *file)
|
|
||||||
{
|
{
|
||||||
const struct file_operations *fops;
|
const struct file_operations *fops;
|
||||||
|
struct inode *f_inode = file_inode(file);
|
||||||
const struct eventfs_entry *entry;
|
const struct eventfs_entry *entry;
|
||||||
struct eventfs_inode *ei_child;
|
struct eventfs_inode *ei_child;
|
||||||
struct tracefs_inode *ti;
|
struct tracefs_inode *ti;
|
||||||
struct eventfs_inode *ei;
|
struct eventfs_inode *ei;
|
||||||
struct dentry_list *dlist;
|
struct dentry *ei_dentry = NULL;
|
||||||
struct dentry **dentries = NULL;
|
struct dentry *dentry;
|
||||||
struct dentry *parent = file_dentry(file);
|
const char *name;
|
||||||
struct dentry *d;
|
|
||||||
struct inode *f_inode = file_inode(file);
|
|
||||||
const char *name = parent->d_name.name;
|
|
||||||
umode_t mode;
|
umode_t mode;
|
||||||
void *data;
|
|
||||||
int cnt = 0;
|
|
||||||
int idx;
|
int idx;
|
||||||
int ret;
|
int ret = -EINVAL;
|
||||||
int i;
|
int ino;
|
||||||
int r;
|
int i, r, c;
|
||||||
|
|
||||||
|
if (!dir_emit_dots(file, ctx))
|
||||||
|
return 0;
|
||||||
|
|
||||||
ti = get_tracefs(f_inode);
|
ti = get_tracefs(f_inode);
|
||||||
if (!(ti->flags & TRACEFS_EVENT_INODE))
|
if (!(ti->flags & TRACEFS_EVENT_INODE))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (WARN_ON_ONCE(file->private_data))
|
c = ctx->pos - 2;
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
idx = srcu_read_lock(&eventfs_srcu);
|
idx = srcu_read_lock(&eventfs_srcu);
|
||||||
|
|
||||||
mutex_lock(&eventfs_mutex);
|
mutex_lock(&eventfs_mutex);
|
||||||
ei = READ_ONCE(ti->private);
|
ei = READ_ONCE(ti->private);
|
||||||
|
if (ei && !ei->is_freed)
|
||||||
|
ei_dentry = READ_ONCE(ei->dentry);
|
||||||
mutex_unlock(&eventfs_mutex);
|
mutex_unlock(&eventfs_mutex);
|
||||||
|
|
||||||
if (!ei) {
|
if (!ei || !ei_dentry)
|
||||||
srcu_read_unlock(&eventfs_srcu, idx);
|
goto out;
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
data = ei->data;
|
/*
|
||||||
|
* Need to create the dentries and inodes to have a consistent
|
||||||
dlist = kmalloc(sizeof(*dlist), GFP_KERNEL);
|
* inode number.
|
||||||
if (!dlist) {
|
*/
|
||||||
srcu_read_unlock(&eventfs_srcu, idx);
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
inode_lock(parent->d_inode);
|
|
||||||
list_for_each_entry_srcu(ei_child, &ei->children, list,
|
list_for_each_entry_srcu(ei_child, &ei->children, list,
|
||||||
srcu_read_lock_held(&eventfs_srcu)) {
|
srcu_read_lock_held(&eventfs_srcu)) {
|
||||||
d = create_dir_dentry(ei, ei_child, parent);
|
|
||||||
if (d) {
|
if (c > 0) {
|
||||||
ret = add_dentries(&dentries, d, cnt);
|
c--;
|
||||||
dput(d);
|
continue;
|
||||||
if (ret < 0)
|
|
||||||
break;
|
|
||||||
cnt++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ei_child->is_freed)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
name = ei_child->name;
|
||||||
|
|
||||||
|
dentry = create_dir_dentry(ei, ei_child, ei_dentry);
|
||||||
|
if (!dentry)
|
||||||
|
goto out;
|
||||||
|
ino = dentry->d_inode->i_ino;
|
||||||
|
dput(dentry);
|
||||||
|
|
||||||
|
if (!dir_emit(ctx, name, strlen(name), ino, DT_DIR))
|
||||||
|
goto out;
|
||||||
|
ctx->pos++;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < ei->nr_entries; i++) {
|
for (i = 0; i < ei->nr_entries; i++) {
|
||||||
void *cdata = data;
|
void *cdata = ei->data;
|
||||||
|
|
||||||
|
if (c > 0) {
|
||||||
|
c--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
entry = &ei->entries[i];
|
entry = &ei->entries[i];
|
||||||
name = entry->name;
|
name = entry->name;
|
||||||
|
|
||||||
mutex_lock(&eventfs_mutex);
|
mutex_lock(&eventfs_mutex);
|
||||||
/* If ei->is_freed, then the event itself may be too */
|
/* If ei->is_freed, then the event itself may be too */
|
||||||
if (!ei->is_freed)
|
if (!ei->is_freed)
|
||||||
@ -774,42 +729,21 @@ static int dcache_dir_open_wrapper(struct inode *inode, struct file *file)
|
|||||||
mutex_unlock(&eventfs_mutex);
|
mutex_unlock(&eventfs_mutex);
|
||||||
if (r <= 0)
|
if (r <= 0)
|
||||||
continue;
|
continue;
|
||||||
d = create_file_dentry(ei, i, parent, name, mode, cdata, fops);
|
|
||||||
if (d) {
|
dentry = create_file_dentry(ei, i, ei_dentry, name, mode, cdata, fops);
|
||||||
ret = add_dentries(&dentries, d, cnt);
|
if (!dentry)
|
||||||
dput(d);
|
goto out;
|
||||||
if (ret < 0)
|
ino = dentry->d_inode->i_ino;
|
||||||
break;
|
dput(dentry);
|
||||||
cnt++;
|
|
||||||
}
|
if (!dir_emit(ctx, name, strlen(name), ino, DT_REG))
|
||||||
|
goto out;
|
||||||
|
ctx->pos++;
|
||||||
}
|
}
|
||||||
inode_unlock(parent->d_inode);
|
ret = 1;
|
||||||
|
out:
|
||||||
srcu_read_unlock(&eventfs_srcu, idx);
|
srcu_read_unlock(&eventfs_srcu, idx);
|
||||||
ret = dcache_dir_open(inode, file);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* dcache_dir_open() sets file->private_data to a dentry cursor.
|
|
||||||
* Need to save that but also save all the dentries that were
|
|
||||||
* opened by this function.
|
|
||||||
*/
|
|
||||||
dlist->cursor = file->private_data;
|
|
||||||
dlist->dentries = dentries;
|
|
||||||
file->private_data = dlist;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This just sets the file->private_data back to the cursor and back.
|
|
||||||
*/
|
|
||||||
static int dcache_readdir_wrapper(struct file *file, struct dir_context *ctx)
|
|
||||||
{
|
|
||||||
struct dentry_list *dlist = file->private_data;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
file->private_data = dlist->cursor;
|
|
||||||
ret = dcache_readdir(file, ctx);
|
|
||||||
dlist->cursor = file->private_data;
|
|
||||||
file->private_data = dlist;
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user