Skip to content

Commit 5133cd7

Browse files
committed
Merge branch 'fsnotify' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs
Pull fsnotify updates from Jan Kara: "The branch contains mainly a rework of fsnotify infrastructure fixing a shortcoming that we have waited for response to fanotify permission events with SRCU read lock held and when the process consuming events was slow to respond the kernel has stalled. It also contains several cleanups of unnecessary indirections in fsnotify framework and a bugfix from Amir fixing leakage of kernel internal errno to userspace" * 'fsnotify' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs: (37 commits) fanotify: don't expose EOPENSTALE to userspace fsnotify: remove a stray unlock fsnotify: Move ->free_mark callback to fsnotify_ops fsnotify: Add group pointer in fsnotify_init_mark() fsnotify: Drop inode_mark.c fsnotify: Remove fsnotify_find_{inode|vfsmount}_mark() fsnotify: Remove fsnotify_detach_group_marks() fsnotify: Rename fsnotify_clear_marks_by_group_flags() fsnotify: Inline fsnotify_clear_{inode|vfsmount}_mark_group() fsnotify: Remove fsnotify_recalc_{inode|vfsmount}_mask() fsnotify: Remove fsnotify_set_mark_{,ignored_}mask_locked() fanotify: Release SRCU lock when waiting for userspace response fsnotify: Pass fsnotify_iter_info into handle_event handler fsnotify: Provide framework for dropping SRCU lock in ->handle_event fsnotify: Remove special handling of mark destruction on group shutdown fsnotify: Detach mark from object list when last reference is dropped fsnotify: Move queueing of mark for destruction into fsnotify_put_mark() inotify: Do not drop mark reference under idr_lock fsnotify: Free fsnotify_mark_connector when there is no mark attached fsnotify: Lock object list with connector lock ...
2 parents 7b66f13 + 4ff33aa commit 5133cd7

24 files changed

+815
-771
lines changed

fs/inode.c

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -371,9 +371,6 @@ void inode_init_once(struct inode *inode)
371371
INIT_LIST_HEAD(&inode->i_lru);
372372
address_space_init_once(&inode->i_data);
373373
i_size_ordered_init(inode);
374-
#ifdef CONFIG_FSNOTIFY
375-
INIT_HLIST_HEAD(&inode->i_fsnotify_marks);
376-
#endif
377374
}
378375
EXPORT_SYMBOL(inode_init_once);
379376

fs/mount.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ struct mount {
5959
struct mountpoint *mnt_mp; /* where is it mounted */
6060
struct hlist_node mnt_mp_list; /* list mounts with the same mountpoint */
6161
#ifdef CONFIG_FSNOTIFY
62-
struct hlist_head mnt_fsnotify_marks;
62+
struct fsnotify_mark_connector __rcu *mnt_fsnotify_marks;
6363
__u32 mnt_fsnotify_mask;
6464
#endif
6565
int mnt_id; /* mount identifier */

fs/namespace.c

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -236,9 +236,6 @@ static struct mount *alloc_vfsmnt(const char *name)
236236
INIT_LIST_HEAD(&mnt->mnt_slave_list);
237237
INIT_LIST_HEAD(&mnt->mnt_slave);
238238
INIT_HLIST_NODE(&mnt->mnt_mp_list);
239-
#ifdef CONFIG_FSNOTIFY
240-
INIT_HLIST_HEAD(&mnt->mnt_fsnotify_marks);
241-
#endif
242239
init_fs_pin(&mnt->mnt_umount, drop_mountpoint);
243240
}
244241
return mnt;

fs/notify/Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
obj-$(CONFIG_FSNOTIFY) += fsnotify.o notification.o group.o inode_mark.o \
2-
mark.o vfsmount_mark.o fdinfo.o
1+
obj-$(CONFIG_FSNOTIFY) += fsnotify.o notification.o group.o mark.o \
2+
fdinfo.o
33

44
obj-y += dnotify/
55
obj-y += inotify/

