Commit 4b22e207 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'afs-fixes-20220802' of git://git.kernel.org/pub/scm/linux/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
parents 426b4ca2 2757a4dc
...@@ -158,7 +158,7 @@ static struct afs_cell *afs_alloc_cell(struct afs_net *net, ...@@ -158,7 +158,7 @@ static struct afs_cell *afs_alloc_cell(struct afs_net *net,
cell->name[i] = tolower(name[i]); cell->name[i] = tolower(name[i]);
cell->name[i] = 0; cell->name[i] = 0;
atomic_set(&cell->ref, 1); refcount_set(&cell->ref, 1);
atomic_set(&cell->active, 0); atomic_set(&cell->active, 0);
INIT_WORK(&cell->manager, afs_manage_cell_work); INIT_WORK(&cell->manager, afs_manage_cell_work);
cell->volumes = RB_ROOT; cell->volumes = RB_ROOT;
...@@ -287,7 +287,7 @@ struct afs_cell *afs_lookup_cell(struct afs_net *net, ...@@ -287,7 +287,7 @@ struct afs_cell *afs_lookup_cell(struct afs_net *net,
cell = candidate; cell = candidate;
candidate = NULL; candidate = NULL;
atomic_set(&cell->active, 2); 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_link_node_rcu(&cell->net_node, parent, pp);
rb_insert_color(&cell->net_node, &net->cells); rb_insert_color(&cell->net_node, &net->cells);
up_write(&net->cells_lock); up_write(&net->cells_lock);
...@@ -295,7 +295,7 @@ struct afs_cell *afs_lookup_cell(struct afs_net *net, ...@@ -295,7 +295,7 @@ struct afs_cell *afs_lookup_cell(struct afs_net *net,
afs_queue_cell(cell, afs_cell_trace_get_queue_new); afs_queue_cell(cell, afs_cell_trace_get_queue_new);
wait_for_cell: 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); afs_cell_trace_wait);
_debug("wait_for_cell"); _debug("wait_for_cell");
wait_var_event(&cell->state, wait_var_event(&cell->state,
...@@ -490,13 +490,13 @@ static void afs_cell_destroy(struct rcu_head *rcu) ...@@ -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_cell *cell = container_of(rcu, struct afs_cell, rcu);
struct afs_net *net = cell->net; struct afs_net *net = cell->net;
int u; int r;
_enter("%p{%s}", cell, cell->name); _enter("%p{%s}", cell, cell->name);
u = atomic_read(&cell->ref); r = refcount_read(&cell->ref);
ASSERTCMP(u, ==, 0); ASSERTCMP(r, ==, 0);
trace_afs_cell(cell->debug_id, u, atomic_read(&cell->active), afs_cell_trace_free); 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_put_vlserverlist(net, rcu_access_pointer(cell->vl_servers));
afs_unuse_cell(net, cell->alias_of, afs_cell_trace_unuse_alias); afs_unuse_cell(net, cell->alias_of, afs_cell_trace_unuse_alias);
...@@ -539,13 +539,10 @@ void afs_cells_timer(struct timer_list *timer) ...@@ -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) 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) __refcount_inc(&cell->ref, &r);
BUG(); trace_afs_cell(cell->debug_id, r + 1, atomic_read(&cell->active), reason);
u = atomic_inc_return(&cell->ref);
trace_afs_cell(cell->debug_id, u, atomic_read(&cell->active), reason);
return cell; return cell;
} }
...@@ -556,12 +553,14 @@ void afs_put_cell(struct afs_cell *cell, enum afs_cell_trace reason) ...@@ -556,12 +553,14 @@ void afs_put_cell(struct afs_cell *cell, enum afs_cell_trace reason)
{ {
if (cell) { if (cell) {
unsigned int debug_id = cell->debug_id; unsigned int debug_id = cell->debug_id;
unsigned int u, a; unsigned int a;
bool zero;
int r;
a = atomic_read(&cell->active); a = atomic_read(&cell->active);
u = atomic_dec_return(&cell->ref); zero = __refcount_dec_and_test(&cell->ref, &r);
trace_afs_cell(debug_id, u, a, reason); trace_afs_cell(debug_id, r - 1, a, reason);
if (u == 0) { if (zero) {
a = atomic_read(&cell->active); a = atomic_read(&cell->active);
WARN(a != 0, "Cell active count %u > 0\n", a); WARN(a != 0, "Cell active count %u > 0\n", a);
call_rcu(&cell->rcu, afs_cell_destroy); call_rcu(&cell->rcu, afs_cell_destroy);
...@@ -574,14 +573,12 @@ void afs_put_cell(struct afs_cell *cell, enum afs_cell_trace reason) ...@@ -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) struct afs_cell *afs_use_cell(struct afs_cell *cell, enum afs_cell_trace reason)
{ {
int u, a; int r, a;
if (atomic_read(&cell->ref) <= 0)
BUG();
u = atomic_read(&cell->ref); r = refcount_read(&cell->ref);
WARN_ON(r == 0);
a = atomic_inc_return(&cell->active); 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; return cell;
} }
...@@ -593,7 +590,7 @@ void afs_unuse_cell(struct afs_net *net, struct afs_cell *cell, enum afs_cell_tr ...@@ -593,7 +590,7 @@ void afs_unuse_cell(struct afs_net *net, struct afs_cell *cell, enum afs_cell_tr
{ {
unsigned int debug_id; unsigned int debug_id;
time64_t now, expire_delay; time64_t now, expire_delay;
int u, a; int r, a;
if (!cell) if (!cell)
return; return;
...@@ -607,9 +604,9 @@ void afs_unuse_cell(struct afs_net *net, struct afs_cell *cell, enum afs_cell_tr ...@@ -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; expire_delay = afs_cell_gc_delay;
debug_id = cell->debug_id; debug_id = cell->debug_id;
u = atomic_read(&cell->ref); r = refcount_read(&cell->ref);
a = atomic_dec_return(&cell->active); 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); WARN_ON(a == 0);
if (a == 1) if (a == 1)
/* 'cell' may now be garbage collected. */ /* 'cell' may now be garbage collected. */
...@@ -621,11 +618,11 @@ void afs_unuse_cell(struct afs_net *net, struct afs_cell *cell, enum afs_cell_tr ...@@ -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) 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); a = atomic_read(&cell->active);
trace_afs_cell(cell->debug_id, u, a, reason); trace_afs_cell(cell->debug_id, r, a, reason);
} }
/* /*
...@@ -739,7 +736,7 @@ static void afs_manage_cell(struct afs_cell *cell) ...@@ -739,7 +736,7 @@ static void afs_manage_cell(struct afs_cell *cell)
active = 1; active = 1;
if (atomic_try_cmpxchg_relaxed(&cell->active, &active, 0)) { if (atomic_try_cmpxchg_relaxed(&cell->active, &active, 0)) {
rb_erase(&cell->net_node, &net->cells); 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); afs_cell_trace_unuse_delete);
smp_store_release(&cell->state, AFS_CELL_REMOVED); smp_store_release(&cell->state, AFS_CELL_REMOVED);
} }
...@@ -866,7 +863,7 @@ void afs_manage_cells(struct work_struct *work) ...@@ -866,7 +863,7 @@ void afs_manage_cells(struct work_struct *work)
bool sched_cell = false; bool sched_cell = false;
active = atomic_read(&cell->active); 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); active, afs_cell_trace_manage);
ASSERTCMP(active, >=, 1); ASSERTCMP(active, >=, 1);
...@@ -874,7 +871,7 @@ void afs_manage_cells(struct work_struct *work) ...@@ -874,7 +871,7 @@ void afs_manage_cells(struct work_struct *work)
if (purging) { if (purging) {
if (test_and_clear_bit(AFS_CELL_FL_NO_GC, &cell->flags)) { if (test_and_clear_bit(AFS_CELL_FL_NO_GC, &cell->flags)) {
active = atomic_dec_return(&cell->active); 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); active, afs_cell_trace_unuse_pin);
} }
} }
......
...@@ -212,8 +212,8 @@ static void SRXAFSCB_CallBack(struct work_struct *work) ...@@ -212,8 +212,8 @@ static void SRXAFSCB_CallBack(struct work_struct *work)
* to maintain cache coherency. * to maintain cache coherency.
*/ */
if (call->server) { if (call->server) {
trace_afs_server(call->server, trace_afs_server(call->server->debug_id,
atomic_read(&call->server->ref), refcount_read(&call->server->ref),
atomic_read(&call->server->active), atomic_read(&call->server->active),
afs_server_trace_callback); afs_server_trace_callback);
afs_break_callbacks(call->server, call->count, call->request); afs_break_callbacks(call->server, call->count, call->request);
......
...@@ -122,7 +122,7 @@ struct afs_call { ...@@ -122,7 +122,7 @@ struct afs_call {
}; };
struct afs_operation *op; struct afs_operation *op;
unsigned int server_index; unsigned int server_index;
atomic_t usage; refcount_t ref;
enum afs_call_state state; enum afs_call_state state;
spinlock_t state_lock; spinlock_t state_lock;
int error; /* error code */ int error; /* error code */
...@@ -365,7 +365,7 @@ struct afs_cell { ...@@ -365,7 +365,7 @@ struct afs_cell {
struct hlist_node proc_link; /* /proc cell list link */ struct hlist_node proc_link; /* /proc cell list link */
time64_t dns_expiry; /* Time AFSDB/SRV record expires */ time64_t dns_expiry; /* Time AFSDB/SRV record expires */
time64_t last_inactive; /* Time of last drop of usage count */ 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 */ atomic_t active; /* Active usage counter */
unsigned long flags; unsigned long flags;
#define AFS_CELL_FL_NO_GC 0 /* The cell was added manually, don't auto-gc */ #define AFS_CELL_FL_NO_GC 0 /* The cell was added manually, don't auto-gc */
...@@ -410,7 +410,7 @@ struct afs_vlserver { ...@@ -410,7 +410,7 @@ struct afs_vlserver {
#define AFS_VLSERVER_FL_IS_YFS 2 /* Server is YFS not AFS */ #define AFS_VLSERVER_FL_IS_YFS 2 /* Server is YFS not AFS */
#define AFS_VLSERVER_FL_RESPONDING 3 /* VL server is responding */ #define AFS_VLSERVER_FL_RESPONDING 3 /* VL server is responding */
rwlock_t lock; /* Lock on addresses */ rwlock_t lock; /* Lock on addresses */
atomic_t usage; refcount_t ref;
unsigned int rtt; /* Server's current RTT in uS */ unsigned int rtt; /* Server's current RTT in uS */
/* Probe state */ /* Probe state */
...@@ -446,7 +446,7 @@ struct afs_vlserver_entry { ...@@ -446,7 +446,7 @@ struct afs_vlserver_entry {
struct afs_vlserver_list { struct afs_vlserver_list {
struct rcu_head rcu; struct rcu_head rcu;
atomic_t usage; refcount_t ref;
u8 nr_servers; u8 nr_servers;
u8 index; /* Server currently in use */ u8 index; /* Server currently in use */
u8 preferred; /* Preferred server */ u8 preferred; /* Preferred server */
...@@ -517,7 +517,7 @@ struct afs_server { ...@@ -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_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_NO_RM2 18 /* Fileserver doesn't support YFS.RemoveFile2 */
#define AFS_SERVER_FL_HAS_FS64 19 /* Fileserver supports FS.{Fetch,Store}Data64 */ #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 */ atomic_t active; /* Active user count */
u32 addr_version; /* Address list version */ u32 addr_version; /* Address list version */
unsigned int rtt; /* Server's current RTT in uS */ unsigned int rtt; /* Server's current RTT in uS */
...@@ -571,7 +571,7 @@ struct afs_volume { ...@@ -571,7 +571,7 @@ struct afs_volume {
struct rcu_head rcu; struct rcu_head rcu;
afs_volid_t vid; /* volume ID */ afs_volid_t vid; /* volume ID */
}; };
atomic_t usage; refcount_t ref;
time64_t update_at; /* Time at which to next update */ time64_t update_at; /* Time at which to next update */
struct afs_cell *cell; /* Cell to which belongs (pins ref) */ struct afs_cell *cell; /* Cell to which belongs (pins ref) */
struct rb_node cell_node; /* Link in cell->volumes */ struct rb_node cell_node; /* Link in cell->volumes */
...@@ -1493,14 +1493,14 @@ extern int afs_end_vlserver_operation(struct afs_vl_cursor *); ...@@ -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) static inline struct afs_vlserver *afs_get_vlserver(struct afs_vlserver *vlserver)
{ {
atomic_inc(&vlserver->usage); refcount_inc(&vlserver->ref);
return vlserver; return vlserver;
} }
static inline struct afs_vlserver_list *afs_get_vlserverlist(struct afs_vlserver_list *vllist) static inline struct afs_vlserver_list *afs_get_vlserverlist(struct afs_vlserver_list *vllist)
{ {
if (vllist) if (vllist)
atomic_inc(&vllist->usage); refcount_inc(&vllist->ref);
return vllist; return vllist;
} }
......
...@@ -47,7 +47,7 @@ static int afs_proc_cells_show(struct seq_file *m, void *v) ...@@ -47,7 +47,7 @@ static int afs_proc_cells_show(struct seq_file *m, void *v)
/* display one cell per line on subsequent lines */ /* display one cell per line on subsequent lines */
seq_printf(m, "%3u %3u %6lld %2u %2u %s\n", seq_printf(m, "%3u %3u %6lld %2u %2u %s\n",
atomic_read(&cell->ref), refcount_read(&cell->ref),
atomic_read(&cell->active), atomic_read(&cell->active),
cell->dns_expiry - ktime_get_real_seconds(), cell->dns_expiry - ktime_get_real_seconds(),
vllist ? vllist->nr_servers : 0, vllist ? vllist->nr_servers : 0,
...@@ -217,7 +217,7 @@ static int afs_proc_cell_volumes_show(struct seq_file *m, void *v) ...@@ -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", 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], afs_vol_types[vol->type],
vol->name); vol->name);
...@@ -388,7 +388,7 @@ static int afs_proc_servers_show(struct seq_file *m, void *v) ...@@ -388,7 +388,7 @@ static int afs_proc_servers_show(struct seq_file *m, void *v)
alist = rcu_dereference(server->addresses); alist = rcu_dereference(server->addresses);
seq_printf(m, "%pU %3d %3d\n", seq_printf(m, "%pU %3d %3d\n",
&server->uuid, &server->uuid,
atomic_read(&server->ref), refcount_read(&server->ref),
atomic_read(&server->active)); atomic_read(&server->active));
seq_printf(m, " - info: fl=%lx rtt=%u brk=%x\n", seq_printf(m, " - info: fl=%lx rtt=%u brk=%x\n",
server->flags, server->rtt, server->cb_s_break); server->flags, server->rtt, server->cb_s_break);
......
...@@ -145,14 +145,14 @@ static struct afs_call *afs_alloc_call(struct afs_net *net, ...@@ -145,14 +145,14 @@ static struct afs_call *afs_alloc_call(struct afs_net *net,
call->type = type; call->type = type;
call->net = net; call->net = net;
call->debug_id = atomic_inc_return(&rxrpc_debug_id); 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_WORK(&call->async_work, afs_process_async_call);
init_waitqueue_head(&call->waitq); init_waitqueue_head(&call->waitq);
spin_lock_init(&call->state_lock); spin_lock_init(&call->state_lock);
call->iter = &call->def_iter; call->iter = &call->def_iter;
o = atomic_inc_return(&net->nr_outstanding_calls); 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)); __builtin_return_address(0));
return call; return call;
} }
...@@ -163,14 +163,16 @@ static struct afs_call *afs_alloc_call(struct afs_net *net, ...@@ -163,14 +163,16 @@ static struct afs_call *afs_alloc_call(struct afs_net *net,
void afs_put_call(struct afs_call *call) void afs_put_call(struct afs_call *call)
{ {
struct afs_net *net = call->net; struct afs_net *net = call->net;
int n = atomic_dec_return(&call->usage); unsigned int debug_id = call->debug_id;
int o = atomic_read(&net->nr_outstanding_calls); 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)); __builtin_return_address(0));
ASSERTCMP(n, >=, 0); if (zero) {
if (n == 0) {
ASSERT(!work_pending(&call->async_work)); ASSERT(!work_pending(&call->async_work));
ASSERT(call->type->name != NULL); ASSERT(call->type->name != NULL);
...@@ -185,7 +187,7 @@ void afs_put_call(struct afs_call *call) ...@@ -185,7 +187,7 @@ void afs_put_call(struct afs_call *call)
afs_put_addrlist(call->alist); afs_put_addrlist(call->alist);
kfree(call->request); 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)); __builtin_return_address(0));
kfree(call); kfree(call);
...@@ -198,9 +200,11 @@ void afs_put_call(struct afs_call *call) ...@@ -198,9 +200,11 @@ void afs_put_call(struct afs_call *call)
static struct afs_call *afs_get_call(struct afs_call *call, static struct afs_call *afs_get_call(struct afs_call *call,
enum afs_call_trace why) 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), atomic_read(&call->net->nr_outstanding_calls),
__builtin_return_address(0)); __builtin_return_address(0));
return call; return call;
...@@ -668,14 +672,13 @@ static void afs_wake_up_async_call(struct sock *sk, struct rxrpc_call *rxcall, ...@@ -668,14 +672,13 @@ static void afs_wake_up_async_call(struct sock *sk, struct rxrpc_call *rxcall,
unsigned long call_user_ID) unsigned long call_user_ID)
{ {
struct afs_call *call = (struct afs_call *)call_user_ID; struct afs_call *call = (struct afs_call *)call_user_ID;
int u; int r;
trace_afs_notify_call(rxcall, call); trace_afs_notify_call(rxcall, call);
call->need_attention = true; call->need_attention = true;
u = atomic_fetch_add_unless(&call->usage, 1, 0); if (__refcount_inc_not_zero(&call->ref, &r)) {
if (u != 0) { trace_afs_call(call->debug_id, afs_call_trace_wake, r + 1,
trace_afs_call(call, afs_call_trace_wake, u + 1,
atomic_read(&call->net->nr_outstanding_calls), atomic_read(&call->net->nr_outstanding_calls),
__builtin_return_address(0)); __builtin_return_address(0));
......
...@@ -228,7 +228,7 @@ static struct afs_server *afs_alloc_server(struct afs_cell *cell, ...@@ -228,7 +228,7 @@ static struct afs_server *afs_alloc_server(struct afs_cell *cell,
if (!server) if (!server)
goto enomem; goto enomem;
atomic_set(&server->ref, 1); refcount_set(&server->ref, 1);
atomic_set(&server->active, 1); atomic_set(&server->active, 1);
server->debug_id = atomic_inc_return(&afs_server_debug_id); server->debug_id = atomic_inc_return(&afs_server_debug_id);
RCU_INIT_POINTER(server->addresses, alist); RCU_INIT_POINTER(server->addresses, alist);
...@@ -243,7 +243,7 @@ static struct afs_server *afs_alloc_server(struct afs_cell *cell, ...@@ -243,7 +243,7 @@ static struct afs_server *afs_alloc_server(struct afs_cell *cell,
server->rtt = UINT_MAX; server->rtt = UINT_MAX;
afs_inc_servers_outstanding(net); afs_inc_servers_outstanding(net);
trace_afs_server(server, 1, 1, afs_server_trace_alloc); trace_afs_server(server->debug_id, 1, 1, afs_server_trace_alloc);
_leave(" = %p", server); _leave(" = %p", server);
return server; return server;
...@@ -352,9 +352,12 @@ void afs_servers_timer(struct timer_list *timer) ...@@ -352,9 +352,12 @@ void afs_servers_timer(struct timer_list *timer)
struct afs_server *afs_get_server(struct afs_server *server, struct afs_server *afs_get_server(struct afs_server *server,
enum afs_server_trace reason) enum afs_server_trace reason)
{ {
unsigned int u = atomic_inc_return(&server->ref); unsigned int a;
int r;
trace_afs_server(server, u, atomic_read(&server->active), reason); __refcount_inc(&server->ref, &r);
a = atomic_read(&server->active);
trace_afs_server(server->debug_id, r + 1, a, reason);
return server; return server;
} }
...@@ -364,14 +367,14 @@ struct afs_server *afs_get_server(struct afs_server *server, ...@@ -364,14 +367,14 @@ struct afs_server *afs_get_server(struct afs_server *server,
static struct afs_server *afs_maybe_use_server(struct afs_server *server, static struct afs_server *afs_maybe_use_server(struct afs_server *server,
enum afs_server_trace reason) enum afs_server_trace reason)
{ {
unsigned int r = atomic_fetch_add_unless(&server->ref, 1, 0);
unsigned int a; unsigned int a;
int r;
if (r == 0) if (!__refcount_inc_not_zero(&server->ref, &r))
return NULL; return NULL;
a = atomic_inc_return(&server->active); a = atomic_inc_return(&server->active);
trace_afs_server(server, r, a, reason); trace_afs_server(server->debug_id, r + 1, a, reason);
return server; return server;
} }
...@@ -380,10 +383,13 @@ static struct afs_server *afs_maybe_use_server(struct afs_server *server, ...@@ -380,10 +383,13 @@ static struct afs_server *afs_maybe_use_server(struct afs_server *server,
*/ */
struct afs_server *afs_use_server(struct afs_server *server, enum afs_server_trace reason) struct afs_server *afs_use_server(struct afs_server *server, enum afs_server_trace reason)
{ {
unsigned int r = atomic_inc_return(&server->ref); unsigned int a;
unsigned int a = atomic_inc_return(&server->active); int r;
trace_afs_server(server, r, a, reason); __refcount_inc(&server->ref, &r);
a = atomic_inc_return(&server->active);
trace_afs_server(server->debug_id, r + 1, a, reason);
return server; return server;
} }
...@@ -393,14 +399,17 @@ struct afs_server *afs_use_server(struct afs_server *server, enum afs_server_tra ...@@ -393,14 +399,17 @@ struct afs_server *afs_use_server(struct afs_server *server, enum afs_server_tra
void afs_put_server(struct afs_net *net, struct afs_server *server, void afs_put_server(struct afs_net *net, struct afs_server *server,
enum afs_server_trace reason) enum afs_server_trace reason)
{ {
unsigned int usage; unsigned int a, debug_id = server->debug_id;
bool zero;
int r;
if (!server) if (!server)
return; return;
usage = atomic_dec_return(&server->ref); a = atomic_inc_return(&server->active);
trace_afs_server(server, usage, atomic_read(&server->active), reason); zero = __refcount_dec_and_test(&server->ref, &r);
if (unlikely(usage == 0)) trace_afs_server(debug_id, r - 1, a, reason);
if (unlikely(zero))
__afs_put_server(net, server); __afs_put_server(net, server);
} }
...@@ -436,7 +445,7 @@ static void afs_server_rcu(struct rcu_head *rcu) ...@@ -436,7 +445,7 @@ static void afs_server_rcu(struct rcu_head *rcu)
{ {
struct afs_server *server = container_of(rcu, struct afs_server, rcu); struct afs_server *server = container_of(rcu, struct afs_server, rcu);
trace_afs_server(server, atomic_read(&server->ref), trace_afs_server(server->debug_id, refcount_read(&server->ref),
atomic_read(&server->active), afs_server_trace_free); atomic_read(&server->active), afs_server_trace_free);
afs_put_addrlist(rcu_access_pointer(server->addresses)); afs_put_addrlist(rcu_access_pointer(server->addresses));
kfree(server); kfree(server);
...@@ -487,7 +496,7 @@ static void afs_gc_servers(struct afs_net *net, struct afs_server *gc_list) ...@@ -487,7 +496,7 @@ static void afs_gc_servers(struct afs_net *net, struct afs_server *gc_list)
active = atomic_read(&server->active); active = atomic_read(&server->active);
if (active == 0) { if (active == 0) {
trace_afs_server(server, atomic_read(&server->ref), trace_afs_server(server->debug_id, refcount_read(&server->ref),
active, afs_server_trace_gc); active, afs_server_trace_gc);
next = rcu_dereference_protected( next = rcu_dereference_protected(
server->uuid_next, lockdep_is_held(&net->fs_lock.lock)); server->uuid_next, lockdep_is_held(&net->fs_lock.lock));
...@@ -553,7 +562,7 @@ void afs_manage_servers(struct work_struct *work) ...@@ -553,7 +562,7 @@ void afs_manage_servers(struct work_struct *work)
_debug("manage %pU %u", &server->uuid, active); _debug("manage %pU %u", &server->uuid, active);
if (purging) { if (purging) {
trace_afs_server(server, atomic_read(&server->ref), trace_afs_server(server->debug_id, refcount_read(&server->ref),
active, afs_server_trace_purging); active, afs_server_trace_purging);
if (active != 0) if (active != 0)
pr_notice("Can't purge s=%08x\n", server->debug_id); pr_notice("Can't purge s=%08x\n", server->debug_id);
...@@ -633,7 +642,8 @@ static noinline bool afs_update_server_record(struct afs_operation *op, ...@@ -633,7 +642,8 @@ static noinline bool afs_update_server_record(struct afs_operation *op,
_enter(""); _enter("");
trace_afs_server(server, atomic_read(&server->ref), atomic_read(&server->active), trace_afs_server(server->debug_id, refcount_read(&server->ref),
atomic_read(&server->active),
afs_server_trace_update); afs_server_trace_update);
alist = afs_vl_lookup_addrs(op->volume->cell, op->key, &server->uuid); alist = afs_vl_lookup_addrs(op->volume->cell, op->key, &server->uuid);
......
...@@ -17,7 +17,7 @@ struct afs_vlserver *afs_alloc_vlserver(const char *name, size_t name_len, ...@@ -17,7 +17,7 @@ struct afs_vlserver *afs_alloc_vlserver(const char *name, size_t name_len,
vlserver = kzalloc(struct_size(vlserver, name, name_len + 1), vlserver = kzalloc(struct_size(vlserver, name, name_len + 1),
GFP_KERNEL); GFP_KERNEL);
if (vlserver) { if (vlserver) {
atomic_set(&vlserver->usage, 1); refcount_set(&vlserver->ref, 1);
rwlock_init(&vlserver->lock); rwlock_init(&vlserver->lock);
init_waitqueue_head(&vlserver->probe_wq); init_waitqueue_head(&vlserver->probe_wq);
spin_lock_init(&vlserver->probe_lock); spin_lock_init(&vlserver->probe_lock);
...@@ -39,13 +39,9 @@ static void afs_vlserver_rcu(struct rcu_head *rcu) ...@@ -39,13 +39,9 @@ static void afs_vlserver_rcu(struct rcu_head *rcu)
void afs_put_vlserver(struct afs_net *net, struct afs_vlserver *vlserver) void afs_put_vlserver(struct afs_net *net, struct afs_vlserver *vlserver)
{ {
if (vlserver) { if (vlserver &&
unsigned int u = atomic_dec_return(&vlserver->usage); refcount_dec_and_test(&vlserver->ref))
//_debug("VL PUT %p{%u}", vlserver, u); call_rcu(&vlserver->rcu, afs_vlserver_rcu);
if (u == 0)
call_rcu(&vlserver->rcu, afs_vlserver_rcu);
}
} }
struct afs_vlserver_list *afs_alloc_vlserver_list(unsigned int nr_servers) struct afs_vlserver_list *afs_alloc_vlserver_list(unsigned int nr_servers)
...@@ -54,7 +50,7 @@ struct afs_vlserver_list *afs_alloc_vlserver_list(unsigned int nr_servers) ...@@ -54,7 +50,7 @@ struct afs_vlserver_list *afs_alloc_vlserver_list(unsigned int nr_servers)
vllist = kzalloc(struct_size(vllist, servers, nr_servers), GFP_KERNEL); vllist = kzalloc(struct_size(vllist, servers, nr_servers), GFP_KERNEL);
if (vllist) { if (vllist) {
atomic_set(&vllist->usage, 1); refcount_set(&vllist->ref, 1);
rwlock_init(&vllist->lock); rwlock_init(&vllist->lock);
} }
...@@ -64,10 +60,7 @@ struct afs_vlserver_list *afs_alloc_vlserver_list(unsigned int nr_servers) ...@@ -64,10 +60,7 @@ struct afs_vlserver_list *afs_alloc_vlserver_list(unsigned int nr_servers)
void afs_put_vlserverlist(struct afs_net *net, struct afs_vlserver_list *vllist) void afs_put_vlserverlist(struct afs_net *net, struct afs_vlserver_list *vllist)
{ {
if (vllist) { if (vllist) {
unsigned int u = atomic_dec_return(&vllist->usage); if (refcount_dec_and_test(&vllist->ref)) {
//_debug("VLLS PUT %p{%u}", vllist, u);
if (u == 0) {
int i; int i;
for (i = 0; i < vllist->nr_servers; i++) { for (i = 0; i < vllist->nr_servers; i++) {
......
...@@ -52,7 +52,7 @@ static void afs_remove_volume_from_cell(struct afs_volume *volume) ...@@ -52,7 +52,7 @@ static void afs_remove_volume_from_cell(struct afs_volume *volume)
struct afs_cell *cell = volume->cell; struct afs_cell *cell = volume->cell;
if (!hlist_unhashed(&volume->proc_link)) { if (!hlist_unhashed(&volume->proc_link)) {
trace_afs_volume(volume->vid, atomic_read(&volume->usage), trace_afs_volume(volume->vid, refcount_read(&cell->ref),
afs_volume_trace_remove); afs_volume_trace_remove);
write_seqlock(&cell->volume_lock); write_seqlock(&cell->volume_lock);
hlist_del_rcu(&volume->proc_link); hlist_del_rcu(&volume->proc_link);
...@@ -87,7 +87,7 @@ static struct afs_volume *afs_alloc_volume(struct afs_fs_context *params, ...@@ -87,7 +87,7 @@ static struct afs_volume *afs_alloc_volume(struct afs_fs_context *params,
volume->type_force = params->force; volume->type_force = params->force;
volume->name_len = vldb->name_len; volume->name_len = vldb->name_len;
atomic_set(&volume->usage, 1); refcount_set(&volume->ref, 1);
INIT_HLIST_NODE(&volume->proc_link); INIT_HLIST_NODE(&volume->proc_link);
rwlock_init(&volume->servers_lock); rwlock_init(&volume->servers_lock);
rwlock_init(&volume->cb_v_break_lock); rwlock_init(&volume->cb_v_break_lock);
...@@ -228,7 +228,7 @@ static void afs_destroy_volume(struct afs_net *net, struct afs_volume *volume) ...@@ -228,7 +228,7 @@ static void afs_destroy_volume(struct afs_net *net, struct afs_volume *volume)
afs_remove_volume_from_cell(volume); afs_remove_volume_from_cell(volume);
afs_put_serverlist(net, rcu_access_pointer(volume->servers)); afs_put_serverlist(net, rcu_access_pointer(volume->servers));
afs_put_cell(volume->cell, afs_cell_trace_put_vol); afs_put_cell(volume->cell, afs_cell_trace_put_vol);
trace_afs_volume(volume->vid, atomic_read(&volume->usage), trace_afs_volume(volume->vid, refcount_read(&volume->ref),
afs_volume_trace_free); afs_volume_trace_free);
kfree_rcu(volume, rcu); kfree_rcu(volume, rcu);
...@@ -242,8 +242,10 @@ struct afs_volume *afs_get_volume(struct afs_volume *volume, ...@@ -242,8 +242,10 @@ struct afs_volume *afs_get_volume(struct afs_volume *volume,
enum afs_volume_trace reason) enum afs_volume_trace reason)
{ {
if (volume) { if (volume) {
int u = atomic_inc_return(&volume->usage); int r;
trace_afs_volume(volume->vid, u, reason);
__refcount_inc(&volume->ref, &r);
trace_afs_volume(volume->vid, r + 1, reason);
} }
return volume; return volume;
} }
...@@ -257,9 +259,12 @@ void afs_put_volume(struct afs_net *net, struct afs_volume *volume, ...@@ -257,9 +259,12 @@ void afs_put_volume(struct afs_net *net, struct afs_volume *volume,
{ {
if (volume) { if (volume) {
afs_volid_t vid = volume->vid; afs_volid_t vid = volume->vid;
int u = atomic_dec_return(&volume->usage); bool zero;
trace_afs_volume(vid, u, reason); int r;
if (u == 0)
zero = __refcount_dec_and_test(&volume->ref, &r);
trace_afs_volume(vid, r - 1, reason);
if (zero)
afs_destroy_volume(net, volume); afs_destroy_volume(net, volume);
} }
} }
......
...@@ -727,31 +727,31 @@ TRACE_EVENT(afs_cb_call, ...@@ -727,31 +727,31 @@ TRACE_EVENT(afs_cb_call,
); );
TRACE_EVENT(afs_call, TRACE_EVENT(afs_call,
TP_PROTO(struct afs_call *call, enum afs_call_trace op, TP_PROTO(unsigned int call_debug_id, enum afs_call_trace op,
int usage, int outstanding, const void *where), int ref, int outstanding, const void *where),
TP_ARGS(call, op, usage, outstanding, where), TP_ARGS(call_debug_id, op, ref, outstanding, where),
TP_STRUCT__entry( TP_STRUCT__entry(
__field(unsigned int, call ) __field(unsigned int, call )
__field(int, op ) __field(int, op )
__field(int, usage ) __field(int, ref )
__field(int, outstanding ) __field(int, outstanding )
__field(const void *, where ) __field(const void *, where )
), ),
TP_fast_assign( TP_fast_assign(
__entry->call = call->debug_id; __entry->call = call_debug_id;
__entry->op = op; __entry->op = op;
__entry->usage = usage; __entry->ref = ref;
__entry->outstanding = outstanding; __entry->outstanding = outstanding;
__entry->where = where; __entry->where = where;
), ),
TP_printk("c=%08x %s u=%d o=%d sp=%pSR", TP_printk("c=%08x %s r=%d o=%d sp=%pSR",
__entry->call, __entry->call,
__print_symbolic(__entry->op, afs_call_traces), __print_symbolic(__entry->op, afs_call_traces),
__entry->usage, __entry->ref,
__entry->outstanding, __entry->outstanding,
__entry->where) __entry->where)
); );
...@@ -1433,10 +1433,10 @@ TRACE_EVENT(afs_cb_miss, ...@@ -1433,10 +1433,10 @@ TRACE_EVENT(afs_cb_miss,
); );
TRACE_EVENT(afs_server, TRACE_EVENT(afs_server,
TP_PROTO(struct afs_server *server, int ref, int active, TP_PROTO(unsigned int server_debug_id, int ref, int active,
enum afs_server_trace reason), enum afs_server_trace reason),
TP_ARGS(server, ref, active, reason), TP_ARGS(server_debug_id, ref, active, reason),
TP_STRUCT__entry( TP_STRUCT__entry(
__field(unsigned int, server ) __field(unsigned int, server )
...@@ -1446,7 +1446,7 @@ TRACE_EVENT(afs_server, ...@@ -1446,7 +1446,7 @@ TRACE_EVENT(afs_server,
), ),
TP_fast_assign( TP_fast_assign(
__entry->server = server->debug_id; __entry->server = server_debug_id;
__entry->ref = ref; __entry->ref = ref;
__entry->active = active; __entry->active = active;
__entry->reason = reason; __entry->reason = reason;
...@@ -1476,36 +1476,36 @@ TRACE_EVENT(afs_volume, ...@@ -1476,36 +1476,36 @@ TRACE_EVENT(afs_volume,
__entry->reason = reason; __entry->reason = reason;
), ),
TP_printk("V=%llx %s u=%d", TP_printk("V=%llx %s ur=%d",
__entry->vid, __entry->vid,
__print_symbolic(__entry->reason, afs_volume_traces), __print_symbolic(__entry->reason, afs_volume_traces),
__entry->ref) __entry->ref)
); );
TRACE_EVENT(afs_cell, TRACE_EVENT(afs_cell,
TP_PROTO(unsigned int cell_debug_id, int usage, int active, TP_PROTO(unsigned int cell_debug_id, int ref, int active,
enum afs_cell_trace reason), enum afs_cell_trace reason),
TP_ARGS(cell_debug_id, usage, active, reason), TP_ARGS(cell_debug_id, ref, active, reason),
TP_STRUCT__entry( TP_STRUCT__entry(
__field(unsigned int, cell ) __field(unsigned int, cell )
__field(int, usage ) __field(int, ref )
__field(int, active ) __field(int, active )
__field(int, reason ) __field(int, reason )
), ),
TP_fast_assign( TP_fast_assign(
__entry->cell = cell_debug_id; __entry->cell = cell_debug_id;
__entry->usage = usage; __entry->ref = ref;
__entry->active = active; __entry->active = active;
__entry->reason = reason; __entry->reason = reason;
), ),
TP_printk("L=%08x %s u=%d a=%d", TP_printk("L=%08x %s r=%d a=%d",
__entry->cell, __entry->cell,
__print_symbolic(__entry->reason, afs_cell_traces), __print_symbolic(__entry->reason, afs_cell_traces),
__entry->usage, __entry->ref,
__entry->active) __entry->active)
); );
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment