Linux Audio

Check our new training course

Loading...
v6.2
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/* AFS fileserver list management.
  3 *
  4 * Copyright (C) 2017 Red Hat, Inc. All Rights Reserved.
  5 * Written by David Howells (dhowells@redhat.com)
  6 */
  7
  8#include <linux/kernel.h>
  9#include <linux/slab.h>
 10#include "internal.h"
 11
 12void afs_put_serverlist(struct afs_net *net, struct afs_server_list *slist)
 13{
 14	int i;
 15
 16	if (slist && refcount_dec_and_test(&slist->usage)) {
 17		for (i = 0; i < slist->nr_servers; i++)
 18			afs_unuse_server(net, slist->servers[i].server,
 19					 afs_server_trace_put_slist);
 
 
 20		kfree(slist);
 21	}
 22}
 23
 24/*
 25 * Build a server list from a VLDB record.
 26 */
 27struct afs_server_list *afs_alloc_server_list(struct afs_cell *cell,
 28					      struct key *key,
 29					      struct afs_vldb_entry *vldb,
 30					      u8 type_mask)
 31{
 32	struct afs_server_list *slist;
 33	struct afs_server *server;
 34	int ret = -ENOMEM, nr_servers = 0, i, j;
 35
 36	for (i = 0; i < vldb->nr_servers; i++)
 37		if (vldb->fs_mask[i] & type_mask)
 38			nr_servers++;
 39
 40	slist = kzalloc(struct_size(slist, servers, nr_servers), GFP_KERNEL);
 41	if (!slist)
 42		goto error;
 43
 44	refcount_set(&slist->usage, 1);
 45	rwlock_init(&slist->lock);
 46
 47	for (i = 0; i < AFS_MAXTYPES; i++)
 48		slist->vids[i] = vldb->vid[i];
 49
 50	/* Make sure a records exists for each server in the list. */
 51	for (i = 0; i < vldb->nr_servers; i++) {
 52		if (!(vldb->fs_mask[i] & type_mask))
 53			continue;
 54
 55		server = afs_lookup_server(cell, key, &vldb->fs_server[i],
 56					   vldb->addr_version[i]);
 57		if (IS_ERR(server)) {
 58			ret = PTR_ERR(server);
 59			if (ret == -ENOENT ||
 60			    ret == -ENOMEDIUM)
 61				continue;
 62			goto error_2;
 63		}
 64
 65		/* Insertion-sort by UUID */
 66		for (j = 0; j < slist->nr_servers; j++)
 67			if (memcmp(&slist->servers[j].server->uuid,
 68				   &server->uuid,
 69				   sizeof(server->uuid)) >= 0)
 70				break;
 71		if (j < slist->nr_servers) {
 72			if (slist->servers[j].server == server) {
 73				afs_put_server(cell->net, server,
 74					       afs_server_trace_put_slist_isort);
 75				continue;
 76			}
 77
 78			memmove(slist->servers + j + 1,
 79				slist->servers + j,
 80				(slist->nr_servers - j) * sizeof(struct afs_server_entry));
 81		}
 82
 83		slist->servers[j].server = server;
 84		slist->nr_servers++;
 85	}
 86
 87	if (slist->nr_servers == 0) {
 88		ret = -EDESTADDRREQ;
 89		goto error_2;
 90	}
 91
 92	return slist;
 93
 94error_2:
 95	afs_put_serverlist(cell->net, slist);
 96error:
 97	return ERR_PTR(ret);
 98}
 99
100/*
101 * Copy the annotations from an old server list to its potential replacement.
102 */
103bool afs_annotate_server_list(struct afs_server_list *new,
104			      struct afs_server_list *old)
105{
106	struct afs_server *cur;
107	int i, j;
108
109	if (old->nr_servers != new->nr_servers)
110		goto changed;
111
112	for (i = 0; i < old->nr_servers; i++)
113		if (old->servers[i].server != new->servers[i].server)
114			goto changed;
115
116	return false;
117
118changed:
119	/* Maintain the same preferred server as before if possible. */
120	cur = old->servers[old->preferred].server;
121	for (j = 0; j < new->nr_servers; j++) {
122		if (new->servers[j].server == cur) {
123			new->preferred = j;
124			break;
125		}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126	}
127
128	return true;
129}
v5.4
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/* AFS fileserver list management.
  3 *
  4 * Copyright (C) 2017 Red Hat, Inc. All Rights Reserved.
  5 * Written by David Howells (dhowells@redhat.com)
  6 */
  7
  8#include <linux/kernel.h>
  9#include <linux/slab.h>
 10#include "internal.h"
 11
 12void afs_put_serverlist(struct afs_net *net, struct afs_server_list *slist)
 13{
 14	int i;
 15
 16	if (slist && refcount_dec_and_test(&slist->usage)) {
 17		for (i = 0; i < slist->nr_servers; i++) {
 18			afs_put_cb_interest(net, slist->servers[i].cb_interest);
 19			afs_put_server(net, slist->servers[i].server,
 20				       afs_server_trace_put_slist);
 21		}
 22		kfree(slist);
 23	}
 24}
 25
 26/*
 27 * Build a server list from a VLDB record.
 28 */
 29struct afs_server_list *afs_alloc_server_list(struct afs_cell *cell,
 30					      struct key *key,
 31					      struct afs_vldb_entry *vldb,
 32					      u8 type_mask)
 33{
 34	struct afs_server_list *slist;
 35	struct afs_server *server;
 36	int ret = -ENOMEM, nr_servers = 0, i, j;
 37
 38	for (i = 0; i < vldb->nr_servers; i++)
 39		if (vldb->fs_mask[i] & type_mask)
 40			nr_servers++;
 41
 42	slist = kzalloc(struct_size(slist, servers, nr_servers), GFP_KERNEL);
 43	if (!slist)
 44		goto error;
 45
 46	refcount_set(&slist->usage, 1);
 47	rwlock_init(&slist->lock);
 48
 
 
 
 49	/* Make sure a records exists for each server in the list. */
 50	for (i = 0; i < vldb->nr_servers; i++) {
 51		if (!(vldb->fs_mask[i] & type_mask))
 52			continue;
 53
 54		server = afs_lookup_server(cell, key, &vldb->fs_server[i]);
 
 55		if (IS_ERR(server)) {
 56			ret = PTR_ERR(server);
 57			if (ret == -ENOENT ||
 58			    ret == -ENOMEDIUM)
 59				continue;
 60			goto error_2;
 61		}
 62
 63		/* Insertion-sort by UUID */
 64		for (j = 0; j < slist->nr_servers; j++)
 65			if (memcmp(&slist->servers[j].server->uuid,
 66				   &server->uuid,
 67				   sizeof(server->uuid)) >= 0)
 68				break;
 69		if (j < slist->nr_servers) {
 70			if (slist->servers[j].server == server) {
 71				afs_put_server(cell->net, server,
 72					       afs_server_trace_put_slist_isort);
 73				continue;
 74			}
 75
 76			memmove(slist->servers + j + 1,
 77				slist->servers + j,
 78				(slist->nr_servers - j) * sizeof(struct afs_server_entry));
 79		}
 80
 81		slist->servers[j].server = server;
 82		slist->nr_servers++;
 83	}
 84
 85	if (slist->nr_servers == 0) {
 86		ret = -EDESTADDRREQ;
 87		goto error_2;
 88	}
 89
 90	return slist;
 91
 92error_2:
 93	afs_put_serverlist(cell->net, slist);
 94error:
 95	return ERR_PTR(ret);
 96}
 97
 98/*
 99 * Copy the annotations from an old server list to its potential replacement.
100 */
101bool afs_annotate_server_list(struct afs_server_list *new,
102			      struct afs_server_list *old)
103{
104	struct afs_server *cur;
105	int i, j;
106
107	if (old->nr_servers != new->nr_servers)
108		goto changed;
109
110	for (i = 0; i < old->nr_servers; i++)
111		if (old->servers[i].server != new->servers[i].server)
112			goto changed;
113
114	return false;
115
116changed:
117	/* Maintain the same preferred server as before if possible. */
118	cur = old->servers[old->preferred].server;
119	for (j = 0; j < new->nr_servers; j++) {
120		if (new->servers[j].server == cur) {
121			new->preferred = j;
122			break;
123		}
124	}
125
126	/* Keep the old callback interest records where possible so that we
127	 * maintain callback interception.
128	 */
129	i = 0;
130	j = 0;
131	while (i < old->nr_servers && j < new->nr_servers) {
132		if (new->servers[j].server == old->servers[i].server) {
133			struct afs_cb_interest *cbi = old->servers[i].cb_interest;
134			if (cbi) {
135				new->servers[j].cb_interest = cbi;
136				refcount_inc(&cbi->usage);
137			}
138			i++;
139			j++;
140			continue;
141		}
142
143		if (new->servers[j].server < old->servers[i].server) {
144			j++;
145			continue;
146		}
147
148		i++;
149		continue;
150	}
151
152	return true;
153}