From 066ca19b3d1c334f00950348799ceda1ec07461c Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Mon, 8 Nov 2010 18:15:08 -0500 Subject: fsnotify: inline mark refcnt functions Inline trivial mark put and get helpers. Signed-off-by: Tvrtko Ursulin Signed-off-by: Eric Paris --- include/linux/fsnotify_backend.h | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h index 7380763595d3..b07cb2fedee3 100644 --- a/include/linux/fsnotify_backend.h +++ b/include/linux/fsnotify_backend.h @@ -412,8 +412,6 @@ extern void fsnotify_clear_inode_marks_by_group(struct fsnotify_group *group); extern void fsnotify_clear_marks_by_group_flags(struct fsnotify_group *group, unsigned int flags); /* run all the marks in a group, and flag them to be freed */ extern void fsnotify_clear_marks_by_group(struct fsnotify_group *group); -extern void fsnotify_get_mark(struct fsnotify_mark *mark); -extern void fsnotify_put_mark(struct fsnotify_mark *mark); extern void fsnotify_unmount_inodes(struct list_head *list); /* put here because inotify does some weird stuff when destroying watches */ @@ -427,6 +425,16 @@ extern struct fsnotify_event *fsnotify_clone_event(struct fsnotify_event *old_ev extern int fsnotify_replace_event(struct fsnotify_event_holder *old_holder, struct fsnotify_event *new_event); +static inline void fsnotify_get_mark(struct fsnotify_mark *mark) +{ + atomic_inc(&mark->refcnt); +} + +static inline void fsnotify_put_mark(struct fsnotify_mark *mark) +{ + if (atomic_dec_and_test(&mark->refcnt)) + mark->free_mark(mark); +} #else static inline int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, -- cgit v1.2.3 From e3366737eeee6c3c482af3758c6dcb65eccfa62d Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Mon, 8 Nov 2010 19:32:57 -0500 Subject: fanotify: retry open RO if RW failes When a listener has requested read-write access to files, but such open failed, also try to open them read-only if requested. Signed-off-by: Tvrtko Ursulin Signed-off-by: Eric Paris --- fs/notify/fanotify/fanotify_user.c | 28 +++++++++++++++++++++++++--- include/linux/fanotify.h | 5 ++++- include/linux/fsnotify_backend.h | 1 + 3 files changed, 30 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c index 8b61220cffc5..88de980bcca1 100644 --- a/fs/notify/fanotify/fanotify_user.c +++ b/fs/notify/fanotify/fanotify_user.c @@ -62,6 +62,7 @@ static int create_fd(struct fsnotify_group *group, struct fsnotify_event *event) struct dentry *dentry; struct vfsmount *mnt; struct file *new_file; + unsigned int flags; pr_debug("%s: group=%p event=%p\n", __func__, group, event); @@ -83,12 +84,25 @@ static int create_fd(struct fsnotify_group *group, struct fsnotify_event *event) mnt = mntget(event->path.mnt); /* it's possible this event was an overflow event. in that case dentry and mnt * are NULL; That's fine, just don't call dentry open */ - if (dentry && mnt) + if (dentry && mnt) { + flags = group->fanotify_data.f_flags; new_file = dentry_open(dentry, mnt, - group->fanotify_data.f_flags | FMODE_NONOTIFY, + flags | FMODE_NONOTIFY, current_cred()); - else + /* + * Attempt fallback to read-only access if writable was not possible + * in order to at least provide something to the listener. + */ + if (IS_ERR(new_file) && group->fanotify_data.readonly_fallback) { + flags &= ~O_ACCMODE; + flags |= O_RDONLY; + new_file = dentry_open(dentry, mnt, + flags | FMODE_NONOTIFY, + current_cred()); + } + } else { new_file = ERR_PTR(-EOVERFLOW); + } if (IS_ERR(new_file)) { /* * we still send an event even if we can't open the file. this @@ -751,6 +765,14 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags) group->fanotify_data.max_marks = FANOTIFY_DEFAULT_MAX_MARKS; } + fd = -EINVAL; + if (flags & FAN_READONLY_FALLBACK) { + if ((event_f_flags & O_ACCMODE) == O_RDWR) + group->fanotify_data.readonly_fallback = true; + else + goto out_put_group; + } + fd = anon_inode_getfd("[fanotify]", &fanotify_fops, group, f_flags); if (fd < 0) goto out_put_group; diff --git a/include/linux/fanotify.h b/include/linux/fanotify.h index 6c6133f76e16..b5fac2ba4a07 100644 --- a/include/linux/fanotify.h +++ b/include/linux/fanotify.h @@ -36,9 +36,12 @@ #define FAN_UNLIMITED_QUEUE 0x00000010 #define FAN_UNLIMITED_MARKS 0x00000020 +/* Attempt read-only open if read-write failed. */ +#define FAN_READONLY_FALLBACK 0x00000040 + #define FAN_ALL_INIT_FLAGS (FAN_CLOEXEC | FAN_NONBLOCK | \ FAN_ALL_CLASS_BITS | FAN_UNLIMITED_QUEUE |\ - FAN_UNLIMITED_MARKS) + FAN_UNLIMITED_MARKS | FAN_READONLY_FALLBACK) /* flags used for fanotify_modify_mark() */ #define FAN_MARK_ADD 0x00000001 diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h index b07cb2fedee3..add135162427 100644 --- a/include/linux/fsnotify_backend.h +++ b/include/linux/fsnotify_backend.h @@ -168,6 +168,7 @@ struct fsnotify_group { wait_queue_head_t access_waitq; atomic_t bypass_perm; #endif /* CONFIG_FANOTIFY_ACCESS_PERMISSIONS */ + bool readonly_fallback; int f_flags; unsigned int max_marks; struct user_struct *user; -- cgit v1.2.3 From 4836781d2a0c82e3746411c2b415fb587413013c Mon Sep 17 00:00:00 2001 From: Lino Sanfilippo Date: Thu, 2 Dec 2010 11:01:48 +0100 Subject: fsnotify: introduce new group mutex This patch intoduces a group specific mutex that is used to synchronize all group related data/tasks for which no dedicated lock exists yet. Signed-off-by: Lino Sanfilippo Signed-off-by: Eric Paris --- fs/notify/group.c | 1 + include/linux/fsnotify_backend.h | 1 + 2 files changed, 2 insertions(+) (limited to 'include') diff --git a/fs/notify/group.c b/fs/notify/group.c index d309f38449cb..cc341d33f5c8 100644 --- a/fs/notify/group.c +++ b/fs/notify/group.c @@ -90,6 +90,7 @@ struct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops) */ atomic_set(&group->num_marks, 1); + mutex_init(&group->mutex); mutex_init(&group->notification_mutex); INIT_LIST_HEAD(&group->notification_list); init_waitqueue_head(&group->notification_waitq); diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h index add135162427..6a3c66051bc8 100644 --- a/include/linux/fsnotify_backend.h +++ b/include/linux/fsnotify_backend.h @@ -125,6 +125,7 @@ struct fsnotify_group { const struct fsnotify_ops *ops; /* how this group handles things */ + struct mutex mutex; /* needed to send notification to userspace */ struct mutex notification_mutex; /* protect the notification_list */ struct list_head notification_list; /* list of event_holder this group needs to send to userspace */ -- cgit v1.2.3