Skip to content

Commit 28e12c0

Browse files
committed
eventfs: Save ownership and mode
Now that inodes and dentries are created on the fly, they are also reclaimed on memory pressure. Since the ownership and file mode are saved in the inode, if they are freed, any changes to the ownership and mode will be lost. To counter this, if the user changes the permissions or ownership, save them, and when creating the inodes again, restore those changes. Link: https://lkml.kernel.org/r/[email protected] Cc: [email protected] Cc: Ajay Kaher <[email protected]> Cc: Mark Rutland <[email protected]> Cc: Andrew Morton <[email protected]> Fixes: 6394044 ("eventfs: Implement eventfs lookup, read, open functions") Reviewed-by: Masami Hiramatsu (Google) <[email protected]> Signed-off-by: Steven Rostedt (Google) <[email protected]>
1 parent 77a06c3 commit 28e12c0

File tree

2 files changed

+151
-13
lines changed

2 files changed

+151
-13
lines changed

fs/tracefs/event_inode.c

Lines changed: 135 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,105 @@ static DEFINE_MUTEX(eventfs_mutex);
4040
*/
4141
DEFINE_STATIC_SRCU(eventfs_srcu);
4242

43+
/* Mode is unsigned short, use the upper bits for flags */
44+
enum {
45+
EVENTFS_SAVE_MODE = BIT(16),
46+
EVENTFS_SAVE_UID = BIT(17),
47+
EVENTFS_SAVE_GID = BIT(18),
48+
};
49+
50+
#define EVENTFS_MODE_MASK (EVENTFS_SAVE_MODE - 1)
51+
4352
static struct dentry *eventfs_root_lookup(struct inode *dir,
4453
struct dentry *dentry,
4554
unsigned int flags);
4655
static int dcache_dir_open_wrapper(struct inode *inode, struct file *file);
4756
static int dcache_readdir_wrapper(struct file *file, struct dir_context *ctx);
4857
static int eventfs_release(struct inode *inode, struct file *file);
4958

59+
static void update_attr(struct eventfs_attr *attr, struct iattr *iattr)
60+
{
61+
unsigned int ia_valid = iattr->ia_valid;
62+
63+
if (ia_valid & ATTR_MODE) {
64+
attr->mode = (attr->mode & ~EVENTFS_MODE_MASK) |
65+
(iattr->ia_mode & EVENTFS_MODE_MASK) |
66+
EVENTFS_SAVE_MODE;
67+
}
68+
if (ia_valid & ATTR_UID) {
69+
attr->mode |= EVENTFS_SAVE_UID;
70+
attr->uid = iattr->ia_uid;
71+
}
72+
if (ia_valid & ATTR_GID) {
73+
attr->mode |= EVENTFS_SAVE_GID;
74+
attr->gid = iattr->ia_gid;
75+
}
76+
}
77+
78+
static int eventfs_set_attr(struct mnt_idmap *idmap, struct dentry *dentry,
79+
struct iattr *iattr)
80+
{
81+
const struct eventfs_entry *entry;
82+
struct eventfs_inode *ei;
83+
const char *name;
84+
int ret;
85+
86+
mutex_lock(&eventfs_mutex);
87+
ei = dentry->d_fsdata;
88+
/* The LSB is set when the eventfs_inode is being freed */
89+
if (((unsigned long)ei & 1UL) || ei->is_freed) {
90+
/* Do not allow changes if the event is about to be removed. */
91+
mutex_unlock(&eventfs_mutex);
92+
return -ENODEV;
93+
}
94+
95+
/* Preallocate the children mode array if necessary */
96+
if (!(dentry->d_inode->i_mode & S_IFDIR)) {
97+
if (!ei->entry_attrs) {
98+
ei->entry_attrs = kzalloc(sizeof(*ei->entry_attrs) * ei->nr_entries,
99+
GFP_KERNEL);
100+
if (!ei->entry_attrs) {
101+
ret = -ENOMEM;
102+
goto out;
103+
}
104+
}
105+
}
106+
107+
ret = simple_setattr(idmap, dentry, iattr);
108+
if (ret < 0)
109+
goto out;
110+
111+
/*
112+
* If this is a dir, then update the ei cache, only the file
113+
* mode is saved in the ei->m_children, and the ownership is
114+
* determined by the parent directory.
115+
*/
116+
if (dentry->d_inode->i_mode & S_IFDIR) {
117+
update_attr(&ei->attr, iattr);
118+
119+
} else {
120+
name = dentry->d_name.name;
121+
122+
for (int i = 0; i < ei->nr_entries; i++) {
123+
entry = &ei->entries[i];
124+
if (strcmp(name, entry->name) == 0) {
125+
update_attr(&ei->entry_attrs[i], iattr);
126+
break;
127+
}
128+
}
129+
}
130+
out:
131+
mutex_unlock(&eventfs_mutex);
132+
return ret;
133+
}
134+
50135
static const struct inode_operations eventfs_root_dir_inode_operations = {
51136
.lookup = eventfs_root_lookup,
137+
.setattr = eventfs_set_attr,
138+
};
139+
140+
static const struct inode_operations eventfs_file_inode_operations = {
141+
.setattr = eventfs_set_attr,
52142
};
53143

