Skip to content

Commit 453f5db

Browse files
committed
Merge tag 'trace-v6.7-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace
Pull tracing fixes from Steven Rostedt: - Fix readers that are blocked on the ring buffer when buffer_percent is 100%. They are supposed to wake up when the buffer is full, but because the sub-buffer that the writer is on is never considered "dirty" in the calculation, dirty pages will never equal nr_pages. Add +1 to the dirty count in order to count for the sub-buffer that the writer is on. - When a reader is blocked on the "snapshot_raw" file, it is to be woken up when a snapshot is done and be able to read the snapshot buffer. But because the snapshot swaps the buffers (the main one with the snapshot one), and the snapshot reader is waiting on the old snapshot buffer, it was not woken up (because it is now on the main buffer after the swap). Worse yet, when it reads the buffer after a snapshot, it's not reading the snapshot buffer, it's reading the live active main buffer. Fix this by forcing a wakeup of all readers on the snapshot buffer when a new snapshot happens, and then update the buffer that the reader is reading to be back on the snapshot buffer. - Fix the modification of the direct_function hash. There was a race when new functions were added to the direct_function hash as when it moved function entries from the old hash to the new one, a direct function trace could be hit and not see its entry. This is fixed by allocating the new hash, copy all the old entries onto it as well as the new entries, and then use rcu_assign_pointer() to update the new direct_function hash with it. This also fixes a memory leak in that code. - Fix eventfs ownership * tag 'trace-v6.7-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace: ftrace: Fix modification of direct_function hash while in use tracing: Fix blocked reader of snapshot buffer ring-buffer: Fix wake ups when buffer_percent is set to 100 eventfs: Fix file and directory uid and gid ownership
2 parents b106bcf + d05cb47 commit 453f5db

File tree

6 files changed

+176
-69
lines changed

6 files changed

+176
-69
lines changed

fs/tracefs/event_inode.c

