diff options
author | David Howells <dhowells@redhat.com> | 2018-05-10 08:43:04 +0100 |
---|---|---|
committer | David Howells <dhowells@redhat.com> | 2018-05-14 13:17:35 +0100 |
commit | d4a96bec7a7362834ef5c31d7b2cc9bf36eb0570 (patch) | |
tree | 003ec92ab854c87f1ebbdbb4ee38e7b8a99e870a /fs/afs/server_list.c | |
parent | f2686b09269ec1a6f23028b5675d87c3b4579a4c (diff) | |
download | linux-d4a96bec7a7362834ef5c31d7b2cc9bf36eb0570.tar.gz linux-d4a96bec7a7362834ef5c31d7b2cc9bf36eb0570.tar.bz2 linux-d4a96bec7a7362834ef5c31d7b2cc9bf36eb0570.zip |
afs: Fix refcounting in callback registration
The refcounting on afs_cb_interest struct objects in
afs_register_server_cb_interest() is wrong as it uses the server list
entry's call back interest pointer without regard for the fact that it
might be replaced at any time and the object thrown away.
Fix this by:
(1) Put a lock on the afs_server_list struct that can be used to
mediate access to the callback interest pointers in the servers array.
(2) Keep a ref on the callback interest that we get from the entry.
(3) Dropping the old reference held by vnode->cb_interest if we replace
the pointer.
Fixes: c435ee34551e ("afs: Overhaul the callback handling")
Signed-off-by: David Howells <dhowells@redhat.com>
Diffstat (limited to 'fs/afs/server_list.c')
-rw-r--r-- | fs/afs/server_list.c | 7 |
1 files changed, 5 insertions, 2 deletions
diff --git a/fs/afs/server_list.c b/fs/afs/server_list.c index 0f8dc4c8f07c..8a5760aa5832 100644 --- a/fs/afs/server_list.c +++ b/fs/afs/server_list.c @@ -49,6 +49,7 @@ struct afs_server_list *afs_alloc_server_list(struct afs_cell *cell, goto error; refcount_set(&slist->usage, 1); + rwlock_init(&slist->lock); /* Make sure a records exists for each server in the list. */ for (i = 0; i < vldb->nr_servers; i++) { @@ -64,9 +65,11 @@ struct afs_server_list *afs_alloc_server_list(struct afs_cell *cell, goto error_2; } - /* Insertion-sort by server pointer */ + /* Insertion-sort by UUID */ for (j = 0; j < slist->nr_servers; j++) - if (slist->servers[j].server >= server) + if (memcmp(&slist->servers[j].server->uuid, + &server->uuid, + sizeof(server->uuid)) >= 0) break; if (j < slist->nr_servers) { if (slist->servers[j].server == server) { |