Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /* AFS fileserver list management.
0003  *
0004  * Copyright (C) 2017 Red Hat, Inc. All Rights Reserved.
0005  * Written by David Howells (dhowells@redhat.com)
0006  */
0007 
0008 #include <linux/kernel.h>
0009 #include <linux/slab.h>
0010 #include "internal.h"
0011 
0012 void afs_put_serverlist(struct afs_net *net, struct afs_server_list *slist)
0013 {
0014     int i;
0015 
0016     if (slist && refcount_dec_and_test(&slist->usage)) {
0017         for (i = 0; i < slist->nr_servers; i++)
0018             afs_unuse_server(net, slist->servers[i].server,
0019                      afs_server_trace_put_slist);
0020         kfree(slist);
0021     }
0022 }
0023 
0024 /*
0025  * Build a server list from a VLDB record.
0026  */
0027 struct afs_server_list *afs_alloc_server_list(struct afs_cell *cell,
0028                           struct key *key,
0029                           struct afs_vldb_entry *vldb,
0030                           u8 type_mask)
0031 {
0032     struct afs_server_list *slist;
0033     struct afs_server *server;
0034     int ret = -ENOMEM, nr_servers = 0, i, j;
0035 
0036     for (i = 0; i < vldb->nr_servers; i++)
0037         if (vldb->fs_mask[i] & type_mask)
0038             nr_servers++;
0039 
0040     slist = kzalloc(struct_size(slist, servers, nr_servers), GFP_KERNEL);
0041     if (!slist)
0042         goto error;
0043 
0044     refcount_set(&slist->usage, 1);
0045     rwlock_init(&slist->lock);
0046 
0047     for (i = 0; i < AFS_MAXTYPES; i++)
0048         slist->vids[i] = vldb->vid[i];
0049 
0050     /* Make sure a records exists for each server in the list. */
0051     for (i = 0; i < vldb->nr_servers; i++) {
0052         if (!(vldb->fs_mask[i] & type_mask))
0053             continue;
0054 
0055         server = afs_lookup_server(cell, key, &vldb->fs_server[i],
0056                        vldb->addr_version[i]);
0057         if (IS_ERR(server)) {
0058             ret = PTR_ERR(server);
0059             if (ret == -ENOENT ||
0060                 ret == -ENOMEDIUM)
0061                 continue;
0062             goto error_2;
0063         }
0064 
0065         /* Insertion-sort by UUID */
0066         for (j = 0; j < slist->nr_servers; j++)
0067             if (memcmp(&slist->servers[j].server->uuid,
0068                    &server->uuid,
0069                    sizeof(server->uuid)) >= 0)
0070                 break;
0071         if (j < slist->nr_servers) {
0072             if (slist->servers[j].server == server) {
0073                 afs_put_server(cell->net, server,
0074                            afs_server_trace_put_slist_isort);
0075                 continue;
0076             }
0077 
0078             memmove(slist->servers + j + 1,
0079                 slist->servers + j,
0080                 (slist->nr_servers - j) * sizeof(struct afs_server_entry));
0081         }
0082 
0083         slist->servers[j].server = server;
0084         slist->nr_servers++;
0085     }
0086 
0087     if (slist->nr_servers == 0) {
0088         ret = -EDESTADDRREQ;
0089         goto error_2;
0090     }
0091 
0092     return slist;
0093 
0094 error_2:
0095     afs_put_serverlist(cell->net, slist);
0096 error:
0097     return ERR_PTR(ret);
0098 }
0099 
0100 /*
0101  * Copy the annotations from an old server list to its potential replacement.
0102  */
0103 bool afs_annotate_server_list(struct afs_server_list *new,
0104                   struct afs_server_list *old)
0105 {
0106     struct afs_server *cur;
0107     int i, j;
0108 
0109     if (old->nr_servers != new->nr_servers)
0110         goto changed;
0111 
0112     for (i = 0; i < old->nr_servers; i++)
0113         if (old->servers[i].server != new->servers[i].server)
0114             goto changed;
0115 
0116     return false;
0117 
0118 changed:
0119     /* Maintain the same preferred server as before if possible. */
0120     cur = old->servers[old->preferred].server;
0121     for (j = 0; j < new->nr_servers; j++) {
0122         if (new->servers[j].server == cur) {
0123             new->preferred = j;
0124             break;
0125         }
0126     }
0127 
0128     return true;
0129 }