Lines changed: 95 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,14 @@ static int eventfs_set_attr(struct mnt_idmap *idmap, struct dentry *dentry,
113113
* determined by the parent directory.
114114
*/
115115
if (dentry->d_inode->i_mode & S_IFDIR) {
116-
update_attr(&ei->attr, iattr);
116+
/*
117+
* The events directory dentry is never freed, unless its
118+
* part of an instance that is deleted. It's attr is the
119+
* default for its child files and directories.
120+
* Do not update it. It's not used for its own mode or ownership
121+
*/
122+
if (!ei->is_events)
123+
update_attr(&ei->attr, iattr);
117124

118125
} else {
119126
name = dentry->d_name.name;
@@ -148,28 +155,93 @@ static const struct file_operations eventfs_file_operations = {
148155
.release = eventfs_release,
149156
};
150157

158+
/* Return the evenfs_inode of the "events" directory */
159+
static struct eventfs_inode *eventfs_find_events(struct dentry *dentry)
160+
{
161+
struct eventfs_inode *ei;
162+
163+
mutex_lock(&eventfs_mutex);
164+
do {
165+
/* The parent always has an ei, except for events itself */
166+
ei = dentry->d_parent->d_fsdata;
167+
168+
/*
169+
* If the ei is being freed, the ownership of the children
170+
* doesn't matter.
171+
*/
172+
if (ei->is_freed) {
173+
ei = NULL;
174+
break;
175+
}
176+
177+
dentry = ei->dentry;
178+
} while (!ei->is_events);
179+
mutex_unlock(&eventfs_mutex);
180+
181+
return ei;
182+
}
183+
151184
static void update_inode_attr(struct dentry *dentry, struct inode *inode,
152185
struct eventfs_attr *attr, umode_t mode)
153186
{
154-
if (!attr) {
155-
inode->i_mode = mode;
187+
struct eventfs_inode *events_ei = eventfs_find_events(dentry);
188+
189+
if (!events_ei)
190+
return;
191+
192+
inode->i_mode = mode;
193+
inode->i_uid = events_ei->attr.uid;
194+
inode->i_gid = events_ei->attr.gid;
195+
196+
if (!attr)
156197
return;
157-
}
158198

159199
if (attr->mode & EVENTFS_SAVE_MODE)
160200
inode->i_mode = attr->mode & EVENTFS_MODE_MASK;
161-
else
162-
inode->i_mode = mode;
163201

164202
if (attr->mode & EVENTFS_SAVE_UID)
165203
inode->i_uid = attr->uid;
166-
else
167-
inode->i_uid = d_inode(dentry->d_parent)->i_uid;
168204

169205
if (attr->mode & EVENTFS_SAVE_GID)
170206
inode->i_gid = attr->gid;
171-
else
172-
inode->i_gid = d_inode(dentry->d_parent)->i_gid;
207+
}
208+
209+
static void update_gid(struct eventfs_inode *ei, kgid_t gid, int level)
210+
{
211+
struct eventfs_inode *ei_child;
212+
213+
/* at most we have events/system/event */
214+
if (WARN_ON_ONCE(level > 3))
215+
return;
216+
217+
ei->attr.gid = gid;
218+
219+
if (ei->entry_attrs) {
220+
for (int i = 0; i < ei->nr_entries; i++) {
221+
ei->entry_attrs[i].gid = gid;
222+
}
223+
}
224+
225+
/*
226+
* Only eventfs_inode with dentries are updated, make sure
227+
* all eventfs_inodes are updated. If one of the children
228+
* do not have a dentry, this function must traverse it.
229+
*/
230+
list_for_each_entry_srcu(ei_child, &ei->children, list,
231+
srcu_read_lock_held(&eventfs_srcu)) {
232+
if (!ei_child->dentry)
233+
update_gid(ei_child, gid, level + 1);
234+
}
235+
}
236+
237+
void eventfs_update_gid(struct dentry *dentry, kgid_t gid)
238+
{
239+
struct eventfs_inode *ei = dentry->d_fsdata;
240+
int idx;
241+
242+
idx = srcu_read_lock(&eventfs_srcu);
243+
update_gid(ei, gid, 0);
244+
srcu_read_unlock(&eventfs_srcu, idx);
173245
}
174246

175247
/**
@@ -860,6 +932,8 @@ struct eventfs_inode *eventfs_create_events_dir(const char *name, struct dentry
860932
struct eventfs_inode *ei;
861933
struct tracefs_inode *ti;
862934
struct inode *inode;
935+
kuid_t uid;
936+
kgid_t gid;
863937

864938
if (security_locked_down(LOCKDOWN_TRACEFS))
865939
return NULL;
@@ -884,11 +958,20 @@ struct eventfs_inode *eventfs_create_events_dir(const char *name, struct dentry
884958
ei->dentry = dentry;
885959
ei->entries = entries;
886960
ei->nr_entries = size;
961+
ei->is_events = 1;
887962
ei->data = data;
888963
ei->name = kstrdup_const(name, GFP_KERNEL);
889964
if (!ei->name)
890965
goto fail;
891966

967+
/* Save the ownership of this directory */
968+
uid = d_inode(dentry->d_parent)->i_uid;
969+
gid = d_inode(dentry->d_parent)->i_gid;
970+
971+
/* This is used as the default ownership of the files and directories */
972+
ei->attr.uid = uid;
973+
ei->attr.gid = gid;
974+
892975
INIT_LIST_HEAD(&ei->children);
893976
INIT_LIST_HEAD(&ei->list);
894977

@@ -897,6 +980,8 @@ struct eventfs_inode *eventfs_create_events_dir(const char *name, struct dentry
897980
ti->private = ei;
898981

899982
inode->i_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO;
983+
inode->i_uid = uid;
984+
inode->i_gid = gid;
900985
inode->i_op = &eventfs_root_dir_inode_operations;
901986
inode->i_fop = &eventfs_file_operations;
902987

fs/tracefs/inode.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ static void set_gid(struct dentry *parent, kgid_t gid)
210210
next = this_parent->d_subdirs.next;
211211
resume:
212212
while (next != &this_parent->d_subdirs) {
213+
struct tracefs_inode *ti;
213214
struct list_head *tmp = next;
214215
struct dentry *dentry = list_entry(tmp, struct dentry, d_child);
215216
next = tmp->next;
@@ -218,6 +219,11 @@ static void set_gid(struct dentry *parent, kgid_t gid)
218219

219220
change_gid(dentry, gid);
220221

222+
/* If this is the events directory, update that too */
223+
ti = get_tracefs(dentry->d_inode);
224+
if (ti && (ti->flags & TRACEFS_EVENT_INODE))
225+
eventfs_update_gid(dentry, gid);
226+
221227
if (!list_empty(&dentry->d_subdirs)) {
222228
spin_unlock(&this_parent->d_lock);
223229
spin_release(&dentry->d_lock.dep_map, _RET_IP_);

fs/tracefs/internal.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ struct eventfs_inode {
6262
struct rcu_head rcu;
6363
};
6464
unsigned int is_freed:1;
65+
unsigned int is_events:1;
6566
unsigned int nr_entries:31;
6667
};
6768

@@ -77,6 +78,7 @@ struct inode *tracefs_get_inode(struct super_block *sb);
7778
struct dentry *eventfs_start_creating(const char *name, struct dentry *parent);
7879
struct dentry *eventfs_failed_creating(struct dentry *dentry);
7980
struct dentry *eventfs_end_creating(struct dentry *dentry);
81+
void eventfs_update_gid(struct dentry *dentry, kgid_t gid);
8082
void eventfs_set_ei_status_free(struct tracefs_inode *ti, struct dentry *dentry);
8183

8284
#endif /* _TRACEFS_INTERNAL_H */

kernel/trace/ftrace.c

Lines changed: 47 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1183,18 +1183,19 @@ static void __add_hash_entry(struct ftrace_hash *hash,
11831183
hash->count++;
11841184
}
11851185

1186-
static int add_hash_entry(struct ftrace_hash *hash, unsigned long ip)
1186+
static struct ftrace_func_entry *
1187+
add_hash_entry(struct ftrace_hash *hash, unsigned long ip)
11871188
{
11881189
struct ftrace_func_entry *entry;
11891190

11901191
entry = kmalloc(sizeof(*entry), GFP_KERNEL);
11911192
if (!entry)
1192-
return -ENOMEM;
1193+
return NULL;
11931194

11941195
entry->ip = ip;
11951196
__add_hash_entry(hash, entry);
11961197

1197-
return 0;
1198+
return entry;
11981199
}
11991200

12001201
static void
@@ -1349,7 +1350,6 @@ alloc_and_copy_ftrace_hash(int size_bits, struct ftrace_hash *hash)
13491350
struct ftrace_func_entry *entry;
13501351
struct ftrace_hash *new_hash;
13511352
int size;
1352-
int ret;
13531353
int i;
13541354

13551355
new_hash = alloc_ftrace_hash(size_bits);
@@ -1366,8 +1366,7 @@ alloc_and_copy_ftrace_hash(int size_bits, struct ftrace_hash *hash)
13661366
size = 1 << hash->size_bits;
13671367
for (i = 0; i < size; i++) {
13681368
hlist_for_each_entry(entry, &hash->buckets[i], hlist) {
1369-
ret = add_hash_entry(new_hash, entry->ip);
1370-
if (ret < 0)
1369+
if (add_hash_entry(new_hash, entry->ip) == NULL)
13711370
goto free_hash;
13721371
}
13731372
}
@@ -2536,7 +2535,7 @@ ftrace_find_unique_ops(struct dyn_ftrace *rec)
25362535

25372536
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
25382537
/* Protected by rcu_tasks for reading, and direct_mutex for writing */
2539-
static struct ftrace_hash *direct_functions = EMPTY_HASH;
2538+
static struct ftrace_hash __rcu *direct_functions = EMPTY_HASH;
25402539
static DEFINE_MUTEX(direct_mutex);
25412540
int ftrace_direct_func_count;
25422541

@@ -2555,39 +2554,6 @@ unsigned long ftrace_find_rec_direct(unsigned long ip)
25552554
return entry->direct;
25562555
}
25572556

2558-
static struct ftrace_func_entry*
2559-
ftrace_add_rec_direct(unsigned long ip, unsigned long addr,
2560-
struct ftrace_hash **free_hash)
2561-
{
2562-
struct ftrace_func_entry *entry;
2563-
2564-
if (ftrace_hash_empty(direct_functions) ||
2565-
direct_functions->count > 2 * (1 << direct_functions->size_bits)) {
2566-
struct ftrace_hash *new_hash;
2567-
int size = ftrace_hash_empty(direct_functions) ? 0 :
2568-
direct_functions->count + 1;
2569-
2570-
if (size < 32)
2571-
size = 32;
2572-
2573-
new_hash = dup_hash(direct_functions, size);
2574-
if (!new_hash)
2575-
return NULL;
2576-
2577-
*free_hash = direct_functions;
2578-
direct_functions = new_hash;
2579-
}
2580-
2581-
entry = kmalloc(sizeof(*entry), GFP_KERNEL);
2582-
if (!entry)
2583-
return NULL;
2584-
2585-
entry->ip = ip;
2586-
entry->direct = addr;
2587-
__add_hash_entry(direct_functions, entry);
2588-
return entry;
2589-
}
2590-
25912557
static void call_direct_funcs(unsigned long ip, unsigned long pip,
25922558
struct ftrace_ops *ops, struct ftrace_regs *fregs)
25932559
{
@@ -4223,8 +4189,8 @@ enter_record(struct ftrace_hash *hash, struct dyn_ftrace *rec, int clear_filter)
42234189
/* Do nothing if it exists */
42244190
if (entry)
42254191
return 0;
4226-
4227-
ret = add_hash_entry(hash, rec->ip);
4192+
if (add_hash_entry(hash, rec->ip) == NULL)
4193+
ret = -ENOMEM;
42284194
}
42294195
return ret;
42304196
}
@@ -5266,7 +5232,8 @@ __ftrace_match_addr(struct ftrace_hash *hash, unsigned long ip, int remove)
52665232
return 0;
52675233
}
52685234

5269-
return add_hash_entry(hash, ip);
5235+
entry = add_hash_entry(hash, ip);
5236+
return entry ? 0 : -ENOMEM;
52705237
}
52715238

