Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.6.
  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}