Commit 33cba859 authored by David Howells's avatar David Howells
Browse files

fscache: Fix fscache_cookie_put() to not deref after dec



fscache_cookie_put() accesses the cookie it has just put inside the
tracepoint that monitors the change - but this is something it's not
allowed to do if we didn't reduce the count to zero.

Fix this by dropping most of those values from the tracepoint and grabbing
the cookie debug ID before doing the dec.

Also take the opportunity to switch over the usage and where arguments on
the tracepoint to put the reason last.

Fixes: a18feb55 ("fscache: Add tracepoints")
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
Reviewed-by: default avatarJeff Layton <jlayton@redhat.com>
cc: linux-cachefs@redhat.com
Link: https://lore.kernel.org/r/162431203107.2908479.3259582550347000088.stgit@warthog.procyon.org.uk/
parent 35b72573
Loading
Loading
Loading
Loading
+6 −4
Original line number Diff line number Diff line
@@ -225,8 +225,8 @@ struct fscache_cookie *fscache_hash_cookie(struct fscache_cookie *candidate)

collision:
	if (test_and_set_bit(FSCACHE_COOKIE_ACQUIRED, &cursor->flags)) {
		trace_fscache_cookie(cursor, fscache_cookie_collision,
				     atomic_read(&cursor->usage));
		trace_fscache_cookie(cursor->debug_id, atomic_read(&cursor->usage),
				     fscache_cookie_collision);
		pr_err("Duplicate cookie detected\n");
		fscache_print_cookie(cursor, 'O');
		fscache_print_cookie(candidate, 'N');
@@ -305,7 +305,8 @@ struct fscache_cookie *__fscache_acquire_cookie(

	cookie = fscache_hash_cookie(candidate);
	if (!cookie) {
		trace_fscache_cookie(candidate, fscache_cookie_discard, 1);
		trace_fscache_cookie(candidate->debug_id, 1,
				     fscache_cookie_discard);
		goto out;
	}

@@ -866,8 +867,9 @@ void fscache_cookie_put(struct fscache_cookie *cookie,
	_enter("%x", cookie->debug_id);

	do {
		unsigned int cookie_debug_id = cookie->debug_id;
		usage = atomic_dec_return(&cookie->usage);
		trace_fscache_cookie(cookie, where, usage);
		trace_fscache_cookie(cookie_debug_id, usage, where);

		if (usage > 0)
			return;
+1 −1
Original line number Diff line number Diff line
@@ -291,7 +291,7 @@ static inline void fscache_cookie_get(struct fscache_cookie *cookie,
{
	int usage = atomic_inc_return(&cookie->usage);

	trace_fscache_cookie(cookie, where, usage);
	trace_fscache_cookie(cookie->debug_id, usage, where);
}

/*
+1 −1
Original line number Diff line number Diff line
@@ -37,7 +37,7 @@ int __fscache_register_netfs(struct fscache_netfs *netfs)
	if (!cookie)
		goto already_registered;
	if (cookie != candidate) {
		trace_fscache_cookie(candidate, fscache_cookie_discard, 1);
		trace_fscache_cookie(candidate->debug_id, 1, fscache_cookie_discard);
		fscache_free_cookie(candidate);
	}

+7 −17
Original line number Diff line number Diff line
@@ -160,37 +160,27 @@ fscache_cookie_traces;


TRACE_EVENT(fscache_cookie,
	    TP_PROTO(struct fscache_cookie *cookie,
		     enum fscache_cookie_trace where,
		     int usage),
	    TP_PROTO(unsigned int cookie_debug_id,
		     int usage,
		     enum fscache_cookie_trace where),

	    TP_ARGS(cookie, where, usage),
	    TP_ARGS(cookie_debug_id, usage, where),

	    TP_STRUCT__entry(
		    __field(unsigned int,		cookie		)
		    __field(unsigned int,		parent		)
		    __field(enum fscache_cookie_trace,	where		)
		    __field(int,			usage		)
		    __field(int,			n_children	)
		    __field(int,			n_active	)
		    __field(u8,				flags		)
			     ),

	    TP_fast_assign(
		    __entry->cookie	= cookie->debug_id;
		    __entry->parent	= cookie->parent ? cookie->parent->debug_id : 0;
		    __entry->cookie	= cookie_debug_id;
		    __entry->where	= where;
		    __entry->usage	= usage;
		    __entry->n_children	= atomic_read(&cookie->n_children);
		    __entry->n_active	= atomic_read(&cookie->n_active);
		    __entry->flags	= cookie->flags;
			   ),

	    TP_printk("%s c=%08x u=%d p=%08x Nc=%d Na=%d f=%02x",
	    TP_printk("%s c=%08x u=%d",
		      __print_symbolic(__entry->where, fscache_cookie_traces),
		      __entry->cookie, __entry->usage,
		      __entry->parent, __entry->n_children, __entry->n_active,
		      __entry->flags)
		      __entry->cookie, __entry->usage)
	    );

TRACE_EVENT(fscache_netfs,