diff mbox

[09/10] audit: Allocate fsnotify mark independently of chunk

Message ID 20180710100217.12866-10-jack@suse.cz (mailing list archive)
State New, archived
Headers show

Commit Message

Jan Kara July 10, 2018, 10:02 a.m. UTC
Allocate fsnotify mark independently instead of embedding it inside
chunk. This will allow us to just replace chunk attached to mark when
growing / shrinking chunk instead of replacing mark attached to inode
which is a more complex operation.

Signed-off-by: Jan Kara <jack@suse.cz>
---
 kernel/audit_tree.c | 59 ++++++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 45 insertions(+), 14 deletions(-)

Comments

Amir Goldstein July 11, 2018, 8:57 a.m. UTC | #1
On Tue, Jul 10, 2018 at 1:02 PM, Jan Kara <jack@suse.cz> wrote:
> Allocate fsnotify mark independently instead of embedding it inside
> chunk. This will allow us to just replace chunk attached to mark when
> growing / shrinking chunk instead of replacing mark attached to inode
> which is a more complex operation.
>
> Signed-off-by: Jan Kara <jack@suse.cz>

Ack.

Thanks for separating this patch.
Amir.

> ---
>  kernel/audit_tree.c | 59 ++++++++++++++++++++++++++++++++++++++++-------------
>  1 file changed, 45 insertions(+), 14 deletions(-)
>
> diff --git a/kernel/audit_tree.c b/kernel/audit_tree.c
> index bce3b04a365d..aec9b27a20ff 100644
> --- a/kernel/audit_tree.c
> +++ b/kernel/audit_tree.c
> @@ -25,7 +25,7 @@ struct audit_tree {
>  struct audit_chunk {
>         struct list_head hash;
>         unsigned long key;
> -       struct fsnotify_mark mark;
> +       struct fsnotify_mark *mark;
>         struct list_head trees;         /* with root here */
>         int dead;
>         int count;
> @@ -38,6 +38,11 @@ struct audit_chunk {
>         } owners[];
>  };
>
> +struct audit_tree_mark {
> +       struct fsnotify_mark fsn_mark;
> +       struct audit_chunk *chunk;
> +};
> +
>  static LIST_HEAD(tree_list);
>  static LIST_HEAD(prune_list);
>  static struct task_struct *prune_thread;
> @@ -73,6 +78,7 @@ static struct task_struct *prune_thread;
>   */
>
>  static struct fsnotify_group *audit_tree_group;
> +static struct kmem_cache *audit_tree_mark_cachep __read_mostly;
>
>  static struct audit_tree *alloc_tree(const char *s)
>  {
> @@ -142,10 +148,28 @@ static void audit_mark_put_chunk(struct audit_chunk *chunk)
>         call_rcu(&chunk->head, __put_chunk);
>  }
>
> +static inline struct audit_tree_mark *AUDIT_M(struct fsnotify_mark *entry)
> +{
> +       return container_of(entry, struct audit_tree_mark, fsn_mark);
> +}
> +
>  static void audit_tree_destroy_watch(struct fsnotify_mark *entry)
>  {
> -       struct audit_chunk *chunk = container_of(entry, struct audit_chunk, mark);
> +       struct audit_chunk *chunk = AUDIT_M(entry)->chunk;
>         audit_mark_put_chunk(chunk);
> +       kmem_cache_free(audit_tree_mark_cachep, entry);
> +}
> +
> +static struct fsnotify_mark *alloc_fsnotify_mark(void)
> +{
> +       struct audit_tree_mark *mark;
> +
> +       mark = kmem_cache_zalloc(audit_tree_mark_cachep, GFP_KERNEL);
> +       if (!mark)
> +               return NULL;
> +       fsnotify_init_mark(&mark->fsn_mark, audit_tree_group);
> +       mark->fsn_mark.mask = FS_IN_IGNORED;
> +       return &mark->fsn_mark;
>  }
>
>  static struct audit_chunk *alloc_chunk(int count)
> @@ -159,6 +183,13 @@ static struct audit_chunk *alloc_chunk(int count)
>         if (!chunk)
>                 return NULL;
>
> +       chunk->mark = alloc_fsnotify_mark();
> +       if (!chunk->mark) {
> +               kfree(chunk);
> +               return NULL;
> +       }
> +       AUDIT_M(chunk->mark)->chunk = chunk;
> +
>         INIT_LIST_HEAD(&chunk->hash);
>         INIT_LIST_HEAD(&chunk->trees);
>         chunk->count = count;
> @@ -167,8 +198,6 @@ static struct audit_chunk *alloc_chunk(int count)
>                 INIT_LIST_HEAD(&chunk->owners[i].list);
>                 chunk->owners[i].index = i;
>         }
> -       fsnotify_init_mark(&chunk->mark, audit_tree_group);
> -       chunk->mark.mask = FS_IN_IGNORED;
>         return chunk;
>  }
>
> @@ -278,7 +307,7 @@ static void replace_chunk(struct audit_chunk *new, struct audit_chunk *old,
>  static void untag_chunk(struct node *p)
>  {
>         struct audit_chunk *chunk = find_chunk(p);
> -       struct fsnotify_mark *entry = &chunk->mark;
> +       struct fsnotify_mark *entry = chunk->mark;
>         struct audit_chunk *new = NULL;
>         struct audit_tree *owner;
>         int size = chunk->count - 1;
> @@ -298,7 +327,7 @@ static void untag_chunk(struct node *p)
>         if (chunk->dead || !(entry->flags & FSNOTIFY_MARK_FLAG_ATTACHED)) {
>                 mutex_unlock(&entry->group->mark_mutex);
>                 if (new)
> -                       fsnotify_put_mark(&new->mark);
> +                       fsnotify_put_mark(new->mark);
>                 goto out;
>         }
>
> @@ -322,9 +351,9 @@ static void untag_chunk(struct node *p)
>         if (!new)
>                 goto Fallback;
>
> -       if (fsnotify_add_mark_locked(&new->mark, entry->connector->obj,
> +       if (fsnotify_add_mark_locked(new->mark, entry->connector->obj,
>                                      FSNOTIFY_OBJ_TYPE_INODE, 1)) {
> -               fsnotify_put_mark(&new->mark);
> +               fsnotify_put_mark(new->mark);
>                 goto Fallback;
>         }
>
> @@ -344,7 +373,7 @@ static void untag_chunk(struct node *p)
>         fsnotify_detach_mark(entry);
>         mutex_unlock(&entry->group->mark_mutex);
>         fsnotify_free_mark(entry);
> -       fsnotify_put_mark(&new->mark);  /* drop initial reference */
> +       fsnotify_put_mark(new->mark);   /* drop initial reference */
>         goto out;
>
>  Fallback:
> @@ -375,7 +404,7 @@ static int create_chunk(struct inode *inode, struct audit_tree *tree)
>                 return -ENOMEM;
>         }
>
> -       entry = &chunk->mark;
> +       entry = chunk->mark;
>         if (fsnotify_add_inode_mark_locked(entry, inode, 0)) {
>                 mutex_unlock(&audit_tree_group->mark_mutex);
>                 fsnotify_put_mark(entry);
> @@ -426,7 +455,7 @@ static int tag_chunk(struct inode *inode, struct audit_tree *tree)
>         if (!old_entry)
>                 return create_chunk(inode, tree);
>
> -       old = container_of(old_entry, struct audit_chunk, mark);
> +       old = AUDIT_M(old_entry)->chunk;
>
>         /* are we already there? */
>         spin_lock(&hash_lock);
> @@ -447,7 +476,7 @@ static int tag_chunk(struct inode *inode, struct audit_tree *tree)
>                 return -ENOMEM;
>         }
>
> -       chunk_entry = &chunk->mark;
> +       chunk_entry = chunk->mark;
>
>         /*
>          * mark_mutex protects mark from getting detached and thus also from
> @@ -457,7 +486,7 @@ static int tag_chunk(struct inode *inode, struct audit_tree *tree)
>                 /* old_entry is being shot, lets just lie */
>                 mutex_unlock(&audit_tree_group->mark_mutex);
>                 fsnotify_put_mark(old_entry);
> -               fsnotify_put_mark(&chunk->mark);
> +               fsnotify_put_mark(chunk->mark);
>                 return -ENOENT;
>         }
>
> @@ -1009,7 +1038,7 @@ static int audit_tree_handle_event(struct fsnotify_group *group,
>
>  static void audit_tree_freeing_mark(struct fsnotify_mark *entry, struct fsnotify_group *group)
>  {
> -       struct audit_chunk *chunk = container_of(entry, struct audit_chunk, mark);
> +       struct audit_chunk *chunk = AUDIT_M(entry)->chunk;
>
>         evict_chunk(chunk);
>
> @@ -1030,6 +1059,8 @@ static int __init audit_tree_init(void)
>  {
>         int i;
>
> +       audit_tree_mark_cachep = KMEM_CACHE(audit_tree_mark, SLAB_PANIC);
> +
>         audit_tree_group = fsnotify_alloc_group(&audit_tree_ops);
>         if (IS_ERR(audit_tree_group))
>                 audit_panic("cannot initialize fsnotify group for rectree watches");
> --
> 2.16.4
>
Amir Goldstein July 11, 2018, 10:48 a.m. UTC | #2
On Wed, Jul 11, 2018 at 11:57 AM, Amir Goldstein <amir73il@gmail.com> wrote:
> On Tue, Jul 10, 2018 at 1:02 PM, Jan Kara <jack@suse.cz> wrote:
>> Allocate fsnotify mark independently instead of embedding it inside
>> chunk. This will allow us to just replace chunk attached to mark when
>> growing / shrinking chunk instead of replacing mark attached to inode
>> which is a more complex operation.
>>
>> Signed-off-by: Jan Kara <jack@suse.cz>
>
> Ack.

Found minor nit.

[...]
>> +static inline struct audit_tree_mark *AUDIT_M(struct fsnotify_mark *entry)
>> +{
>> +       return container_of(entry, struct audit_tree_mark, fsn_mark);
>> +}
>> +
>>  static void audit_tree_destroy_watch(struct fsnotify_mark *entry)
>>  {
>> -       struct audit_chunk *chunk = container_of(entry, struct audit_chunk, mark);
>> +       struct audit_chunk *chunk = AUDIT_M(entry)->chunk;
>>         audit_mark_put_chunk(chunk);
>> +       kmem_cache_free(audit_tree_mark_cachep, entry);

Technically, we should be freeing AUDIT_M(entry)
although it is the same address with current struct layout.

Thanks,
Amir.
Jan Kara July 16, 2018, 3:13 p.m. UTC | #3
On Wed 11-07-18 13:48:58, Amir Goldstein wrote:
> On Wed, Jul 11, 2018 at 11:57 AM, Amir Goldstein <amir73il@gmail.com> wrote:
> > On Tue, Jul 10, 2018 at 1:02 PM, Jan Kara <jack@suse.cz> wrote:
> >> Allocate fsnotify mark independently instead of embedding it inside
> >> chunk. This will allow us to just replace chunk attached to mark when
> >> growing / shrinking chunk instead of replacing mark attached to inode
> >> which is a more complex operation.
> >>
> >> Signed-off-by: Jan Kara <jack@suse.cz>
> >
> > Ack.
> 
> Found minor nit.
> 
> [...]
> >> +static inline struct audit_tree_mark *AUDIT_M(struct fsnotify_mark *entry)
> >> +{
> >> +       return container_of(entry, struct audit_tree_mark, fsn_mark);
> >> +}
> >> +
> >>  static void audit_tree_destroy_watch(struct fsnotify_mark *entry)
> >>  {
> >> -       struct audit_chunk *chunk = container_of(entry, struct audit_chunk, mark);
> >> +       struct audit_chunk *chunk = AUDIT_M(entry)->chunk;
> >>         audit_mark_put_chunk(chunk);
> >> +       kmem_cache_free(audit_tree_mark_cachep, entry);
> 
> Technically, we should be freeing AUDIT_M(entry)
> although it is the same address with current struct layout.

Right, thanks for spotting this. Fixed in my tree.

								Honza
Paul Moore July 27, 2018, 4:47 a.m. UTC | #4
On Tue, Jul 10, 2018 at 6:02 AM Jan Kara <jack@suse.cz> wrote:
> Allocate fsnotify mark independently instead of embedding it inside
> chunk. This will allow us to just replace chunk attached to mark when
> growing / shrinking chunk instead of replacing mark attached to inode
> which is a more complex operation.
>
> Signed-off-by: Jan Kara <jack@suse.cz>
> ---
>  kernel/audit_tree.c | 59 ++++++++++++++++++++++++++++++++++++++++-------------
>  1 file changed, 45 insertions(+), 14 deletions(-)

...

> diff --git a/kernel/audit_tree.c b/kernel/audit_tree.c
> index bce3b04a365d..aec9b27a20ff 100644
> --- a/kernel/audit_tree.c
> +++ b/kernel/audit_tree.c
> @@ -38,6 +38,11 @@ struct audit_chunk {
>         } owners[];
>  };
>
> +struct audit_tree_mark {
> +       struct fsnotify_mark fsn_mark;
> +       struct audit_chunk *chunk;
> +};

It's probably okay to just call it "mark" considering we call
fsnotify_mark fields "mark" elsewhere.  If we are going to change it
in one spot we should probably change it other places as well for the
sake of readability.

2,10 +148,28 @@ static void audit_mark_put_chunk(struct audit_chunk *chunk)
>         call_rcu(&chunk->head, __put_chunk);
>  }
>
> +static inline struct audit_tree_mark *AUDIT_M(struct fsnotify_mark *entry)
> +{
> +       return container_of(entry, struct audit_tree_mark, fsn_mark);
> +}

When I see a symbol in all caps I think "macro definition", but this
isn't a macro definition.  I would suggest a different name, dropping
the caps, or converting it into a macro.

Also, unless I missed a call, it seems like after patch 10 all callers
of AUDIT_M end up getting the chunk field; maybe it is better if
AUDIT_M() ends up returning the audit_chunk pointer instead of the
audit_tree_mark pointer (and of course a name change if this is a
reasonable change)?

>  static void audit_tree_destroy_watch(struct fsnotify_mark *entry)
>  {
> -       struct audit_chunk *chunk = container_of(entry, struct audit_chunk, mark);
> +       struct audit_chunk *chunk = AUDIT_M(entry)->chunk;
>         audit_mark_put_chunk(chunk);
> +       kmem_cache_free(audit_tree_mark_cachep, entry);
> +}

I think you've said you've already fixed the above (thanks for the
review Amir!).

> +static struct fsnotify_mark *alloc_fsnotify_mark(void)
> +{
> +       struct audit_tree_mark *mark;
> +
> +       mark = kmem_cache_zalloc(audit_tree_mark_cachep, GFP_KERNEL);
> +       if (!mark)
> +               return NULL;
> +       fsnotify_init_mark(&mark->fsn_mark, audit_tree_group);
> +       mark->fsn_mark.mask = FS_IN_IGNORED;
> +       return &mark->fsn_mark;
>  }

Can't we just call it alloc_mark()?  Or did you create the function
earlier in the patchset and I'm missing it now?

[SIDE NOTE: I have some rather big disagreements with the current
naming in this file, but keeping things consistent seems to be a Good
Thing (once again, this is an existing problem not specific to your
patches).]

--
paul moore
www.paul-moore.com
Jan Kara Sept. 4, 2018, 2:03 p.m. UTC | #5
On Fri 27-07-18 00:47:37, Paul Moore wrote:
> On Tue, Jul 10, 2018 at 6:02 AM Jan Kara <jack@suse.cz> wrote:
> > Allocate fsnotify mark independently instead of embedding it inside
> > chunk. This will allow us to just replace chunk attached to mark when
> > growing / shrinking chunk instead of replacing mark attached to inode
> > which is a more complex operation.
> >
> > Signed-off-by: Jan Kara <jack@suse.cz>
> > ---
> >  kernel/audit_tree.c | 59 ++++++++++++++++++++++++++++++++++++++++-------------
> >  1 file changed, 45 insertions(+), 14 deletions(-)
> 
> ...
> 
> > diff --git a/kernel/audit_tree.c b/kernel/audit_tree.c
> > index bce3b04a365d..aec9b27a20ff 100644
> > --- a/kernel/audit_tree.c
> > +++ b/kernel/audit_tree.c
> > @@ -38,6 +38,11 @@ struct audit_chunk {
> >         } owners[];
> >  };
> >
> > +struct audit_tree_mark {
> > +       struct fsnotify_mark fsn_mark;
> > +       struct audit_chunk *chunk;
> > +};
> 
> It's probably okay to just call it "mark" considering we call
> fsnotify_mark fields "mark" elsewhere.  If we are going to change it
> in one spot we should probably change it other places as well for the
> sake of readability.

The current notation is that 'fsn_mark' (or sometimes 'entry') is struct
fsnotify_mark while plain 'mark' is struct audit_tree_mark (well, except
for audit_chunk AFAICS). So just replacing fsn_mark with mark is IMO going
to cause more confusion. But if you prefer different naming convention,
this is the right moment to bring some consistency into the whole thing.
So how do you prefer to differentiate between fsnotify_mark and
audit_tree_mark?

> 2,10 +148,28 @@ static void audit_mark_put_chunk(struct audit_chunk *chunk)
> >         call_rcu(&chunk->head, __put_chunk);
> >  }
> >
> > +static inline struct audit_tree_mark *AUDIT_M(struct fsnotify_mark *entry)
> > +{
> > +       return container_of(entry, struct audit_tree_mark, fsn_mark);
> > +}
> 
> When I see a symbol in all caps I think "macro definition", but this
> isn't a macro definition.  I would suggest a different name, dropping
> the caps, or converting it into a macro.

I want the inline function for type safety. All caps for this function is a
tradition from filesystem space where all FOO_I(inode) or FOO_SB(sb)
helpers are all caps. I then inherited it for fs/notify/. So it is
consistent with some code. But if you still don't like all caps, I can
change the name... Hmm, given your comment below, I guess I'll just change
the name since it will have exactly two call sites.

> Also, unless I missed a call, it seems like after patch 10 all callers
> of AUDIT_M end up getting the chunk field; maybe it is better if
> AUDIT_M() ends up returning the audit_chunk pointer instead of the
> audit_tree_mark pointer (and of course a name change if this is a
> reasonable change)?

Good point. All but one - audit_tree_destroy_watch(). I'll create a helper
for this.

> > +static struct fsnotify_mark *alloc_fsnotify_mark(void)
> > +{
> > +       struct audit_tree_mark *mark;
> > +
> > +       mark = kmem_cache_zalloc(audit_tree_mark_cachep, GFP_KERNEL);
> > +       if (!mark)
> > +               return NULL;
> > +       fsnotify_init_mark(&mark->fsn_mark, audit_tree_group);
> > +       mark->fsn_mark.mask = FS_IN_IGNORED;
> > +       return &mark->fsn_mark;
> >  }
> 
> Can't we just call it alloc_mark()?  Or did you create the function
> earlier in the patchset and I'm missing it now?

No, previously mark got allocated as a part of alloc_chunk() as it was
embedded there. OK, I can call this alloc_mark().

> [SIDE NOTE: I have some rather big disagreements with the current
> naming in this file, but keeping things consistent seems to be a Good
> Thing (once again, this is an existing problem not specific to your
> patches).]

I agree some of the names are tad bit confusing. But not that I'd have
great idea how to improve that.

								Honza
Jan Kara Sept. 4, 2018, 2:07 p.m. UTC | #6
On Tue 04-09-18 16:03:07, Jan Kara wrote:
> On Fri 27-07-18 00:47:37, Paul Moore wrote:
> > On Tue, Jul 10, 2018 at 6:02 AM Jan Kara <jack@suse.cz> wrote:
> > > Allocate fsnotify mark independently instead of embedding it inside
> > > chunk. This will allow us to just replace chunk attached to mark when
> > > growing / shrinking chunk instead of replacing mark attached to inode
> > > which is a more complex operation.
> > >
> > > Signed-off-by: Jan Kara <jack@suse.cz>
> > > ---
> > >  kernel/audit_tree.c | 59 ++++++++++++++++++++++++++++++++++++++++-------------
> > >  1 file changed, 45 insertions(+), 14 deletions(-)
> > 
> > ...
> > 
> > > diff --git a/kernel/audit_tree.c b/kernel/audit_tree.c
> > > index bce3b04a365d..aec9b27a20ff 100644
> > > --- a/kernel/audit_tree.c
> > > +++ b/kernel/audit_tree.c
> > > @@ -38,6 +38,11 @@ struct audit_chunk {
> > >         } owners[];
> > >  };
> > >
> > > +struct audit_tree_mark {
> > > +       struct fsnotify_mark fsn_mark;
> > > +       struct audit_chunk *chunk;
> > > +};
> > 
> > It's probably okay to just call it "mark" considering we call
> > fsnotify_mark fields "mark" elsewhere.  If we are going to change it
> > in one spot we should probably change it other places as well for the
> > sake of readability.
> 
> The current notation is that 'fsn_mark' (or sometimes 'entry') is struct
> fsnotify_mark while plain 'mark' is struct audit_tree_mark (well, except
> for audit_chunk AFAICS). So just replacing fsn_mark with mark is IMO going
> to cause more confusion. But if you prefer different naming convention,
> this is the right moment to bring some consistency into the whole thing.
> So how do you prefer to differentiate between fsnotify_mark and
> audit_tree_mark?

After searching the code and given your observation that audit_tree_mark is
rarely directly used, I guess I'll just make fsn_mark -> mark, entry->mark
renaming and invent some name for the few places where we use
audit_tree_mark directly.

								Honza
diff mbox

Patch

diff --git a/kernel/audit_tree.c b/kernel/audit_tree.c
index bce3b04a365d..aec9b27a20ff 100644
--- a/kernel/audit_tree.c
+++ b/kernel/audit_tree.c
@@ -25,7 +25,7 @@  struct audit_tree {
 struct audit_chunk {
 	struct list_head hash;
 	unsigned long key;
-	struct fsnotify_mark mark;
+	struct fsnotify_mark *mark;
 	struct list_head trees;		/* with root here */
 	int dead;
 	int count;
@@ -38,6 +38,11 @@  struct audit_chunk {
 	} owners[];
 };
 
+struct audit_tree_mark {
+	struct fsnotify_mark fsn_mark;
+	struct audit_chunk *chunk;
+};
+
 static LIST_HEAD(tree_list);
 static LIST_HEAD(prune_list);
 static struct task_struct *prune_thread;
@@ -73,6 +78,7 @@  static struct task_struct *prune_thread;
  */
 
 static struct fsnotify_group *audit_tree_group;
+static struct kmem_cache *audit_tree_mark_cachep __read_mostly;
 
 static struct audit_tree *alloc_tree(const char *s)
 {
@@ -142,10 +148,28 @@  static void audit_mark_put_chunk(struct audit_chunk *chunk)
 	call_rcu(&chunk->head, __put_chunk);
 }
 
+static inline struct audit_tree_mark *AUDIT_M(struct fsnotify_mark *entry)
+{
+	return container_of(entry, struct audit_tree_mark, fsn_mark);
+}
+
 static void audit_tree_destroy_watch(struct fsnotify_mark *entry)
 {
-	struct audit_chunk *chunk = container_of(entry, struct audit_chunk, mark);
+	struct audit_chunk *chunk = AUDIT_M(entry)->chunk;
 	audit_mark_put_chunk(chunk);
+	kmem_cache_free(audit_tree_mark_cachep, entry);
+}
+
+static struct fsnotify_mark *alloc_fsnotify_mark(void)
+{
+	struct audit_tree_mark *mark;
+
+	mark = kmem_cache_zalloc(audit_tree_mark_cachep, GFP_KERNEL);
+	if (!mark)
+		return NULL;
+	fsnotify_init_mark(&mark->fsn_mark, audit_tree_group);
+	mark->fsn_mark.mask = FS_IN_IGNORED;
+	return &mark->fsn_mark;
 }
 
 static struct audit_chunk *alloc_chunk(int count)
@@ -159,6 +183,13 @@  static struct audit_chunk *alloc_chunk(int count)
 	if (!chunk)
 		return NULL;
 
+	chunk->mark = alloc_fsnotify_mark();
+	if (!chunk->mark) {
+		kfree(chunk);
+		return NULL;
+	}
+	AUDIT_M(chunk->mark)->chunk = chunk;
+
 	INIT_LIST_HEAD(&chunk->hash);
 	INIT_LIST_HEAD(&chunk->trees);
 	chunk->count = count;
@@ -167,8 +198,6 @@  static struct audit_chunk *alloc_chunk(int count)
 		INIT_LIST_HEAD(&chunk->owners[i].list);
 		chunk->owners[i].index = i;
 	}
-	fsnotify_init_mark(&chunk->mark, audit_tree_group);
-	chunk->mark.mask = FS_IN_IGNORED;
 	return chunk;
 }
 
@@ -278,7 +307,7 @@  static void replace_chunk(struct audit_chunk *new, struct audit_chunk *old,
 static void untag_chunk(struct node *p)
 {
 	struct audit_chunk *chunk = find_chunk(p);
-	struct fsnotify_mark *entry = &chunk->mark;
+	struct fsnotify_mark *entry = chunk->mark;
 	struct audit_chunk *new = NULL;
 	struct audit_tree *owner;
 	int size = chunk->count - 1;
@@ -298,7 +327,7 @@  static void untag_chunk(struct node *p)
 	if (chunk->dead || !(entry->flags & FSNOTIFY_MARK_FLAG_ATTACHED)) {
 		mutex_unlock(&entry->group->mark_mutex);
 		if (new)
-			fsnotify_put_mark(&new->mark);
+			fsnotify_put_mark(new->mark);
 		goto out;
 	}
 
@@ -322,9 +351,9 @@  static void untag_chunk(struct node *p)
 	if (!new)
 		goto Fallback;
 
-	if (fsnotify_add_mark_locked(&new->mark, entry->connector->obj,
+	if (fsnotify_add_mark_locked(new->mark, entry->connector->obj,
 				     FSNOTIFY_OBJ_TYPE_INODE, 1)) {
-		fsnotify_put_mark(&new->mark);
+		fsnotify_put_mark(new->mark);
 		goto Fallback;
 	}
 
@@ -344,7 +373,7 @@  static void untag_chunk(struct node *p)
 	fsnotify_detach_mark(entry);
 	mutex_unlock(&entry->group->mark_mutex);
 	fsnotify_free_mark(entry);
-	fsnotify_put_mark(&new->mark);	/* drop initial reference */
+	fsnotify_put_mark(new->mark);	/* drop initial reference */
 	goto out;
 
 Fallback:
@@ -375,7 +404,7 @@  static int create_chunk(struct inode *inode, struct audit_tree *tree)
 		return -ENOMEM;
 	}
 
-	entry = &chunk->mark;
+	entry = chunk->mark;
 	if (fsnotify_add_inode_mark_locked(entry, inode, 0)) {
 		mutex_unlock(&audit_tree_group->mark_mutex);
 		fsnotify_put_mark(entry);
@@ -426,7 +455,7 @@  static int tag_chunk(struct inode *inode, struct audit_tree *tree)
 	if (!old_entry)
 		return create_chunk(inode, tree);
 
-	old = container_of(old_entry, struct audit_chunk, mark);
+	old = AUDIT_M(old_entry)->chunk;
 
 	/* are we already there? */
 	spin_lock(&hash_lock);
@@ -447,7 +476,7 @@  static int tag_chunk(struct inode *inode, struct audit_tree *tree)
 		return -ENOMEM;
 	}
 
-	chunk_entry = &chunk->mark;
+	chunk_entry = chunk->mark;
 
 	/*
 	 * mark_mutex protects mark from getting detached and thus also from
@@ -457,7 +486,7 @@  static int tag_chunk(struct inode *inode, struct audit_tree *tree)
 		/* old_entry is being shot, lets just lie */
 		mutex_unlock(&audit_tree_group->mark_mutex);
 		fsnotify_put_mark(old_entry);
-		fsnotify_put_mark(&chunk->mark);
+		fsnotify_put_mark(chunk->mark);
 		return -ENOENT;
 	}
 
@@ -1009,7 +1038,7 @@  static int audit_tree_handle_event(struct fsnotify_group *group,
 
 static void audit_tree_freeing_mark(struct fsnotify_mark *entry, struct fsnotify_group *group)
 {
-	struct audit_chunk *chunk = container_of(entry, struct audit_chunk, mark);
+	struct audit_chunk *chunk = AUDIT_M(entry)->chunk;
 
 	evict_chunk(chunk);
 
@@ -1030,6 +1059,8 @@  static int __init audit_tree_init(void)
 {
 	int i;
 
+	audit_tree_mark_cachep = KMEM_CACHE(audit_tree_mark, SLAB_PANIC);
+
 	audit_tree_group = fsnotify_alloc_group(&audit_tree_ops);
 	if (IS_ERR(audit_tree_group))
 		audit_panic("cannot initialize fsnotify group for rectree watches");