Skip to content

Commit

Permalink
Merge tag 'afs-fixes-20220802' of git://git.kernel.org/pub/scm/linux/…
Browse files Browse the repository at this point in the history
…kernel/git/dhowells/linux-fs

Pull AFS fixes from David Howells:
 "Fix AFS refcount handling.

  The first patch converts afs to use refcount_t for its refcounts and
  the second patch fixes afs_put_call() and afs_put_server() to save the
  values they're going to log in the tracepoint before decrementing the
  refcount"

* tag 'afs-fixes-20220802' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs:
  afs: Fix access after dec in put functions
  afs: Use refcount_t rather than atomic_t
  • Loading branch information
torvalds committed Aug 9, 2022
2 parents 426b4ca + 2757a4d commit 4b22e20
Show file tree
Hide file tree
Showing 9 changed files with 124 additions and 116 deletions.
61 changes: 29 additions & 32 deletions fs/afs/cell.c
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ static struct afs_cell *afs_alloc_cell(struct afs_net *net,
cell->name[i] = tolower(name[i]);
cell->name[i] = 0;

atomic_set(&cell->ref, 1);
refcount_set(&cell->ref, 1);
atomic_set(&cell->active, 0);
INIT_WORK(&cell->manager, afs_manage_cell_work);
cell->volumes = RB_ROOT;
Expand Down Expand Up @@ -287,15 +287,15 @@ struct afs_cell *afs_lookup_cell(struct afs_net *net,
cell = candidate;
candidate = NULL;
atomic_set(&cell->active, 2);
trace_afs_cell(cell->debug_id, atomic_read(&cell->ref), 2, afs_cell_trace_insert);
trace_afs_cell(cell->debug_id, refcount_read(&cell->ref), 2, afs_cell_trace_insert);
rb_link_node_rcu(&cell->net_node, parent, pp);
rb_insert_color(&cell->net_node, &net->cells);
up_write(&net->cells_lock);

afs_queue_cell(cell, afs_cell_trace_get_queue_new);

wait_for_cell:
trace_afs_cell(cell->debug_id, atomic_read(&cell->ref), atomic_read(&cell->active),
trace_afs_cell(cell->debug_id, refcount_read(&cell->ref), atomic_read(&cell->active),
afs_cell_trace_wait);
_debug("wait_for_cell");
wait_var_event(&cell->state,
Expand Down Expand Up @@ -490,13 +490,13 @@ static void afs_cell_destroy(struct rcu_head *rcu)
{
struct afs_cell *cell = container_of(rcu, struct afs_cell, rcu);
struct afs_net *net = cell->net;
int u;
int r;

_enter("%p{%s}", cell, cell->name);

u = atomic_read(&cell->ref);
ASSERTCMP(u, ==, 0);
trace_afs_cell(cell->debug_id, u, atomic_read(&cell->active), afs_cell_trace_free);
r = refcount_read(&cell->ref);
ASSERTCMP(r, ==, 0);
trace_afs_cell(cell->debug_id, r, atomic_read(&cell->active), afs_cell_trace_free);

afs_put_vlserverlist(net, rcu_access_pointer(cell->vl_servers));
afs_unuse_cell(net, cell->alias_of, afs_cell_trace_unuse_alias);
Expand Down Expand Up @@ -539,13 +539,10 @@ void afs_cells_timer(struct timer_list *timer)
*/
struct afs_cell *afs_get_cell(struct afs_cell *cell, enum afs_cell_trace reason)
{
int u;
int r;

if (atomic_read(&cell->ref) <= 0)
BUG();

u = atomic_inc_return(&cell->ref);
trace_afs_cell(cell->debug_id, u, atomic_read(&cell->active), reason);
__refcount_inc(&cell->ref, &r);
trace_afs_cell(cell->debug_id, r + 1, atomic_read(&cell->active), reason);
return cell;
}

Expand All @@ -556,12 +553,14 @@ void afs_put_cell(struct afs_cell *cell, enum afs_cell_trace reason)
{
if (cell) {
unsigned int debug_id = cell->debug_id;
unsigned int u, a;
unsigned int a;
bool zero;
int r;

a = atomic_read(&cell->active);
u = atomic_dec_return(&cell->ref);
trace_afs_cell(debug_id, u, a, reason);
if (u == 0) {
zero = __refcount_dec_and_test(&cell->ref, &r);
trace_afs_cell(debug_id, r - 1, a, reason);
if (zero) {
a = atomic_read(&cell->active);
WARN(a != 0, "Cell active count %u > 0\n", a);
call_rcu(&cell->rcu, afs_cell_destroy);
Expand All @@ -574,14 +573,12 @@ void afs_put_cell(struct afs_cell *cell, enum afs_cell_trace reason)
*/
struct afs_cell *afs_use_cell(struct afs_cell *cell, enum afs_cell_trace reason)
{
int u, a;

if (atomic_read(&cell->ref) <= 0)
BUG();
int r, a;

u = atomic_read(&cell->ref);
r = refcount_read(&cell->ref);
WARN_ON(r == 0);
a = atomic_inc_return(&cell->active);
trace_afs_cell(cell->debug_id, u, a, reason);
trace_afs_cell(cell->debug_id, r, a, reason);
return cell;
}

Expand All @@ -593,7 +590,7 @@ void afs_unuse_cell(struct afs_net *net, struct afs_cell *cell, enum afs_cell_tr
{
unsigned int debug_id;
time64_t now, expire_delay;
int u, a;
int r, a;

if (!cell)
return;
Expand All @@ -607,9 +604,9 @@ void afs_unuse_cell(struct afs_net *net, struct afs_cell *cell, enum afs_cell_tr
expire_delay = afs_cell_gc_delay;

debug_id = cell->debug_id;
u = atomic_read(&cell->ref);
r = refcount_read(&cell->ref);
a = atomic_dec_return(&cell->active);
trace_afs_cell(debug_id, u, a, reason);
trace_afs_cell(debug_id, r, a, reason);
WARN_ON(a == 0);
if (a == 1)
/* 'cell' may now be garbage collected. */
Expand All @@ -621,11 +618,11 @@ void afs_unuse_cell(struct afs_net *net, struct afs_cell *cell, enum afs_cell_tr
*/
void afs_see_cell(struct afs_cell *cell, enum afs_cell_trace reason)
{
int u, a;
int r, a;

u = atomic_read(&cell->ref);
r = refcount_read(&cell->ref);
a = atomic_read(&cell->active);
trace_afs_cell(cell->debug_id, u, a, reason);
trace_afs_cell(cell->debug_id, r, a, reason);
}

/*
Expand Down Expand Up @@ -739,7 +736,7 @@ static void afs_manage_cell(struct afs_cell *cell)
active = 1;
if (atomic_try_cmpxchg_relaxed(&cell->active, &active, 0)) {
rb_erase(&cell->net_node, &net->cells);
trace_afs_cell(cell->debug_id, atomic_read(&cell->ref), 0,
trace_afs_cell(cell->debug_id, refcount_read(&cell->ref), 0,
afs_cell_trace_unuse_delete);
smp_store_release(&cell->state, AFS_CELL_REMOVED);
}
Expand Down Expand Up @@ -866,15 +863,15 @@ void afs_manage_cells(struct work_struct *work)
bool sched_cell = false;

active = atomic_read(&cell->active);
trace_afs_cell(cell->debug_id, atomic_read(&cell->ref),
trace_afs_cell(cell->debug_id, refcount_read(&cell->ref),
active, afs_cell_trace_manage);

ASSERTCMP(active, >=, 1);

if (purging) {
if (test_and_clear_bit(AFS_CELL_FL_NO_GC, &cell->flags)) {
active = atomic_dec_return(&cell->active);
trace_afs_cell(cell->debug_id, atomic_read(&cell->ref),
trace_afs_cell(cell->debug_id, refcount_read(&cell->ref),
active, afs_cell_trace_unuse_pin);
}
}
Expand Down
4 changes: 2 additions & 2 deletions fs/afs/cmservice.c
Original file line number Diff line number Diff line change
Expand Up @@ -212,8 +212,8 @@ static void SRXAFSCB_CallBack(struct work_struct *work)
* to maintain cache coherency.
*/
if (call->server) {
trace_afs_server(call->server,
atomic_read(&call->server->ref),
trace_afs_server(call->server->debug_id,
refcount_read(&call->server->ref),
atomic_read(&call->server->active),
afs_server_trace_callback);
afs_break_callbacks(call->server, call->count, call->request);
Expand Down
16 changes: 8 additions & 8 deletions fs/afs/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ struct afs_call {
};
struct afs_operation *op;
unsigned int server_index;
atomic_t usage;
refcount_t ref;
enum afs_call_state state;
spinlock_t state_lock;
int error; /* error code */
Expand Down Expand Up @@ -365,7 +365,7 @@ struct afs_cell {
struct hlist_node proc_link; /* /proc cell list link */
time64_t dns_expiry; /* Time AFSDB/SRV record expires */
time64_t last_inactive; /* Time of last drop of usage count */
atomic_t ref; /* Struct refcount */
refcount_t ref; /* Struct refcount */
atomic_t active; /* Active usage counter */
unsigned long flags;
#define AFS_CELL_FL_NO_GC 0 /* The cell was added manually, don't auto-gc */
Expand Down Expand Up @@ -410,7 +410,7 @@ struct afs_vlserver {
#define AFS_VLSERVER_FL_IS_YFS 2 /* Server is YFS not AFS */
#define AFS_VLSERVER_FL_RESPONDING 3 /* VL server is responding */
rwlock_t lock; /* Lock on addresses */
atomic_t usage;
refcount_t ref;
unsigned int rtt; /* Server's current RTT in uS */

/* Probe state */
Expand Down Expand Up @@ -446,7 +446,7 @@ struct afs_vlserver_entry {

struct afs_vlserver_list {
struct rcu_head rcu;
atomic_t usage;
refcount_t ref;
u8 nr_servers;
u8 index; /* Server currently in use */
u8 preferred; /* Preferred server */
Expand Down Expand Up @@ -517,7 +517,7 @@ struct afs_server {
#define AFS_SERVER_FL_NO_IBULK 17 /* Fileserver doesn't support FS.InlineBulkStatus */
#define AFS_SERVER_FL_NO_RM2 18 /* Fileserver doesn't support YFS.RemoveFile2 */
#define AFS_SERVER_FL_HAS_FS64 19 /* Fileserver supports FS.{Fetch,Store}Data64 */
atomic_t ref; /* Object refcount */
refcount_t ref; /* Object refcount */
atomic_t active; /* Active user count */
u32 addr_version; /* Address list version */
unsigned int rtt; /* Server's current RTT in uS */
Expand Down Expand Up @@ -571,7 +571,7 @@ struct afs_volume {
struct rcu_head rcu;
afs_volid_t vid; /* volume ID */
};
atomic_t usage;
refcount_t ref;
time64_t update_at; /* Time at which to next update */
struct afs_cell *cell; /* Cell to which belongs (pins ref) */
struct rb_node cell_node; /* Link in cell->volumes */
Expand Down Expand Up @@ -1493,14 +1493,14 @@ extern int afs_end_vlserver_operation(struct afs_vl_cursor *);
*/
static inline struct afs_vlserver *afs_get_vlserver(struct afs_vlserver *vlserver)
{
atomic_inc(&vlserver->usage);
refcount_inc(&vlserver->ref);
return vlserver;
}

static inline struct afs_vlserver_list *afs_get_vlserverlist(struct afs_vlserver_list *vllist)
{
if (vllist)
atomic_inc(&vllist->usage);
refcount_inc(&vllist->ref);
return vllist;
}

Expand Down
6 changes: 3 additions & 3 deletions fs/afs/proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ static int afs_proc_cells_show(struct seq_file *m, void *v)

/* display one cell per line on subsequent lines */
seq_printf(m, "%3u %3u %6lld %2u %2u %s\n",
atomic_read(&cell->ref),
refcount_read(&cell->ref),
atomic_read(&cell->active),
cell->dns_expiry - ktime_get_real_seconds(),
vllist ? vllist->nr_servers : 0,
Expand Down Expand Up @@ -217,7 +217,7 @@ static int afs_proc_cell_volumes_show(struct seq_file *m, void *v)
}

seq_printf(m, "%3d %08llx %s %s\n",
atomic_read(&vol->usage), vol->vid,
refcount_read(&vol->ref), vol->vid,
afs_vol_types[vol->type],
vol->name);

Expand Down Expand Up @@ -388,7 +388,7 @@ static int afs_proc_servers_show(struct seq_file *m, void *v)
alist = rcu_dereference(server->addresses);
seq_printf(m, "%pU %3d %3d\n",
&server->uuid,
atomic_read(&server->ref),
refcount_read(&server->ref),
atomic_read(&server->active));
seq_printf(m, " - info: fl=%lx rtt=%u brk=%x\n",
server->flags, server->rtt, server->cb_s_break);
Expand Down
31 changes: 17 additions & 14 deletions fs/afs/rxrpc.c
Original file line number Diff line number Diff line change
Expand Up @@ -145,14 +145,14 @@ static struct afs_call *afs_alloc_call(struct afs_net *net,
call->type = type;
call->net = net;
call->debug_id = atomic_inc_return(&rxrpc_debug_id);
atomic_set(&call->usage, 1);
refcount_set(&call->ref, 1);
INIT_WORK(&call->async_work, afs_process_async_call);
init_waitqueue_head(&call->waitq);
spin_lock_init(&call->state_lock);
call->iter = &call->def_iter;

o = atomic_inc_return(&net->nr_outstanding_calls);
trace_afs_call(call, afs_call_trace_alloc, 1, o,
trace_afs_call(call->debug_id, afs_call_trace_alloc, 1, o,
__builtin_return_address(0));
return call;
}
Expand All @@ -163,14 +163,16 @@ static struct afs_call *afs_alloc_call(struct afs_net *net,
void afs_put_call(struct afs_call *call)
{
struct afs_net *net = call->net;
int n = atomic_dec_return(&call->usage);
int o = atomic_read(&net->nr_outstanding_calls);
unsigned int debug_id = call->debug_id;
bool zero;
int r, o;

trace_afs_call(call, afs_call_trace_put, n, o,
zero = __refcount_dec_and_test(&call->ref, &r);
o = atomic_read(&net->nr_outstanding_calls);
trace_afs_call(debug_id, afs_call_trace_put, r - 1, o,
__builtin_return_address(0));

ASSERTCMP(n, >=, 0);
if (n == 0) {
if (zero) {
ASSERT(!work_pending(&call->async_work));
ASSERT(call->type->name != NULL);

Expand All @@ -185,7 +187,7 @@ void afs_put_call(struct afs_call *call)
afs_put_addrlist(call->alist);
kfree(call->request);

trace_afs_call(call, afs_call_trace_free, 0, o,
trace_afs_call(call->debug_id, afs_call_trace_free, 0, o,
__builtin_return_address(0));
kfree(call);

Expand All @@ -198,9 +200,11 @@ void afs_put_call(struct afs_call *call)
static struct afs_call *afs_get_call(struct afs_call *call,
enum afs_call_trace why)
{
int u = atomic_inc_return(&call->usage);
int r;

trace_afs_call(call, why, u,
__refcount_inc(&call->ref, &r);

trace_afs_call(call->debug_id, why, r + 1,
atomic_read(&call->net->nr_outstanding_calls),
__builtin_return_address(0));
return call;
Expand Down Expand Up @@ -668,14 +672,13 @@ static void afs_wake_up_async_call(struct sock *sk, struct rxrpc_call *rxcall,
unsigned long call_user_ID)
{
struct afs_call *call = (struct afs_call *)call_user_ID;
int u;
int r;

trace_afs_notify_call(rxcall, call);
call->need_attention = true;

u = atomic_fetch_add_unless(&call->usage, 1, 0);
if (u != 0) {
trace_afs_call(call, afs_call_trace_wake, u + 1,
if (__refcount_inc_not_zero(&call->ref, &r)) {
trace_afs_call(call->debug_id, afs_call_trace_wake, r + 1,
atomic_read(&call->net->nr_outstanding_calls),
__builtin_return_address(0));

Expand Down
Loading

0 comments on commit 4b22e20

Please sign in to comment.