* [PATCH 2/8] fsnotify: provide the data type to should_send_event
2009-08-11 16:30 [PATCH 1/8] fsnotify: allow notification requests to not include private data Eric Paris
@ 2009-08-11 16:30 ` Eric Paris
2009-08-11 16:30 ` [PATCH 3/8] fsnotify: include data in should_send calls Eric Paris
` (5 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Eric Paris @ 2009-08-11 16:30 UTC (permalink / raw)
To: linux-kernel, linux-fsdevel, viro
fanotify is only interested in event types which contain enough information
to open the original file in the context of the fanotify listener. Since
fanotify may not want to send events if that data isn't present we pass
the data type to the should_send_event function call so fanotify can express
its lack of interest.
Signed-off-by: Eric Paris <eparis@redhat.com>
---
fs/notify/dnotify/dnotify.c | 3 ++-
fs/notify/fsnotify.c | 2 +-
fs/notify/inotify/inotify_fsnotify.c | 3 ++-
include/linux/fsnotify_backend.h | 3 ++-
kernel/audit_tree.c | 3 ++-
kernel/audit_watch.c | 3 ++-
6 files changed, 11 insertions(+), 6 deletions(-)
diff --git a/fs/notify/dnotify/dnotify.c b/fs/notify/dnotify/dnotify.c
index 6b71be9..7e979fb 100644
--- a/fs/notify/dnotify/dnotify.c
+++ b/fs/notify/dnotify/dnotify.c
@@ -132,7 +132,8 @@ static int dnotify_handle_event(struct fsnotify_group *group,
* userspace notification for that pair.
*/
static bool dnotify_should_send_event(struct fsnotify_group *group,
- struct inode *inode, __u32 mask)
+ struct inode *inode, __u32 mask,
+ int data_type)
{
struct fsnotify_mark_entry *entry;
bool send;
diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c
index 037e878..94a58ee 100644
--- a/fs/notify/fsnotify.c
+++ b/fs/notify/fsnotify.c
@@ -156,7 +156,7 @@ void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, const
idx = srcu_read_lock(&fsnotify_grp_srcu);
list_for_each_entry_rcu(group, &fsnotify_groups, group_list) {
if (test_mask & group->mask) {
- if (!group->ops->should_send_event(group, to_tell, mask))
+ if (!group->ops->should_send_event(group, to_tell, mask, data_is))
continue;
if (!event) {
event = fsnotify_create_event(to_tell, mask, data,
diff --git a/fs/notify/inotify/inotify_fsnotify.c b/fs/notify/inotify/inotify_fsnotify.c
index 47cd258..317998e 100644
--- a/fs/notify/inotify/inotify_fsnotify.c
+++ b/fs/notify/inotify/inotify_fsnotify.c
@@ -84,7 +84,8 @@ static void inotify_freeing_mark(struct fsnotify_mark_entry *entry, struct fsnot
inotify_ignored_and_remove_idr(entry, group);
}
-static bool inotify_should_send_event(struct fsnotify_group *group, struct inode *inode, __u32 mask)
+static bool inotify_should_send_event(struct fsnotify_group *group, struct inode *inode,
+ __u32 mask, int data_type)
{
struct fsnotify_mark_entry *entry;
bool send;
diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h
index e252843..61aed0c 100644
--- a/include/linux/fsnotify_backend.h
+++ b/include/linux/fsnotify_backend.h
@@ -84,7 +84,8 @@ struct fsnotify_event_private_data;
* valid group and inode to use to clean up.
*/
struct fsnotify_ops {
- bool (*should_send_event)(struct fsnotify_group *group, struct inode *inode, __u32 mask);
+ bool (*should_send_event)(struct fsnotify_group *group, struct inode *inode,
+ __u32 mask, int data_type);
int (*handle_event)(struct fsnotify_group *group, struct fsnotify_event *event);
void (*free_group_priv)(struct fsnotify_group *group);
void (*freeing_mark)(struct fsnotify_mark_entry *entry, struct fsnotify_group *group);
diff --git a/kernel/audit_tree.c b/kernel/audit_tree.c
index 184ca3f..c15af4a 100644
--- a/kernel/audit_tree.c
+++ b/kernel/audit_tree.c
@@ -958,7 +958,8 @@ static void audit_tree_freeing_mark(struct fsnotify_mark_entry *entry, struct fs
fsnotify_put_mark(entry);
}
-static bool audit_tree_send_event(struct fsnotify_group *group, struct inode *inode, __u32 mask)
+static bool audit_tree_send_event(struct fsnotify_group *group, struct inode *inode,
+ __u32 mask, int data_type)
{
return 0;
}
diff --git a/kernel/audit_watch.c b/kernel/audit_watch.c
index aa8babc..fa37460 100644
--- a/kernel/audit_watch.c
+++ b/kernel/audit_watch.c
@@ -504,7 +504,8 @@ void audit_remove_watch_rule(struct audit_krule *krule)
}
}
-static bool audit_watch_should_send_event(struct fsnotify_group *group, struct inode *inode, __u32 mask)
+static bool audit_watch_should_send_event(struct fsnotify_group *group, struct inode *inode,
+ __u32 mask, int data_type)
{
struct fsnotify_mark_entry *entry;
bool send;
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 3/8] fsnotify: include data in should_send calls
2009-08-11 16:30 [PATCH 1/8] fsnotify: allow notification requests to not include private data Eric Paris
2009-08-11 16:30 ` [PATCH 2/8] fsnotify: provide the data type to should_send_event Eric Paris
@ 2009-08-11 16:30 ` Eric Paris
2009-08-11 16:30 ` [PATCH 4/8] fsnotify: pass a file instead of an inode to open, read, and write Eric Paris
` (4 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Eric Paris @ 2009-08-11 16:30 UTC (permalink / raw)
To: linux-kernel, linux-fsdevel, viro
fanotify is going to need to look at file->private_data to know if an event
should be sent or not. This passes the data (which might be a file,
dentry, inode, or none) to the should_send function calls so fanotify can
get that information when available
Signed-off-by: Eric Paris <eparis@redhat.com>
---
fs/notify/dnotify/dnotify.c | 2 +-
fs/notify/fsnotify.c | 3 ++-
fs/notify/inotify/inotify_fsnotify.c | 2 +-
include/linux/fsnotify_backend.h | 2 +-
kernel/audit_tree.c | 2 +-
kernel/audit_watch.c | 2 +-
6 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/fs/notify/dnotify/dnotify.c b/fs/notify/dnotify/dnotify.c
index 7e979fb..c28c38f 100644
--- a/fs/notify/dnotify/dnotify.c
+++ b/fs/notify/dnotify/dnotify.c
@@ -133,7 +133,7 @@ static int dnotify_handle_event(struct fsnotify_group *group,
*/
static bool dnotify_should_send_event(struct fsnotify_group *group,
struct inode *inode, __u32 mask,
- int data_type)
+ void *data, int data_type)
{
struct fsnotify_mark_entry *entry;
bool send;
diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c
index 94a58ee..b98be4a 100644
--- a/fs/notify/fsnotify.c
+++ b/fs/notify/fsnotify.c
@@ -156,7 +156,8 @@ void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, const
idx = srcu_read_lock(&fsnotify_grp_srcu);
list_for_each_entry_rcu(group, &fsnotify_groups, group_list) {
if (test_mask & group->mask) {
- if (!group->ops->should_send_event(group, to_tell, mask, data_is))
+ if (!group->ops->should_send_event(group, to_tell, mask,
+ data, data_is))
continue;
if (!event) {
event = fsnotify_create_event(to_tell, mask, data,
diff --git a/fs/notify/inotify/inotify_fsnotify.c b/fs/notify/inotify/inotify_fsnotify.c
index 317998e..743d8fa 100644
--- a/fs/notify/inotify/inotify_fsnotify.c
+++ b/fs/notify/inotify/inotify_fsnotify.c
@@ -85,7 +85,7 @@ static void inotify_freeing_mark(struct fsnotify_mark_entry *entry, struct fsnot
}
static bool inotify_should_send_event(struct fsnotify_group *group, struct inode *inode,
- __u32 mask, int data_type)
+ __u32 mask, void *data, int data_type)
{
struct fsnotify_mark_entry *entry;
bool send;
diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h
index 61aed0c..2766df6 100644
--- a/include/linux/fsnotify_backend.h
+++ b/include/linux/fsnotify_backend.h
@@ -85,7 +85,7 @@ struct fsnotify_event_private_data;
*/
struct fsnotify_ops {
bool (*should_send_event)(struct fsnotify_group *group, struct inode *inode,
- __u32 mask, int data_type);
+ __u32 mask, void *data, int data_type);
int (*handle_event)(struct fsnotify_group *group, struct fsnotify_event *event);
void (*free_group_priv)(struct fsnotify_group *group);
void (*freeing_mark)(struct fsnotify_mark_entry *entry, struct fsnotify_group *group);
diff --git a/kernel/audit_tree.c b/kernel/audit_tree.c
index c15af4a..295c03c 100644
--- a/kernel/audit_tree.c
+++ b/kernel/audit_tree.c
@@ -959,7 +959,7 @@ static void audit_tree_freeing_mark(struct fsnotify_mark_entry *entry, struct fs
}
static bool audit_tree_send_event(struct fsnotify_group *group, struct inode *inode,
- __u32 mask, int data_type)
+ __u32 mask, void *data, int data_type)
{
return 0;
}
diff --git a/kernel/audit_watch.c b/kernel/audit_watch.c
index fa37460..6056aca 100644
--- a/kernel/audit_watch.c
+++ b/kernel/audit_watch.c
@@ -505,7 +505,7 @@ void audit_remove_watch_rule(struct audit_krule *krule)
}
static bool audit_watch_should_send_event(struct fsnotify_group *group, struct inode *inode,
- __u32 mask, int data_type)
+ __u32 mask, void *data, int data_type)
{
struct fsnotify_mark_entry *entry;
bool send;
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 4/8] fsnotify: pass a file instead of an inode to open, read, and write
2009-08-11 16:30 [PATCH 1/8] fsnotify: allow notification requests to not include private data Eric Paris
2009-08-11 16:30 ` [PATCH 2/8] fsnotify: provide the data type to should_send_event Eric Paris
2009-08-11 16:30 ` [PATCH 3/8] fsnotify: include data in should_send calls Eric Paris
@ 2009-08-11 16:30 ` Eric Paris
2009-08-11 16:30 ` [PATCH 5/8] fsnotify: send struct file when sending events to parents when possible Eric Paris
` (3 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Eric Paris @ 2009-08-11 16:30 UTC (permalink / raw)
To: linux-kernel, linux-fsdevel, viro
fanotify, the upcoming notification system actually needs a struct path so it can
do opens in the context of listeners, and it needs a file so it can get f_flags
from the original process. Close was the only operation that already was passing
a struct file to the notification hook. This patch passes a file for access,
modify, and open as well as they are easily available to these hooks.
Signed-off-by: Eric Paris <eparis@redhat.com>
---
fs/compat.c | 5 ++---
fs/exec.c | 4 ++--
fs/nfsd/vfs.c | 4 ++--
fs/open.c | 2 +-
fs/read_write.c | 8 ++++----
include/linux/fsnotify.h | 15 +++++++++------
6 files changed, 20 insertions(+), 18 deletions(-)
diff --git a/fs/compat.c b/fs/compat.c
index 94502da..1465b80 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -1177,11 +1177,10 @@ out:
if (iov != iovstack)
kfree(iov);
if ((ret + (type == READ)) > 0) {
- struct dentry *dentry = file->f_path.dentry;
if (type == READ)
- fsnotify_access(dentry);
+ fsnotify_access(file);
else
- fsnotify_modify(dentry);
+ fsnotify_modify(file);
}
return ret;
}
diff --git a/fs/exec.c b/fs/exec.c
index 4a8849e..12b1d4e 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -128,7 +128,7 @@ SYSCALL_DEFINE1(uselib, const char __user *, library)
if (file->f_path.mnt->mnt_flags & MNT_NOEXEC)
goto exit;
- fsnotify_open(file->f_path.dentry);
+ fsnotify_open(file);
error = -ENOEXEC;
if(file->f_op) {
@@ -663,7 +663,7 @@ struct file *open_exec(const char *name)
if (file->f_path.mnt->mnt_flags & MNT_NOEXEC)
goto exit;
- fsnotify_open(file->f_path.dentry);
+ fsnotify_open(file);
err = deny_write_access(file);
if (err)
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 23341c1..5c8f67e 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -948,7 +948,7 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
nfsdstats.io_read += host_err;
*count = host_err;
err = 0;
- fsnotify_access(file->f_path.dentry);
+ fsnotify_access(file);
} else
err = nfserrno(host_err);
out:
@@ -1059,7 +1059,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
goto out_nfserr;
*cnt = host_err;
nfsdstats.io_write += host_err;
- fsnotify_modify(file->f_path.dentry);
+ fsnotify_modify(file);
/* clear setuid/setgid flag after write */
if (inode->i_mode & (S_ISUID | S_ISGID))
diff --git a/fs/open.c b/fs/open.c
index dd98e80..650ae9f 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -1038,7 +1038,7 @@ long do_sys_open(int dfd, const char __user *filename, int flags, int mode)
put_unused_fd(fd);
fd = PTR_ERR(f);
} else {
- fsnotify_open(f->f_path.dentry);
+ fsnotify_open(f);
fd_install(fd, f);
}
}
diff --git a/fs/read_write.c b/fs/read_write.c
index 6c8c55d..c7479e9 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -293,7 +293,7 @@ ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
else
ret = do_sync_read(file, buf, count, pos);
if (ret > 0) {
- fsnotify_access(file->f_path.dentry);
+ fsnotify_access(file);
add_rchar(current, ret);
}
inc_syscr(current);
@@ -348,7 +348,7 @@ ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_
else
ret = do_sync_write(file, buf, count, pos);
if (ret > 0) {
- fsnotify_modify(file->f_path.dentry);
+ fsnotify_modify(file);
add_wchar(current, ret);
}
inc_syscw(current);
@@ -656,9 +656,9 @@ out:
kfree(iov);
if ((ret + (type == READ)) > 0) {
if (type == READ)
- fsnotify_access(file->f_path.dentry);
+ fsnotify_access(file);
else
- fsnotify_modify(file->f_path.dentry);
+ fsnotify_modify(file);
}
return ret;
}
diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h
index 936f9aa..36357a4 100644
--- a/include/linux/fsnotify.h
+++ b/include/linux/fsnotify.h
@@ -183,8 +183,9 @@ static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry)
/*
* fsnotify_access - file was read
*/
-static inline void fsnotify_access(struct dentry *dentry)
+static inline void fsnotify_access(struct file *file)
{
+ struct dentry *dentry = file->f_path.dentry;
struct inode *inode = dentry->d_inode;
__u32 mask = FS_ACCESS;
@@ -194,14 +195,15 @@ static inline void fsnotify_access(struct dentry *dentry)
inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
fsnotify_parent(dentry, mask);
- fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
+ fsnotify(inode, mask, file, FSNOTIFY_EVENT_FILE, NULL, 0);
}
/*
* fsnotify_modify - file was modified
*/
-static inline void fsnotify_modify(struct dentry *dentry)
+static inline void fsnotify_modify(struct file *file)
{
+ struct dentry *dentry = file->f_path.dentry;
struct inode *inode = dentry->d_inode;
__u32 mask = FS_MODIFY;
@@ -211,14 +213,15 @@ static inline void fsnotify_modify(struct dentry *dentry)
inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
fsnotify_parent(dentry, mask);
- fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
+ fsnotify(inode, mask, file, FSNOTIFY_EVENT_FILE, NULL, 0);
}
/*
* fsnotify_open - file was opened
*/
-static inline void fsnotify_open(struct dentry *dentry)
+static inline void fsnotify_open(struct file *file)
{
+ struct dentry *dentry = file->f_path.dentry;
struct inode *inode = dentry->d_inode;
__u32 mask = FS_OPEN;
@@ -228,7 +231,7 @@ static inline void fsnotify_open(struct dentry *dentry)
inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
fsnotify_parent(dentry, mask);
- fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
+ fsnotify(inode, mask, file, FSNOTIFY_EVENT_FILE, NULL, 0);
}
/*
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 5/8] fsnotify: send struct file when sending events to parents when possible
2009-08-11 16:30 [PATCH 1/8] fsnotify: allow notification requests to not include private data Eric Paris
` (2 preceding siblings ...)
2009-08-11 16:30 ` [PATCH 4/8] fsnotify: pass a file instead of an inode to open, read, and write Eric Paris
@ 2009-08-11 16:30 ` Eric Paris
2009-08-11 16:30 ` [PATCH 6/8] fsnotify: per group notification queue merge types Eric Paris
` (2 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Eric Paris @ 2009-08-11 16:30 UTC (permalink / raw)
To: linux-kernel, linux-fsdevel, viro
fanotify needs a path in order to open an fd to the object which changed.
Currently notifications to inode's parents are done using only the inode.
For some parental notification we have the entire file, send that so
fanotify can use it.
Signed-off-by: Eric Paris <eparis@redhat.com>
---
fs/notify/fsnotify.c | 13 ++++++++++---
include/linux/fsnotify.h | 35 ++++++++++++++++++-----------------
include/linux/fsnotify_backend.h | 4 ++--
3 files changed, 30 insertions(+), 22 deletions(-)
diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c
index b98be4a..d4b0272 100644
--- a/fs/notify/fsnotify.c
+++ b/fs/notify/fsnotify.c
@@ -77,13 +77,16 @@ void __fsnotify_update_child_dentry_flags(struct inode *inode)
}
/* Notify this dentry's parent about a child's events. */
-void __fsnotify_parent(struct dentry *dentry, __u32 mask)
+void __fsnotify_parent(struct file *file, struct dentry *dentry, __u32 mask)
{
struct dentry *parent;
struct inode *p_inode;
bool send = false;
bool should_update_children = false;
+ if (file)
+ dentry = file->f_path.dentry;
+
if (!(dentry->d_flags & DCACHE_FSNOTIFY_PARENT_WATCHED))
return;
@@ -114,8 +117,12 @@ void __fsnotify_parent(struct dentry *dentry, __u32 mask)
* specifies these are events which came from a child. */
mask |= FS_EVENT_ON_CHILD;
- fsnotify(p_inode, mask, dentry->d_inode, FSNOTIFY_EVENT_INODE,
- dentry->d_name.name, 0);
+ if (file)
+ fsnotify(p_inode, mask, file, FSNOTIFY_EVENT_FILE,
+ dentry->d_name.name, 0);
+ else
+ fsnotify(p_inode, mask, dentry->d_inode, FSNOTIFY_EVENT_INODE,
+ dentry->d_name.name, 0);
dput(parent);
}
diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h
index 36357a4..c0de28b 100644
--- a/include/linux/fsnotify.h
+++ b/include/linux/fsnotify.h
@@ -29,9 +29,14 @@ static inline void fsnotify_d_instantiate(struct dentry *entry,
}
/* Notify this dentry's parent about a child's events. */
-static inline void fsnotify_parent(struct dentry *dentry, __u32 mask)
+static inline void fsnotify_parent(struct file *file, struct dentry *dentry, __u32 mask)
{
- __fsnotify_parent(dentry, mask);
+ BUG_ON(file && dentry);
+
+ if (file)
+ dentry = file->f_path.dentry;
+
+ __fsnotify_parent(file, dentry, mask);
inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name);
}
@@ -124,7 +129,7 @@ static inline void fsnotify_nameremove(struct dentry *dentry, int isdir)
if (isdir)
mask |= FS_IN_ISDIR;
- fsnotify_parent(dentry, mask);
+ fsnotify_parent(NULL, dentry, mask);
}
/*
@@ -185,8 +190,7 @@ static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry)
*/
static inline void fsnotify_access(struct file *file)
{
- struct dentry *dentry = file->f_path.dentry;
- struct inode *inode = dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
__u32 mask = FS_ACCESS;
if (S_ISDIR(inode->i_mode))
@@ -194,7 +198,7 @@ static inline void fsnotify_access(struct file *file)
inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
- fsnotify_parent(dentry, mask);
+ fsnotify_parent(file, NULL, mask);
fsnotify(inode, mask, file, FSNOTIFY_EVENT_FILE, NULL, 0);
}
@@ -203,8 +207,7 @@ static inline void fsnotify_access(struct file *file)
*/
static inline void fsnotify_modify(struct file *file)
{
- struct dentry *dentry = file->f_path.dentry;
- struct inode *inode = dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
__u32 mask = FS_MODIFY;
if (S_ISDIR(inode->i_mode))
@@ -212,7 +215,7 @@ static inline void fsnotify_modify(struct file *file)
inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
- fsnotify_parent(dentry, mask);
+ fsnotify_parent(file, NULL, mask);
fsnotify(inode, mask, file, FSNOTIFY_EVENT_FILE, NULL, 0);
}
@@ -221,8 +224,7 @@ static inline void fsnotify_modify(struct file *file)
*/
static inline void fsnotify_open(struct file *file)
{
- struct dentry *dentry = file->f_path.dentry;
- struct inode *inode = dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
__u32 mask = FS_OPEN;
if (S_ISDIR(inode->i_mode))
@@ -230,7 +232,7 @@ static inline void fsnotify_open(struct file *file)
inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
- fsnotify_parent(dentry, mask);
+ fsnotify_parent(file, NULL, mask);
fsnotify(inode, mask, file, FSNOTIFY_EVENT_FILE, NULL, 0);
}
@@ -239,8 +241,7 @@ static inline void fsnotify_open(struct file *file)
*/
static inline void fsnotify_close(struct file *file)
{
- struct dentry *dentry = file->f_path.dentry;
- struct inode *inode = dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
fmode_t mode = file->f_mode;
__u32 mask = (mode & FMODE_WRITE) ? FS_CLOSE_WRITE : FS_CLOSE_NOWRITE;
@@ -249,7 +250,7 @@ static inline void fsnotify_close(struct file *file)
inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
- fsnotify_parent(dentry, mask);
+ fsnotify_parent(file, NULL, mask);
fsnotify(inode, mask, file, FSNOTIFY_EVENT_FILE, NULL, 0);
}
@@ -266,7 +267,7 @@ static inline void fsnotify_xattr(struct dentry *dentry)
inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
- fsnotify_parent(dentry, mask);
+ fsnotify_parent(NULL, dentry, mask);
fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
}
@@ -302,7 +303,7 @@ static inline void fsnotify_change(struct dentry *dentry, unsigned int ia_valid)
mask |= FS_IN_ISDIR;
inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
- fsnotify_parent(dentry, mask);
+ fsnotify_parent(NULL, dentry, mask);
fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
}
}
diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h
index 2766df6..0e0c2b7 100644
--- a/include/linux/fsnotify_backend.h
+++ b/include/linux/fsnotify_backend.h
@@ -259,7 +259,7 @@ struct fsnotify_mark_entry {
/* main fsnotify call to send events */
extern void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is,
const char *name, u32 cookie);
-extern void __fsnotify_parent(struct dentry *dentry, __u32 mask);
+extern void __fsnotify_parent(struct file *file, struct dentry *dentry, __u32 mask);
extern void __fsnotify_inode_delete(struct inode *inode);
extern u32 fsnotify_get_cookie(void);
@@ -367,7 +367,7 @@ static inline void fsnotify(struct inode *to_tell, __u32 mask, void *data, int d
const char *name, u32 cookie)
{}
-static inline void __fsnotify_parent(struct dentry *dentry, __u32 mask)
+static inline void __fsnotify_parent(struct file *file, struct dentry *dentry, __u32 mask)
{}
static inline void __fsnotify_inode_delete(struct inode *inode)
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 6/8] fsnotify: per group notification queue merge types
2009-08-11 16:30 [PATCH 1/8] fsnotify: allow notification requests to not include private data Eric Paris
` (3 preceding siblings ...)
2009-08-11 16:30 ` [PATCH 5/8] fsnotify: send struct file when sending events to parents when possible Eric Paris
@ 2009-08-11 16:30 ` Eric Paris
2009-08-11 16:30 ` [PATCH 7/8] fsnotify: clone existing events Eric Paris
2009-08-11 16:30 ` [PATCH 8/8] fsnotify: replace an event on a list Eric Paris
6 siblings, 0 replies; 8+ messages in thread
From: Eric Paris @ 2009-08-11 16:30 UTC (permalink / raw)
To: linux-kernel, linux-fsdevel, viro
inotify only wishes to merge a new event with the last event on the
notification fifo. fanotify is willing to merge any events including by
means of bitwise OR masks of multiple events together. This patch moves
the inotify event merging logic out of the generic fsnotify notification.c
and into the inotify code. This allows each use of fsnotify to provide
their own merge functionality.
Signed-off-by: Eric Paris <eparis@redhat.com>
---
fs/notify/inotify/inotify_fsnotify.c | 52 ++++++++++++++++++++++++++++
fs/notify/inotify/inotify_user.c | 2 +
fs/notify/notification.c | 63 +++++++++-------------------------
include/linux/fsnotify_backend.h | 6 ++-
4 files changed, 72 insertions(+), 51 deletions(-)
diff --git a/fs/notify/inotify/inotify_fsnotify.c b/fs/notify/inotify/inotify_fsnotify.c
index 743d8fa..133f080 100644
--- a/fs/notify/inotify/inotify_fsnotify.c
+++ b/fs/notify/inotify/inotify_fsnotify.c
@@ -31,6 +31,56 @@
#include "inotify.h"
+/*
+ * Check if 2 events contain the same information. We do not compare private data
+ * but at this moment that isn't a problem for any know fsnotify listeners.
+ */
+static bool event_compare(struct fsnotify_event *old, struct fsnotify_event *new)
+{
+ if ((old->mask == new->mask) &&
+ (old->to_tell == new->to_tell) &&
+ (old->data_type == new->data_type) &&
+ (old->name_len == new->name_len)) {
+ switch (old->data_type) {
+ case (FSNOTIFY_EVENT_INODE):
+ /* remember, after old was put on the wait_q we aren't
+ * allowed to look at the inode any more, only thing
+ * left to check was if the file_name is the same */
+ if (old->name_len &&
+ !strcmp(old->file_name, new->file_name))
+ return true;
+ break;
+ case (FSNOTIFY_EVENT_PATH):
+ if ((old->path.mnt == new->path.mnt) &&
+ (old->path.dentry == new->path.dentry))
+ return true;
+ break;
+ case (FSNOTIFY_EVENT_NONE):
+ return true;
+ };
+ }
+ return false;
+}
+
+static int inotify_merge(struct list_head *list, struct fsnotify_event *event)
+{
+ struct fsnotify_event_holder *last_holder;
+ struct fsnotify_event *last_event;
+ int ret = 0;
+
+ /* and the list better be locked by something too */
+ spin_lock(&event->lock);
+
+ last_holder = list_entry(list->prev, struct fsnotify_event_holder, event_list);
+ last_event = last_holder->event;
+ if (event_compare(last_event, event))
+ ret = -EEXIST;
+
+ spin_unlock(&event->lock);
+
+ return ret;
+}
+
static int inotify_handle_event(struct fsnotify_group *group, struct fsnotify_event *event)
{
struct fsnotify_mark_entry *entry;
@@ -61,7 +111,7 @@ static int inotify_handle_event(struct fsnotify_group *group, struct fsnotify_ev
fsn_event_priv->group = group;
event_priv->wd = wd;
- ret = fsnotify_add_notify_event(group, event, fsn_event_priv);
+ ret = fsnotify_add_notify_event(group, event, fsn_event_priv, inotify_merge);
/* EEXIST is not an error */
if (ret == -EEXIST)
ret = 0;
diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c
index fb38e73..d5e78f6 100644
--- a/fs/notify/inotify/inotify_user.c
+++ b/fs/notify/inotify/inotify_user.c
@@ -401,7 +401,7 @@ void inotify_ignored_and_remove_idr(struct fsnotify_mark_entry *entry,
fsn_event_priv->group = group;
event_priv->wd = ientry->wd;
- fsnotify_add_notify_event(group, ignored_event, fsn_event_priv);
+ fsnotify_add_notify_event(group, ignored_event, fsn_event_priv, NULL);
/* did the private data get added? */
if (list_empty(&fsn_event_priv->event_list))
diff --git a/fs/notify/notification.c b/fs/notify/notification.c
index cdf203c..bcf6fde 100644
--- a/fs/notify/notification.c
+++ b/fs/notify/notification.c
@@ -104,7 +104,8 @@ struct fsnotify_event_holder *fsnotify_alloc_event_holder(void)
void fsnotify_destroy_event_holder(struct fsnotify_event_holder *holder)
{
- kmem_cache_free(fsnotify_event_holder_cachep, holder);
+ if (holder)
+ kmem_cache_free(fsnotify_event_holder_cachep, holder);
}
/*
@@ -129,48 +130,16 @@ struct fsnotify_event_private_data *fsnotify_remove_priv_from_event(struct fsnot
}
/*
- * Check if 2 events contain the same information. We do not compare private data
- * but at this moment that isn't a problem for any know fsnotify listeners.
- */
-static bool event_compare(struct fsnotify_event *old, struct fsnotify_event *new)
-{
- if ((old->mask == new->mask) &&
- (old->to_tell == new->to_tell) &&
- (old->data_type == new->data_type) &&
- (old->name_len == new->name_len)) {
- switch (old->data_type) {
- case (FSNOTIFY_EVENT_INODE):
- /* remember, after old was put on the wait_q we aren't
- * allowed to look at the inode any more, only thing
- * left to check was if the file_name is the same */
- if (old->name_len &&
- !strcmp(old->file_name, new->file_name))
- return true;
- break;
- case (FSNOTIFY_EVENT_PATH):
- if ((old->path.mnt == new->path.mnt) &&
- (old->path.dentry == new->path.dentry))
- return true;
- break;
- case (FSNOTIFY_EVENT_NONE):
- return false;
- };
- }
- return false;
-}
-
-/*
* Add an event to the group notification queue. The group can later pull this
* event off the queue to deal with. If the event is successfully added to the
* group's notification queue, a reference is taken on event.
*/
int fsnotify_add_notify_event(struct fsnotify_group *group, struct fsnotify_event *event,
- struct fsnotify_event_private_data *priv)
+ struct fsnotify_event_private_data *priv,
+ int (*merge)(struct list_head *, struct fsnotify_event *))
{
struct fsnotify_event_holder *holder = NULL;
struct list_head *list = &group->notification_list;
- struct fsnotify_event_holder *last_holder;
- struct fsnotify_event *last_event;
/* easy to tell if priv was attached to the event */
if (priv)
@@ -199,6 +168,18 @@ alloc_holder:
priv = NULL;
}
+ if (!list_empty(list) && merge) {
+ int ret;
+
+ ret = merge(list, event);
+ if (ret) {
+ mutex_unlock(&group->notification_mutex);
+ if (holder != &event->holder)
+ fsnotify_destroy_event_holder(holder);
+ return ret;
+ }
+ }
+
spin_lock(&event->lock);
if (list_empty(&event->holder.event_list)) {
@@ -213,18 +194,6 @@ alloc_holder:
goto alloc_holder;
}
- if (!list_empty(list)) {
- last_holder = list_entry(list->prev, struct fsnotify_event_holder, event_list);
- last_event = last_holder->event;
- if (event_compare(last_event, event)) {
- spin_unlock(&event->lock);
- mutex_unlock(&group->notification_mutex);
- if (holder != &event->holder)
- fsnotify_destroy_event_holder(holder);
- return -EEXIST;
- }
- }
-
group->q_len++;
holder->event = event;
diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h
index 0e0c2b7..25789d4 100644
--- a/include/linux/fsnotify_backend.h
+++ b/include/linux/fsnotify_backend.h
@@ -328,8 +328,10 @@ extern struct fsnotify_event_private_data *fsnotify_remove_priv_from_event(struc
struct fsnotify_event *event);
/* attach the event to the group notification queue */
-extern int fsnotify_add_notify_event(struct fsnotify_group *group, struct fsnotify_event *event,
- struct fsnotify_event_private_data *priv);
+extern int fsnotify_add_notify_event(struct fsnotify_group *group,
+ struct fsnotify_event *event,
+ struct fsnotify_event_private_data *priv,
+ int (*merge)(struct list_head *, struct fsnotify_event *));
/* true if the group notification queue is empty */
extern bool fsnotify_notify_queue_is_empty(struct fsnotify_group *group);
/* return, but do not dequeue the first event on the notification queue */
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 7/8] fsnotify: clone existing events
2009-08-11 16:30 [PATCH 1/8] fsnotify: allow notification requests to not include private data Eric Paris
` (4 preceding siblings ...)
2009-08-11 16:30 ` [PATCH 6/8] fsnotify: per group notification queue merge types Eric Paris
@ 2009-08-11 16:30 ` Eric Paris
2009-08-11 16:30 ` [PATCH 8/8] fsnotify: replace an event on a list Eric Paris
6 siblings, 0 replies; 8+ messages in thread
From: Eric Paris @ 2009-08-11 16:30 UTC (permalink / raw)
To: linux-kernel, linux-fsdevel, viro
fsnotify_clone_event will take an event, clone it, and return the cloned
event to the caller. Since events may be in use by multiple fsnotify
groups simultaneously certain event entries (such as the mask) cannot be
changed after the event was created. Since fanotify would like to merge
events happening on the same file it needs a new clean event to work with
so it can change any fields it wishes.
Signed-off-by: Eric Paris <eparis@redhat.com>
---
fs/notify/notification.c | 29 +++++++++++++++++++++++++----
include/linux/fsnotify_backend.h | 3 +++
2 files changed, 28 insertions(+), 4 deletions(-)
diff --git a/fs/notify/notification.c b/fs/notify/notification.c
index bcf6fde..4fb1399 100644
--- a/fs/notify/notification.c
+++ b/fs/notify/notification.c
@@ -286,11 +286,33 @@ static void initialize_event(struct fsnotify_event *event)
spin_lock_init(&event->lock);
- event->data_type = FSNOTIFY_EVENT_NONE;
-
INIT_LIST_HEAD(&event->private_data_list);
}
+struct fsnotify_event *fsnotify_clone_event(struct fsnotify_event *old_event)
+{
+ struct fsnotify_event *event;
+
+ event = kmem_cache_alloc(fsnotify_event_cachep, GFP_KERNEL);
+ if (!event)
+ return NULL;
+
+ memcpy(event, old_event, sizeof(*event));
+ initialize_event(event);
+
+ if (event->name_len) {
+ event->file_name = kstrdup(old_event->file_name, GFP_KERNEL);
+ if (!event->file_name) {
+ kmem_cache_free(fsnotify_event_cachep, event);
+ return NULL;
+ }
+ }
+ if (event->data_type == FSNOTIFY_EVENT_PATH)
+ path_get(&event->path);
+
+ return event;
+}
+
/*
* fsnotify_create_event - Allocate a new event which will be sent to each
* group's handle_event function if the group was interested in this
@@ -326,6 +348,7 @@ struct fsnotify_event *fsnotify_create_event(struct inode *to_tell, __u32 mask,
event->sync_cookie = cookie;
event->to_tell = to_tell;
+ event->data_type = data_type;
switch (data_type) {
case FSNOTIFY_EVENT_FILE: {
@@ -342,12 +365,10 @@ struct fsnotify_event *fsnotify_create_event(struct inode *to_tell, __u32 mask,
event->path.dentry = path->dentry;
event->path.mnt = path->mnt;
path_get(&event->path);
- event->data_type = FSNOTIFY_EVENT_PATH;
break;
}
case FSNOTIFY_EVENT_INODE:
event->inode = data;
- event->data_type = FSNOTIFY_EVENT_INODE;
break;
case FSNOTIFY_EVENT_NONE:
event->inode = NULL;
diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h
index 25789d4..3a7fff2 100644
--- a/include/linux/fsnotify_backend.h
+++ b/include/linux/fsnotify_backend.h
@@ -363,6 +363,9 @@ extern struct fsnotify_event *fsnotify_create_event(struct inode *to_tell, __u32
void *data, int data_is, const char *name,
u32 cookie, gfp_t gfp);
+/* fanotify likes to change events after they are on lists... */
+extern struct fsnotify_event *fsnotify_clone_event(struct fsnotify_event *old_event);
+
#else
static inline void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is,
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 8/8] fsnotify: replace an event on a list
2009-08-11 16:30 [PATCH 1/8] fsnotify: allow notification requests to not include private data Eric Paris
` (5 preceding siblings ...)
2009-08-11 16:30 ` [PATCH 7/8] fsnotify: clone existing events Eric Paris
@ 2009-08-11 16:30 ` Eric Paris
6 siblings, 0 replies; 8+ messages in thread
From: Eric Paris @ 2009-08-11 16:30 UTC (permalink / raw)
To: linux-kernel, linux-fsdevel, viro
fanotify would like to clone events already on its notification list, make
changes to the new event, and then replace the old event on the list with
the new event. This patch implements the replace functionality of that
process.
Signed-off-by: Eric Paris <eparis@redhat.com>
---
fs/notify/notification.c | 56 ++++++++++++++++++++++++++++++++++++++
include/linux/fsnotify_backend.h | 2 +
2 files changed, 58 insertions(+), 0 deletions(-)
diff --git a/fs/notify/notification.c b/fs/notify/notification.c
index 4fb1399..4f69b6f 100644
--- a/fs/notify/notification.c
+++ b/fs/notify/notification.c
@@ -289,6 +289,62 @@ static void initialize_event(struct fsnotify_event *event)
INIT_LIST_HEAD(&event->private_data_list);
}
+/*
+ * Caller damn well better be holding whatever mutex is protecting the
+ * old_holder->event_list.
+ */
+int fsnotify_replace_event(struct fsnotify_event_holder *old_holder,
+ struct fsnotify_event *new_event)
+{
+ struct fsnotify_event *old_event = old_holder->event;
+ struct fsnotify_event_holder *new_holder = NULL;
+
+ /*
+ * There is one fsnotify_event_holder embedded inside each fsnotify_event.
+ * Check if we expect to be able to use that holder. If not alloc a new
+ * holder.
+ * For the overflow event it's possible that something will use the in
+ * event holder before we get the lock so we may need to jump back and
+ * alloc a new holder, this can't happen for most events...
+ */
+ if (!list_empty(&new_event->holder.event_list)) {
+alloc_holder:
+ new_holder = fsnotify_alloc_event_holder();
+ if (!new_holder)
+ return -ENOMEM;
+ }
+
+ spin_lock(&old_event->lock);
+ spin_lock(&new_event->lock);
+
+ if (list_empty(&new_event->holder.event_list)) {
+ if (unlikely(new_holder))
+ fsnotify_destroy_event_holder(new_holder);
+ new_holder = &new_event->holder;
+ } else if (unlikely(!new_holder)) {
+ /* between the time we checked above and got the lock the in
+ * event holder was used, go back and get a new one */
+ spin_unlock(&new_event->lock);
+ spin_unlock(&old_event->lock);
+ goto alloc_holder;
+ }
+
+ new_holder->event = new_event;
+ list_replace_init(&old_holder->event_list, &new_holder->event_list);
+
+ spin_unlock(&new_event->lock);
+ spin_unlock(&old_event->lock);
+
+ /* event == holder means we are referenced through the in event holder */
+ if (old_holder != &old_event->holder)
+ fsnotify_destroy_event_holder(old_holder);
+
+ fsnotify_get_event(new_event); /* on the list take reference */
+ fsnotify_put_event(old_event); /* off the list, drop reference */
+
+ return 0;
+}
+
struct fsnotify_event *fsnotify_clone_event(struct fsnotify_event *old_event)
{
struct fsnotify_event *event;
diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h
index 3a7fff2..427f6ff 100644
--- a/include/linux/fsnotify_backend.h
+++ b/include/linux/fsnotify_backend.h
@@ -365,6 +365,8 @@ extern struct fsnotify_event *fsnotify_create_event(struct inode *to_tell, __u32
/* fanotify likes to change events after they are on lists... */
extern struct fsnotify_event *fsnotify_clone_event(struct fsnotify_event *old_event);
+extern int fsnotify_replace_event(struct fsnotify_event_holder *old_holder,
+ struct fsnotify_event *new_event);
#else
^ permalink raw reply related [flat|nested] 8+ messages in thread