aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2014-01-21 18:48:14 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2014-01-21 19:19:41 -0500
commit7053aee26a3548ebaba046ae2e52396ccf56ac6c (patch)
tree1d21fa9409fede7b908ac08df2984766120448db /kernel
parente9fe69045bd648d75d8d8099b8658a4ee005a8e5 (diff)
fsnotify: do not share events between notification groups
Currently fsnotify framework creates one event structure for each notification event and links this event into all interested notification groups. This is done so that we save memory when several notification groups are interested in the event. However the need for event structure shared between inotify & fanotify bloats the event structure so the result is often higher memory consumption. Another problem is that fsnotify framework keeps path references with outstanding events so that fanotify can return open file descriptors with its events. This has the undesirable effect that filesystem cannot be unmounted while there are outstanding events - a regression for inotify compared to a situation before it was converted to fsnotify framework. For fanotify this problem is hard to avoid and users of fanotify should kind of expect this behavior when they ask for file descriptors from notified files. This patch changes fsnotify and its users to create separate event structure for each group. This allows for much simpler code (~400 lines removed by this patch) and also smaller event structures. For example on 64-bit system original struct fsnotify_event consumes 120 bytes, plus additional space for file name, additional 24 bytes for second and each subsequent group linking the event, and additional 32 bytes for each inotify group for private data. After the conversion inotify event consumes 48 bytes plus space for file name which is considerably less memory unless file names are long and there are several groups interested in the events (both of which are uncommon). Fanotify event fits in 56 bytes after the conversion (fanotify doesn't care about file names so its events don't have to have it allocated). A win unless there are four or more fanotify groups interested in the event. The conversion also solves the problem with unmount when only inotify is used as we don't have to grab path references for inotify events. [hughd@google.com: fanotify: fix corruption preventing startup] Signed-off-by: Jan Kara <jack@suse.cz> Reviewed-by: Christoph Hellwig <hch@lst.de> Cc: Eric Paris <eparis@parisplace.org> Cc: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Hugh Dickins <hughd@google.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/audit_tree.c8
-rw-r--r--kernel/audit_watch.c14
2 files changed, 12 insertions, 10 deletions
diff --git a/kernel/audit_tree.c b/kernel/audit_tree.c
index 43c307dc9453..bcc0b1821227 100644
--- a/kernel/audit_tree.c
+++ b/kernel/audit_tree.c
@@ -912,9 +912,11 @@ static void evict_chunk(struct audit_chunk *chunk)
912} 912}
913 913
914static int audit_tree_handle_event(struct fsnotify_group *group, 914static int audit_tree_handle_event(struct fsnotify_group *group,
915 struct inode *to_tell,
915 struct fsnotify_mark *inode_mark, 916 struct fsnotify_mark *inode_mark,
916 struct fsnotify_mark *vfsmonut_mark, 917 struct fsnotify_mark *vfsmount_mark,
917 struct fsnotify_event *event) 918 u32 mask, void *data, int data_type,
919 const unsigned char *file_name)
918{ 920{
919 BUG(); 921 BUG();
920 return -EOPNOTSUPP; 922 return -EOPNOTSUPP;
@@ -945,7 +947,7 @@ static const struct fsnotify_ops audit_tree_ops = {
945 .handle_event = audit_tree_handle_event, 947 .handle_event = audit_tree_handle_event,
946 .should_send_event = audit_tree_send_event, 948 .should_send_event = audit_tree_send_event,
947 .free_group_priv = NULL, 949 .free_group_priv = NULL,
948 .free_event_priv = NULL, 950 .free_event = NULL,
949 .freeing_mark = audit_tree_freeing_mark, 951 .freeing_mark = audit_tree_freeing_mark,
950}; 952};
951 953
diff --git a/kernel/audit_watch.c b/kernel/audit_watch.c
index 22831c4d369c..a760c32cb639 100644
--- a/kernel/audit_watch.c
+++ b/kernel/audit_watch.c
@@ -475,25 +475,25 @@ static bool audit_watch_should_send_event(struct fsnotify_group *group, struct i
475 475
476/* Update watch data in audit rules based on fsnotify events. */ 476/* Update watch data in audit rules based on fsnotify events. */
477static int audit_watch_handle_event(struct fsnotify_group *group, 477static int audit_watch_handle_event(struct fsnotify_group *group,
478 struct inode *to_tell,
478 struct fsnotify_mark *inode_mark, 479 struct fsnotify_mark *inode_mark,
479 struct fsnotify_mark *vfsmount_mark, 480 struct fsnotify_mark *vfsmount_mark,
480 struct fsnotify_event *event) 481 u32 mask, void *data, int data_type,
482 const unsigned char *dname)
481{ 483{
482 struct inode *inode; 484 struct inode *inode;
483 __u32 mask = event->mask;
484 const char *dname = event->file_name;
485 struct audit_parent *parent; 485 struct audit_parent *parent;
486 486
487 parent = container_of(inode_mark, struct audit_parent, mark); 487 parent = container_of(inode_mark, struct audit_parent, mark);
488 488
489 BUG_ON(group != audit_watch_group); 489 BUG_ON(group != audit_watch_group);
490 490
491 switch (event->data_type) { 491 switch (data_type) {
492 case (FSNOTIFY_EVENT_PATH): 492 case (FSNOTIFY_EVENT_PATH):
493 inode = event->path.dentry->d_inode; 493 inode = ((struct path *)data)->dentry->d_inode;
494 break; 494 break;
495 case (FSNOTIFY_EVENT_INODE): 495 case (FSNOTIFY_EVENT_INODE):
496 inode = event->inode; 496 inode = (struct inode *)data;
497 break; 497 break;
498 default: 498 default:
499 BUG(); 499 BUG();
@@ -516,7 +516,7 @@ static const struct fsnotify_ops audit_watch_fsnotify_ops = {
516 .handle_event = audit_watch_handle_event, 516 .handle_event = audit_watch_handle_event,
517 .free_group_priv = NULL, 517 .free_group_priv = NULL,
518 .freeing_mark = NULL, 518 .freeing_mark = NULL,
519 .free_event_priv = NULL, 519 .free_event = NULL,
520}; 520};
521 521
522static int __init audit_watch_init(void) 522static int __init audit_watch_init(void)