fs/notify/dnotify/dnotify.c

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -52,25 +52,21 @@ struct dnotify_mark {
5252
*/
5353
static void dnotify_recalc_inode_mask(struct fsnotify_mark *fsn_mark)
5454
{
55-
__u32 new_mask, old_mask;
55+
__u32 new_mask = 0;
5656
struct dnotify_struct *dn;
5757
struct dnotify_mark *dn_mark = container_of(fsn_mark,
5858
struct dnotify_mark,
5959
fsn_mark);
6060

6161
assert_spin_locked(&fsn_mark->lock);
6262

63-
old_mask = fsn_mark->mask;
64-
new_mask = 0;
6563
for (dn = dn_mark->dn; dn != NULL; dn = dn->dn_next)
6664
new_mask |= (dn->dn_mask & ~FS_DN_MULTISHOT);
67-
fsnotify_set_mark_mask_locked(fsn_mark, new_mask);
68-
69-
if (old_mask == new_mask)
65+
if (fsn_mark->mask == new_mask)
7066
return;
67+
fsn_mark->mask = new_mask;
7168

72-
if (fsn_mark->inode)
73-
fsnotify_recalc_inode_mask(fsn_mark->inode);
69+
fsnotify_recalc_mask(fsn_mark->connector);
7470
}
7571

7672
/*
@@ -86,7 +82,8 @@ static int dnotify_handle_event(struct fsnotify_group *group,
8682
struct fsnotify_mark *inode_mark,
8783
struct fsnotify_mark *vfsmount_mark,
8884
u32 mask, const void *data, int data_type,
89-
const unsigned char *file_name, u32 cookie)
85+
const unsigned char *file_name, u32 cookie,
86+
struct fsnotify_iter_info *iter_info)
9087
{
9188
struct dnotify_mark *dn_mark;
9289
struct dnotify_struct *dn;
@@ -138,6 +135,7 @@ static void dnotify_free_mark(struct fsnotify_mark *fsn_mark)
138135

139136
static struct fsnotify_ops dnotify_fsnotify_ops = {
140137
.handle_event = dnotify_handle_event,
138+
.free_mark = dnotify_free_mark,
141139
};
142140

143141
/*
@@ -160,7 +158,7 @@ void dnotify_flush(struct file *filp, fl_owner_t id)
160158
if (!S_ISDIR(inode->i_mode))
161159
return;
162160

163-
fsn_mark = fsnotify_find_inode_mark(dnotify_group, inode);
161+
fsn_mark = fsnotify_find_mark(&inode->i_fsnotify_marks, dnotify_group);
164162
if (!fsn_mark)
165163
return;
166164
dn_mark = container_of(fsn_mark, struct dnotify_mark, fsn_mark);
@@ -308,21 +306,20 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg)
308306

309307
/* set up the new_fsn_mark and new_dn_mark */
310308
new_fsn_mark = &new_dn_mark->fsn_mark;
311-
fsnotify_init_mark(new_fsn_mark, dnotify_free_mark);
309+
fsnotify_init_mark(new_fsn_mark, dnotify_group);
312310
new_fsn_mark->mask = mask;
313311
new_dn_mark->dn = NULL;
314312

315313
/* this is needed to prevent the fcntl/close race described below */
316314
mutex_lock(&dnotify_group->mark_mutex);
317315

318316
/* add the new_fsn_mark or find an old one. */
319-
fsn_mark = fsnotify_find_inode_mark(dnotify_group, inode);
317+
fsn_mark = fsnotify_find_mark(&inode->i_fsnotify_marks, dnotify_group);
320318
if (fsn_mark) {
321319
dn_mark = container_of(fsn_mark, struct dnotify_mark, fsn_mark);
322320
spin_lock(&fsn_mark->lock);
323321
} else {
324-
fsnotify_add_mark_locked(new_fsn_mark, dnotify_group, inode,
325-
NULL, 0);
322+
fsnotify_add_mark_locked(new_fsn_mark, inode, NULL, 0);
326323
spin_lock(&new_fsn_mark->lock);
327324
fsn_mark = new_fsn_mark;
328325
dn_mark = new_dn_mark;

fs/notify/fanotify/fanotify.c

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,26 @@ static int fanotify_merge(struct list_head *list, struct fsnotify_event *event)
5757

5858
#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
5959
static int fanotify_get_response(struct fsnotify_group *group,
60-
struct fanotify_perm_event_info *event)
60+
struct fanotify_perm_event_info *event,
61+
struct fsnotify_iter_info *iter_info)
6162
{
6263
int ret;
6364

6465
pr_debug("%s: group=%p event=%p\n", __func__, group, event);
6566

67+
/*
68+
* fsnotify_prepare_user_wait() fails if we race with mark deletion.
69+
* Just let the operation pass in that case.
70+
*/
71+
if (!fsnotify_prepare_user_wait(iter_info)) {
72+
event->response = FAN_ALLOW;
73+
goto out;
74+
}
75+
6676
wait_event(group->fanotify_data.access_waitq, event->response);
6777

78+
fsnotify_finish_user_wait(iter_info);
79+
out:
6880
/* userspace responded, convert to something usable */
6981
switch (event->response) {
7082
case FAN_ALLOW:
@@ -174,7 +186,8 @@ static int fanotify_handle_event(struct fsnotify_group *group,
174186
struct fsnotify_mark *inode_mark,
175187
struct fsnotify_mark *fanotify_mark,
176188
u32 mask, const void *data, int data_type,
177-
const unsigned char *file_name, u32 cookie)
189+
const unsigned char *file_name, u32 cookie,
190+
struct fsnotify_iter_info *iter_info)
178191
{
179192
int ret = 0;
180193
struct fanotify_event_info *event;
@@ -215,7 +228,8 @@ static int fanotify_handle_event(struct fsnotify_group *group,
215228

216229
#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
217230
if (mask & FAN_ALL_PERM_EVENTS) {
218-
ret = fanotify_get_response(group, FANOTIFY_PE(fsn_event));
231+
ret = fanotify_get_response(group, FANOTIFY_PE(fsn_event),
232+
iter_info);
219233
fsnotify_destroy_event(group, fsn_event);
220234
}
221235
#endif
@@ -248,8 +262,14 @@ static void fanotify_free_event(struct fsnotify_event *fsn_event)
248262
kmem_cache_free(fanotify_event_cachep, event);
249263
}
250264

265+
static void fanotify_free_mark(struct fsnotify_mark *fsn_mark)
266+
{
267+
kmem_cache_free(fanotify_mark_cache, fsn_mark);
268+
}
269+
251270
const struct fsnotify_ops fanotify_fsnotify_ops = {
252271
.handle_event = fanotify_handle_event,
253272
.free_group_priv = fanotify_free_group_priv,
254273
.free_event = fanotify_free_event,
274+
.free_mark = fanotify_free_mark,
255275
};

fs/notify/fanotify/fanotify.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include <linux/path.h>
33
#include <linux/slab.h>
44

5+
extern struct kmem_cache *fanotify_mark_cache;
56
extern struct kmem_cache *fanotify_event_cachep;
67
extern struct kmem_cache *fanotify_perm_event_cachep;
78

0 commit comments

Comments
 (0)