summaryrefslogtreecommitdiffstats
path: root/kernel/auditsc.c
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2017-03-14 07:31:02 -0400
committerJan Kara <jack@suse.cz>2017-04-10 11:37:34 -0400
commit9dd813c15b2c101168808d4f5941a29985758973 (patch)
tree62646b8b8e4335b9d311bdcd3224d12308961c20 /kernel/auditsc.c
parentc1f33073ac1b33510e956de7181438515e438db0 (diff)
fsnotify: Move mark list head from object into dedicated structure
Currently notification marks are attached to object (inode or vfsmnt) by a hlist_head in the object. The list is also protected by a spinlock in the object. So while there is any mark attached to the list of marks, the object must be pinned in memory (and thus e.g. last iput() deleting inode cannot happen). Also for list iteration in fsnotify() to work, we must hold fsnotify_mark_srcu lock so that mark itself and mark->obj_list.next cannot get freed. Thus we are required to wait for response to fanotify events from userspace process with fsnotify_mark_srcu lock held. That causes issues when userspace process is buggy and does not reply to some event - basically the whole notification subsystem gets eventually stuck. So to be able to drop fsnotify_mark_srcu lock while waiting for response, we have to pin the mark in memory and make sure it stays in the object list (as removing the mark waiting for response could lead to lost notification events for groups later in the list). However we don't want inode reclaim to block on such mark as that would lead to system just locking up elsewhere. This commit is the first in the series that paves way towards solving these conflicting lifetime needs. Instead of anchoring the list of marks directly in the object, we anchor it in a dedicated structure (fsnotify_mark_connector) and just point to that structure from the object. The following commits will also add spinlock protecting the list and object pointer to the structure. Reviewed-by: Miklos Szeredi <mszeredi@redhat.com> Reviewed-by: Amir Goldstein <amir73il@gmail.com> Signed-off-by: Jan Kara <jack@suse.cz>
Diffstat (limited to 'kernel/auditsc.c')
-rw-r--r--kernel/auditsc.c7
1 files changed, 5 insertions, 2 deletions
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index d6a8de5f8fa3..bf7b7ca295d0 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -73,6 +73,7 @@
73#include <linux/ctype.h> 73#include <linux/ctype.h>
74#include <linux/string.h> 74#include <linux/string.h>
75#include <linux/uaccess.h> 75#include <linux/uaccess.h>
76#include <linux/fsnotify_backend.h>
76#include <uapi/linux/limits.h> 77#include <uapi/linux/limits.h>
77 78
78#include "audit.h" 79#include "audit.h"
@@ -1596,7 +1597,8 @@ static inline void handle_one(const struct inode *inode)
1596 struct audit_tree_refs *p; 1597 struct audit_tree_refs *p;
1597 struct audit_chunk *chunk; 1598 struct audit_chunk *chunk;
1598 int count; 1599 int count;
1599 if (likely(hlist_empty(&inode->i_fsnotify_marks))) 1600 if (likely(!inode->i_fsnotify_marks ||
1601 hlist_empty(&inode->i_fsnotify_marks->list)))
1600 return; 1602 return;
1601 context = current->audit_context; 1603 context = current->audit_context;
1602 p = context->trees; 1604 p = context->trees;
@@ -1639,7 +1641,8 @@ retry:
1639 seq = read_seqbegin(&rename_lock); 1641 seq = read_seqbegin(&rename_lock);
1640 for(;;) { 1642 for(;;) {
1641 struct inode *inode = d_backing_inode(d); 1643 struct inode *inode = d_backing_inode(d);
1642 if (inode && unlikely(!hlist_empty(&inode->i_fsnotify_marks))) { 1644 if (inode && unlikely(inode->i_fsnotify_marks &&
1645 !hlist_empty(&inode->i_fsnotify_marks->list))) {
1643 struct audit_chunk *chunk; 1646 struct audit_chunk *chunk;
1644 chunk = audit_tree_lookup(inode); 1647 chunk = audit_tree_lookup(inode);
1645 if (chunk) { 1648 if (chunk) {