54144
static const struct file_operations eventfs_file_operations = {
@@ -59,10 +149,30 @@ static const struct file_operations eventfs_file_operations = {
59149
.release = eventfs_release,
60150
};
61151

152+
static void update_inode_attr(struct inode *inode, struct eventfs_attr *attr, umode_t mode)
153+
{
154+
if (!attr) {
155+
inode->i_mode = mode;
156+
return;
157+
}
158+
159+
if (attr->mode & EVENTFS_SAVE_MODE)
160+
inode->i_mode = attr->mode & EVENTFS_MODE_MASK;
161+
else
162+
inode->i_mode = mode;
163+
164+
if (attr->mode & EVENTFS_SAVE_UID)
165+
inode->i_uid = attr->uid;
166+
167+
if (attr->mode & EVENTFS_SAVE_GID)
168+
inode->i_gid = attr->gid;
169+
}
170+
62171
/**
63172
* create_file - create a file in the tracefs filesystem
64173
* @name: the name of the file to create.
65174
* @mode: the permission that the file should have.
175+
* @attr: saved attributes changed by user
66176
* @parent: parent dentry for this file.
67177
* @data: something that the caller will want to get to later on.
68178
* @fop: struct file_operations that should be used for this file.
@@ -72,6 +182,7 @@ static const struct file_operations eventfs_file_operations = {
72182
* call.
73183
*/
74184
static struct dentry *create_file(const char *name, umode_t mode,
185+
struct eventfs_attr *attr,
75186
struct dentry *parent, void *data,
76187
const struct file_operations *fop)
77188
{
@@ -95,7 +206,10 @@ static struct dentry *create_file(const char *name, umode_t mode,
95206
if (unlikely(!inode))
96207
return eventfs_failed_creating(dentry);
97208

98-
inode->i_mode = mode;
209+
/* If the user updated the directory's attributes, use them */
210+
update_inode_attr(inode, attr, mode);
211+
212+
inode->i_op = &eventfs_file_inode_operations;
99213
inode->i_fop = fop;
100214
inode->i_private = data;
101215

@@ -108,27 +222,29 @@ static struct dentry *create_file(const char *name, umode_t mode,
108222

109223
/**
110224
* create_dir - create a dir in the tracefs filesystem
111-
* @name: the name of the file to create.
225+
* @ei: the eventfs_inode that represents the directory to create
112226
* @parent: parent dentry for this file.
113227
*
114228
* This function will create a dentry for a directory represented by
115229
* a eventfs_inode.
116230
*/
117-
static struct dentry *create_dir(const char *name, struct dentry *parent)
231+
static struct dentry *create_dir(struct eventfs_inode *ei, struct dentry *parent)
118232
{
119233
struct tracefs_inode *ti;
120234
struct dentry *dentry;
121235
struct inode *inode;
122236

123-
dentry = eventfs_start_creating(name, parent);
237+
dentry = eventfs_start_creating(ei->name, parent);
124238
if (IS_ERR(dentry))
125239
return dentry;
126240

127241
inode = tracefs_get_inode(dentry->d_sb);
128242
if (unlikely(!inode))
129243
return eventfs_failed_creating(dentry);
130244

131-
inode->i_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO;
245+
/* If the user updated the directory's attributes, use them */
246+
update_inode_attr(inode, &ei->attr, S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO);
247+
132248
inode->i_op = &eventfs_root_dir_inode_operations;
133249
inode->i_fop = &eventfs_file_operations;
134250

@@ -146,6 +262,7 @@ static void free_ei(struct eventfs_inode *ei)
146262
{
147263
kfree_const(ei->name);
148264
kfree(ei->d_children);
265+
kfree(ei->entry_attrs);
149266
kfree(ei);
150267
}
151268

@@ -231,7 +348,7 @@ void eventfs_set_ei_status_free(struct tracefs_inode *ti, struct dentry *dentry)
231348
/**
232349
* create_file_dentry - create a dentry for a file of an eventfs_inode
233350
* @ei: the eventfs_inode that the file will be created under
234-
* @e_dentry: a pointer to the d_children[] of the @ei
351+
* @idx: the index into the d_children[] of the @ei
235352
* @parent: The parent dentry of the created file.
236353
* @name: The name of the file to create
237354
* @mode: The mode of the file.
@@ -244,10 +361,12 @@ void eventfs_set_ei_status_free(struct tracefs_inode *ti, struct dentry *dentry)
244361
* just do a dget() on it and return. Otherwise create the dentry and attach it.
245362
*/
246363
static struct dentry *
247-
create_file_dentry(struct eventfs_inode *ei, struct dentry **e_dentry,
364+
create_file_dentry(struct eventfs_inode *ei, int idx,
248365
struct dentry *parent, const char *name, umode_t mode, void *data,
249366
const struct file_operations *fops, bool lookup)
250367
{
368+
struct eventfs_attr *attr = NULL;
369+
struct dentry **e_dentry = &ei->d_children[idx];
251370
struct dentry *dentry;
252371
bool invalidate = false;
253372

@@ -264,13 +383,18 @@ create_file_dentry(struct eventfs_inode *ei, struct dentry **e_dentry,
264383
mutex_unlock(&eventfs_mutex);
265384
return *e_dentry;
266385
}
386+
387+
/* ei->entry_attrs are protected by SRCU */
388+
if (ei->entry_attrs)
389+
attr = &ei->entry_attrs[idx];
390+
267391
mutex_unlock(&eventfs_mutex);
268392

269393
/* The lookup already has the parent->d_inode locked */
270394
if (!lookup)
271395
inode_lock(parent->d_inode);
272396

273-
dentry = create_file(name, mode, parent, data, fops);
397+
dentry = create_file(name, mode, attr, parent, data, fops);
274398

275399
if (!lookup)
276400
inode_unlock(parent->d_inode);
@@ -378,7 +502,7 @@ create_dir_dentry(struct eventfs_inode *pei, struct eventfs_inode *ei,
378502
if (!lookup)
379503
inode_lock(parent->d_inode);
380504

381-
dentry = create_dir(ei->name, parent);
505+
dentry = create_dir(ei, parent);
382506

383507
if (!lookup)
384508
inode_unlock(parent->d_inode);
@@ -495,8 +619,7 @@ static struct dentry *eventfs_root_lookup(struct inode *dir,
495619
if (r <= 0)
496620
continue;
497621
ret = simple_lookup(dir, dentry, flags);
498-
create_file_dentry(ei, &ei->d_children[i],
499-
ei_dentry, name, mode, cdata,
622+
create_file_dentry(ei, i, ei_dentry, name, mode, cdata,
500623
fops, true);
501624
break;
502625
}
@@ -629,8 +752,7 @@ static int dcache_dir_open_wrapper(struct inode *inode, struct file *file)
629752
r = entry->callback(name, &mode, &cdata, &fops);
630753
if (r <= 0)
631754
continue;
632-
d = create_file_dentry(ei, &ei->d_children[i],
633-
parent, name, mode, cdata, fops, false);
755+
d = create_file_dentry(ei, i, parent, name, mode, cdata, fops, false);
634756
if (d) {
635757
ret = add_dentries(&dentries, d, cnt);
636758
if (ret < 0)

fs/tracefs/internal.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,18 @@ struct tracefs_inode {
1313
struct inode vfs_inode;
1414
};
1515

16+
/*
17+
* struct eventfs_attr - cache the mode and ownership of a eventfs entry
18+
* @mode: saved mode plus flags of what is saved
19+
* @uid: saved uid if changed
20+
* @gid: saved gid if changed
21+
*/
22+
struct eventfs_attr {
23+
int mode;
24+
kuid_t uid;
25+
kgid_t gid;
26+
};
27+
1628
/*
1729
* struct eventfs_inode - hold the properties of the eventfs directories.
1830
* @list: link list into the parent directory
@@ -22,6 +34,8 @@ struct tracefs_inode {
2234
* @dentry: the dentry of the directory
2335
* @d_parent: pointer to the parent's dentry
2436
* @d_children: The array of dentries to represent the files when created
37+
* @entry_attrs: Saved mode and ownership of the @d_children
38+
* @attr: Saved mode and ownership of eventfs_inode itself
2539
* @data: The private data to pass to the callbacks
2640
* @is_freed: Flag set if the eventfs is on its way to be freed
2741
* Note if is_freed is set, then dentry is corrupted.
@@ -35,6 +49,8 @@ struct eventfs_inode {
3549
struct dentry *dentry; /* Check is_freed to access */
3650
struct dentry *d_parent;
3751
struct dentry **d_children;
52+
struct eventfs_attr *entry_attrs;
53+
struct eventfs_attr attr;
3854
void *data;
3955
/*
4056
* Union - used for deletion

0 commit comments

Comments
 (0)