52725239
static int
@@ -5410,7 +5377,7 @@ static void remove_direct_functions_hash(struct ftrace_hash *hash, unsigned long
54105377
*/
54115378
int register_ftrace_direct(struct ftrace_ops *ops, unsigned long addr)
54125379
{
5413-
struct ftrace_hash *hash, *free_hash = NULL;
5380+
struct ftrace_hash *hash, *new_hash = NULL, *free_hash = NULL;
54145381
struct ftrace_func_entry *entry, *new;
54155382
int err = -EBUSY, size, i;
54165383

@@ -5436,35 +5403,62 @@ int register_ftrace_direct(struct ftrace_ops *ops, unsigned long addr)
54365403
}
54375404
}
54385405

5439-
/* ... and insert them to direct_functions hash. */
54405406
err = -ENOMEM;
5407+
5408+
/* Make a copy hash to place the new and the old entries in */
5409+
size = hash->count + direct_functions->count;
5410+
if (size > 32)
5411+
size = 32;
5412+
new_hash = alloc_ftrace_hash(fls(size));
5413+
if (!new_hash)
5414+
goto out_unlock;
5415+
5416+
/* Now copy over the existing direct entries */
5417+
size = 1 << direct_functions->size_bits;
5418+
for (i = 0; i < size; i++) {
5419+
hlist_for_each_entry(entry, &direct_functions->buckets[i], hlist) {
5420+
new = add_hash_entry(new_hash, entry->ip);
5421+
if (!new)
5422+
goto out_unlock;
5423+
new->direct = entry->direct;
5424+
}
5425+
}
5426+
5427+
/* ... and add the new entries */
5428+
size = 1 << hash->size_bits;
54415429
for (i = 0; i < size; i++) {
54425430
hlist_for_each_entry(entry, &hash->buckets[i], hlist) {
5443-
new = ftrace_add_rec_direct(entry->ip, addr, &free_hash);
5431+
new = add_hash_entry(new_hash, entry->ip);
54445432
if (!new)
5445-
goto out_remove;
5433+
goto out_unlock;
5434+
/* Update both the copy and the hash entry */
5435+
new->direct = addr;
54465436
entry->direct = addr;
54475437
}
54485438
}
54495439

5440+
free_hash = direct_functions;
5441+
rcu_assign_pointer(direct_functions, new_hash);
5442+
new_hash = NULL;
5443+
54505444
ops->func = call_direct_funcs;
54515445
ops->flags = MULTI_FLAGS;
54525446
ops->trampoline = FTRACE_REGS_ADDR;
54535447
ops->direct_call = addr;
54545448

54555449
err = register_ftrace_function_nolock(ops);
54565450

5457-
out_remove:
5458-
if (err)
5459-
remove_direct_functions_hash(hash, addr);
5460-
54615451
out_unlock:
54625452
mutex_unlock(&direct_mutex);
54635453

5464-
if (free_hash) {
5454+
if (free_hash && free_hash != EMPTY_HASH) {
54655455
synchronize_rcu_tasks();
54665456
free_ftrace_hash(free_hash);
54675457
}
5458+
5459+
if (new_hash)
5460+
free_ftrace_hash(new_hash);
5461+
54685462
return err;
54695463
}
54705464
EXPORT_SYMBOL_GPL(register_ftrace_direct);
@@ -6309,7 +6303,7 @@ ftrace_graph_set_hash(struct ftrace_hash *hash, char *buffer)
63096303

63106304
if (entry)
63116305
continue;
6312-
if (add_hash_entry(hash, rec->ip) < 0)
6306+
if (add_hash_entry(hash, rec->ip) == NULL)
63136307
goto out;
63146308
} else {
63156309
if (entry) {

0 commit comments

Comments
 (0)