Blame view
fs/notify/group.c
4 KB
c82ee6d3b treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-or-later |
90586523e fsnotify: unified... |
2 3 |
/* * Copyright (C) 2008 Red Hat, Inc., Eric Paris <eparis@redhat.com> |
90586523e fsnotify: unified... |
4 5 6 7 8 9 10 11 |
*/ #include <linux/list.h> #include <linux/mutex.h> #include <linux/slab.h> #include <linux/srcu.h> #include <linux/rculist.h> #include <linux/wait.h> |
d46eb14b7 fs: fsnotify: acc... |
12 |
#include <linux/memcontrol.h> |
90586523e fsnotify: unified... |
13 14 15 |
#include <linux/fsnotify_backend.h> #include "fsnotify.h" |
60063497a atomic: use <linu... |
16 |
#include <linux/atomic.h> |
90586523e fsnotify: unified... |
17 |
|
3be25f49b fsnotify: add mar... |
18 |
/* |
90586523e fsnotify: unified... |
19 20 |
* Final freeing of a group */ |
cafbaae8a fs/notify/group.c... |
21 |
static void fsnotify_final_destroy_group(struct fsnotify_group *group) |
90586523e fsnotify: unified... |
22 23 24 |
{ if (group->ops->free_group_priv) group->ops->free_group_priv(group); |
d46eb14b7 fs: fsnotify: acc... |
25 |
mem_cgroup_put(group->memcg); |
90586523e fsnotify: unified... |
26 27 28 29 |
kfree(group); } /* |
12703dbfe fsnotify: add a w... |
30 31 32 33 34 |
* Stop queueing new events for this group. Once this function returns * fsnotify_add_event() will not add any new events to the group's queue. */ void fsnotify_group_stop_queueing(struct fsnotify_group *group) { |
c21dbe20f fsnotify: convert... |
35 |
spin_lock(&group->notification_lock); |
12703dbfe fsnotify: add a w... |
36 |
group->shutdown = true; |
c21dbe20f fsnotify: convert... |
37 |
spin_unlock(&group->notification_lock); |
12703dbfe fsnotify: add a w... |
38 39 40 |
} /* |
23e964c28 fsnotify: use ref... |
41 42 43 44 |
* Trying to get rid of a group. Remove all marks, flush all events and release * the group reference. * Note that another thread calling fsnotify_clear_marks_by_group() may still * hold a ref to the group. |
3be25f49b fsnotify: add mar... |
45 |
*/ |
d8153d4d8 inotify, fanotify... |
46 |
void fsnotify_destroy_group(struct fsnotify_group *group) |
3be25f49b fsnotify: add mar... |
47 |
{ |
12703dbfe fsnotify: add a w... |
48 49 50 51 52 53 54 |
/* * Stop queueing new events. The code below is careful enough to not * require this but fanotify needs to stop queuing events even before * fsnotify_destroy_group() is called and this makes the other callers * of fsnotify_destroy_group() to see the same behavior. */ fsnotify_group_stop_queueing(group); |
f09b04a03 fsnotify: Remove ... |
55 |
/* Clear all marks for this group and queue them for destruction */ |
d6f7b98bc fsnotify: use typ... |
56 |
fsnotify_clear_marks_by_group(group, FSNOTIFY_OBJ_ALL_TYPES_MASK); |
2e37c6ca8 fsnotify: Remove ... |
57 58 59 60 61 62 63 |
/* * Some marks can still be pinned when waiting for response from * userspace. Wait for those now. fsnotify_prepare_user_wait() will * not succeed now so this wait is race-free. */ wait_event(group->notification_waitq, !atomic_read(&group->user_waits)); |
3be25f49b fsnotify: add mar... |
64 |
|
35e481761 fsnotify: avoid s... |
65 |
/* |
f09b04a03 fsnotify: Remove ... |
66 67 68 69 |
* Wait until all marks get really destroyed. We could actually destroy * them ourselves instead of waiting for worker to do it, however that * would be racy as worker can already be processing some marks before * we even entered fsnotify_destroy_group(). |
35e481761 fsnotify: avoid s... |
70 |
*/ |
f09b04a03 fsnotify: Remove ... |
71 |
fsnotify_wait_marks_destroyed(); |
75c1be487 fsnotify: srcu to... |
72 |
|
35e481761 fsnotify: avoid s... |
73 74 75 76 77 78 |
/* * Since we have waited for fsnotify_mark_srcu in * fsnotify_mark_destroy_list() there can be no outstanding event * notification against this group. So clearing the notification queue * of all events is reliable now. */ |
23e964c28 fsnotify: use ref... |
79 |
fsnotify_flush_notify(group); |
ff57cd586 fsnotify: Allocat... |
80 81 82 83 84 85 |
/* * Destroy overflow event (we cannot use fsnotify_destroy_event() as * that deliberately ignores overflow events. */ if (group->overflow_event) group->ops->free_event(group->overflow_event); |
23e964c28 fsnotify: use ref... |
86 |
fsnotify_put_group(group); |
3be25f49b fsnotify: add mar... |
87 88 89 |
} /* |
986129520 fsnotify: introdu... |
90 91 92 93 |
* Get reference to a group. */ void fsnotify_get_group(struct fsnotify_group *group) { |
7761daa6a fsnotify: convert... |
94 |
refcount_inc(&group->refcnt); |
986129520 fsnotify: introdu... |
95 96 97 |
} /* |
90586523e fsnotify: unified... |
98 99 100 101 |
* Drop a reference to a group. Free it if it's through. */ void fsnotify_put_group(struct fsnotify_group *group) { |
7761daa6a fsnotify: convert... |
102 |
if (refcount_dec_and_test(&group->refcnt)) |
23e964c28 fsnotify: use ref... |
103 |
fsnotify_final_destroy_group(group); |
90586523e fsnotify: unified... |
104 |
} |
b72679ee8 notify: export sy... |
105 |
EXPORT_SYMBOL_GPL(fsnotify_put_group); |
90586523e fsnotify: unified... |
106 107 |
/* |
ffab83402 fsnotify: fsnotif... |
108 |
* Create a new fsnotify_group and hold a reference for the group returned. |
90586523e fsnotify: unified... |
109 |
*/ |
0d2e2a1d0 fsnotify: drop ma... |
110 |
struct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops) |
90586523e fsnotify: unified... |
111 |
{ |
74be0cc82 fsnotify: remove ... |
112 |
struct fsnotify_group *group; |
90586523e fsnotify: unified... |
113 |
|
f0553af05 fsnotify: kzalloc... |
114 |
group = kzalloc(sizeof(struct fsnotify_group), GFP_KERNEL); |
90586523e fsnotify: unified... |
115 116 |
if (!group) return ERR_PTR(-ENOMEM); |
36fddebaa fsnotify: initial... |
117 |
/* set to 0 when there a no external references to this group */ |
7761daa6a fsnotify: convert... |
118 |
refcount_set(&group->refcnt, 1); |
23e964c28 fsnotify: use ref... |
119 |
atomic_set(&group->num_marks, 0); |
abc77577a fsnotify: Provide... |
120 |
atomic_set(&group->user_waits, 0); |
36fddebaa fsnotify: initial... |
121 |
|
c21dbe20f fsnotify: convert... |
122 |
spin_lock_init(&group->notification_lock); |
a2d8bc6cb fsnotify: generic... |
123 124 |
INIT_LIST_HEAD(&group->notification_list); init_waitqueue_head(&group->notification_waitq); |
a2d8bc6cb fsnotify: generic... |
125 |
group->max_events = UINT_MAX; |
986ab0980 fsnotify: use a m... |
126 |
mutex_init(&group->mark_mutex); |
e61ce8673 fsnotify: rename ... |
127 |
INIT_LIST_HEAD(&group->marks_list); |
3be25f49b fsnotify: add mar... |
128 |
|
90586523e fsnotify: unified... |
129 |
group->ops = ops; |
90586523e fsnotify: unified... |
130 131 |
return group; } |
b72679ee8 notify: export sy... |
132 |
EXPORT_SYMBOL_GPL(fsnotify_alloc_group); |
0a6b6bd59 fsnotify: make fa... |
133 134 135 136 137 138 139 |
int fsnotify_fasync(int fd, struct file *file, int on) { struct fsnotify_group *group = file->private_data; return fasync_helper(fd, file, on, &group->fsn_fa) >= 0 ? 0 : -EIO; } |