diff options
| author | Arnaldo Carvalho de Melo <acme@redhat.com> | 2024-04-22 13:35:18 -0300 |
|---|---|---|
| committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2024-04-22 13:35:18 -0300 |
| commit | 173b0b5b0e865348684c02bd9cb1d22b5d46e458 (patch) | |
| tree | a42a2cc8b724b94a9478aedfcbfabcec0197b246 /fs/debugfs/inode.c | |
| parent | Revert "tools headers: Remove almost unused copy of uapi/stat.h, add few cond... (diff) | |
| parent | Linux 6.9-rc5 (diff) | |
| download | linux-173b0b5b0e865348684c02bd9cb1d22b5d46e458.tar.gz linux-173b0b5b0e865348684c02bd9cb1d22b5d46e458.zip | |
Merge remote-tracking branch 'torvalds/master' into perf-tools-next
To pick up fixes sent via perf-tools, by Namhyung Kim.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'fs/debugfs/inode.c')
| -rw-r--r-- | fs/debugfs/inode.c | 25 |
1 files changed, 20 insertions, 5 deletions
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index 034a617cb1a5..a40da0065433 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c @@ -751,13 +751,28 @@ static void __debugfs_file_removed(struct dentry *dentry) if ((unsigned long)fsd & DEBUGFS_FSDATA_IS_REAL_FOPS_BIT) return; - /* if we hit zero, just wait for all to finish */ - if (!refcount_dec_and_test(&fsd->active_users)) { - wait_for_completion(&fsd->active_users_drained); + /* if this was the last reference, we're done */ + if (refcount_dec_and_test(&fsd->active_users)) return; - } - /* if we didn't hit zero, try to cancel any we can */ + /* + * If there's still a reference, the code that obtained it can + * be in different states: + * - The common case of not using cancellations, or already + * after debugfs_leave_cancellation(), where we just need + * to wait for debugfs_file_put() which signals the completion; + * - inside a cancellation section, i.e. between + * debugfs_enter_cancellation() and debugfs_leave_cancellation(), + * in which case we need to trigger the ->cancel() function, + * and then wait for debugfs_file_put() just like in the + * previous case; + * - before debugfs_enter_cancellation() (but obviously after + * debugfs_file_get()), in which case we may not see the + * cancellation in the list on the first round of the loop, + * but debugfs_enter_cancellation() signals the completion + * after adding it, so this code gets woken up to call the + * ->cancel() function. + */ while (refcount_read(&fsd->active_users)) { struct debugfs_cancellation *c; |
