mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-28 05:24:47 +08:00
afs: Use refcount_t rather than atomic_t
[ Upstream commitc56f9ec8b2
] Use refcount_t rather than atomic_t in afs to make use of the count checking facilities provided. Signed-off-by: David Howells <dhowells@redhat.com> Reviewed-by: Marc Dionne <marc.dionne@auristor.com> cc: linux-afs@lists.infradead.org Link: https://lore.kernel.org/r/165911277768.3745403.423349776836296452.stgit@warthog.procyon.org.uk/ # v1 Stable-dep-of:9a6b294ab4
("afs: Fix use-after-free due to get/remove race in volume tree") Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
d1fe946cb5
commit
57bf562950
@ -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,
|
|||||||
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,
|
|||||||
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,
|
||||||
@ -492,13 +492,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);
|
||||||
@ -541,13 +541,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -558,12 +555,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);
|
||||||
@ -576,14 +575,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)
|
r = refcount_read(&cell->ref);
|
||||||
BUG();
|
WARN_ON(r == 0);
|
||||||
|
|
||||||
u = atomic_read(&cell->ref);
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -595,7 +592,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;
|
||||||
@ -609,9 +606,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. */
|
||||||
@ -623,11 +620,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -753,7 +750,7 @@ again:
|
|||||||
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);
|
||||||
}
|
}
|
||||||
@ -880,7 +877,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);
|
||||||
@ -888,7 +885,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -213,7 +213,7 @@ static void SRXAFSCB_CallBack(struct work_struct *work)
|
|||||||
*/
|
*/
|
||||||
if (call->server) {
|
if (call->server) {
|
||||||
trace_afs_server(call->server,
|
trace_afs_server(call->server,
|
||||||
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);
|
||||||
|
@ -123,7 +123,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 */
|
||||||
@ -368,7 +368,7 @@ struct afs_cell {
|
|||||||
#endif
|
#endif
|
||||||
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 */
|
||||||
@ -413,7 +413,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 */
|
||||||
@ -449,7 +449,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 */
|
||||||
@ -520,7 +520,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 */
|
||||||
@ -575,7 +575,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 */
|
||||||
@ -1483,14 +1483,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)
|
|||||||
|
|
||||||
/* 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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
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)
|
|||||||
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,7 +145,7 @@ 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);
|
||||||
@ -163,14 +163,15 @@ 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);
|
bool zero;
|
||||||
int o = atomic_read(&net->nr_outstanding_calls);
|
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(call, 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);
|
||||||
|
|
||||||
@ -198,9 +199,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, 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;
|
||||||
@ -663,14 +666,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, 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,
|
|||||||
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);
|
||||||
@ -352,9 +352,10 @@ 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);
|
int r;
|
||||||
|
|
||||||
trace_afs_server(server, u, atomic_read(&server->active), reason);
|
__refcount_inc(&server->ref, &r);
|
||||||
|
trace_afs_server(server, r + 1, atomic_read(&server->active), reason);
|
||||||
return server;
|
return server;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -364,14 +365,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, r + 1, a, reason);
|
||||||
return server;
|
return server;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -380,10 +381,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, r + 1, a, reason);
|
||||||
return server;
|
return server;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -393,14 +397,15 @@ 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;
|
bool zero;
|
||||||
|
int r;
|
||||||
|
|
||||||
if (!server)
|
if (!server)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
usage = atomic_dec_return(&server->ref);
|
zero = __refcount_dec_and_test(&server->ref, &r);
|
||||||
trace_afs_server(server, usage, atomic_read(&server->active), reason);
|
trace_afs_server(server, r - 1, atomic_read(&server->active), reason);
|
||||||
if (unlikely(usage == 0))
|
if (unlikely(zero))
|
||||||
__afs_put_server(net, server);
|
__afs_put_server(net, server);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -436,7 +441,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, 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 +492,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, 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 +558,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, 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 +638,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, 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,
|
|||||||
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)
|
|||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
if (u == 0)
|
|
||||||
call_rcu(&vlserver->rcu, afs_vlserver_rcu);
|
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)
|
|||||||
|
|
||||||
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)
|
|||||||
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++) {
|
||||||
|
@ -53,7 +53,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);
|
||||||
@ -88,7 +88,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);
|
||||||
@ -229,7 +229,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);
|
||||||
|
|
||||||
@ -243,8 +243,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;
|
||||||
}
|
}
|
||||||
@ -258,9 +260,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -728,14 +728,14 @@ 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(struct afs_call *call, 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, 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 )
|
||||||
),
|
),
|
||||||
@ -743,15 +743,15 @@ TRACE_EVENT(afs_call,
|
|||||||
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)
|
||||||
);
|
);
|
||||||
@ -1475,36 +1475,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)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user