2 * Copyright (c) 2014 Your File System, Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
8 * - Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * - Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * - Neither the name of Secure Endpoints Inc. nor the names of its contributors
14 * may be used to endorse or promote products derived from this software without
15 * specific prior written permission from Secure Endpoints, Inc. and
16 * Your File System, Inc.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
21 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
22 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include <afsconfig.h>
32 #include <afs/param.h>
37 #include "cm_getaddrs.h"
39 typedef struct _uuid2addrsEntry {
49 #define CM_GETADDRS_FLAG_DELETE 1
51 /* lock for hash table */
52 osi_rwlock_t cm_getaddrsLock;
55 #define CM_GETADDRS_HASHTABLESIZE 128
56 static afs_uint32 cm_getaddrsHashTableSize = CM_GETADDRS_HASHTABLESIZE;
58 #define CM_GETADDRS_HASH(uuidp) \
59 (opr_jhash((const afs_uint32 *)uuidp, 4, 0) & (cm_getaddrsHashTableSize - 1))
61 static struct _uuid2addrsHashTableBucket {
62 uuid2addrsEntry_t * Firstp;
63 uuid2addrsEntry_t * Endp;
64 } cm_getaddrsHashTable[CM_GETADDRS_HASHTABLESIZE];
67 * Return a cached entry that matches the requested
68 * uuid if the requested unique is less than or equal
69 * to the cached entry. Otherwise, return NULL.
71 * Returned entries are returned with a reference.
73 static uuid2addrsEntry_t *
74 cm_getaddrsFind(afsUUID *uuid, afs_int32 srv_unique)
76 uuid2addrsEntry_t * entry = NULL;
77 afs_uint32 hash = CM_GETADDRS_HASH(uuid);
79 lock_ObtainRead(&cm_getaddrsLock);
81 for ( entry = cm_getaddrsHashTable[hash].Firstp;
83 entry = (uuid2addrsEntry_t *)osi_QNext(&entry->q))
85 if (memcmp(uuid, &entry->uuid, sizeof(afsUUID)) == 0 &&
86 srv_unique <= entry->unique &&
87 !(entry->flags & CM_GETADDRS_FLAG_DELETE))
93 lock_ReleaseRead(&cm_getaddrsLock);
99 cm_getaddrsPut(uuid2addrsEntry_t *entry)
101 lock_ObtainRead(&cm_getaddrsLock);
103 lock_ReleaseRead(&cm_getaddrsLock);
107 * Add a bulkaddrs list to the getaddrs queue.
108 * Once this function is called the bulkaddrs structure
109 * no longer belongs to the caller and must not be
110 * accessed. It may be freed if there is a race with
114 static uuid2addrsEntry_t *
115 cm_getaddrsAdd(afsUUID *uuid, afs_int32 srv_unique,
116 afs_uint32 nentries, bulkaddrs *addrsp)
118 uuid2addrsEntry_t * entry, *next, *retentry = NULL;
119 afs_uint32 hash = CM_GETADDRS_HASH(uuid);
122 lock_ObtainWrite(&cm_getaddrsLock);
123 for ( entry = cm_getaddrsHashTable[hash].Firstp;
127 next = (uuid2addrsEntry_t *)osi_QNext(&entry->q);
129 if ((entry->flags & CM_GETADDRS_FLAG_DELETE) &&
130 entry->refCount == 0)
132 osi_QRemoveHT((osi_queue_t **) &cm_getaddrsHashTable[hash].Firstp,
133 (osi_queue_t **) &cm_getaddrsHashTable[hash].Endp,
135 xdr_free((xdrproc_t) xdr_bulkaddrs, &entry->addrs);
139 if (memcmp(uuid, &entry->uuid, sizeof(afsUUID)) == 0)
142 if (srv_unique <= entry->unique) {
144 * out of date or duplicate entry.
147 xdr_free((xdrproc_t) xdr_bulkaddrs, addrsp);
150 retentry->refCount++;
155 * this entry is newer than the one we found,
156 * if it is unused then update it
158 if (entry->refCount == 0) {
159 xdr_free((xdrproc_t) xdr_bulkaddrs, &entry->addrs);
161 entry->unique = srv_unique;
162 entry->addrs = *addrsp;
163 entry->nentries = nentries;
166 retentry->refCount++;
173 entry = calloc(1, sizeof(uuid2addrsEntry_t));
175 memcpy(&entry->uuid, uuid, sizeof(afsUUID));
176 entry->unique = srv_unique;
177 entry->addrs = *addrsp;
178 entry->nentries = nentries;
180 osi_QAddH((osi_queue_t **) &cm_getaddrsHashTable[hash].Firstp,
181 (osi_queue_t **) &cm_getaddrsHashTable[hash].Endp,
184 retentry->refCount++;
187 lock_ReleaseWrite(&cm_getaddrsLock);
193 * cm_GetAddrsU takes as input a uuid and a unique value which
194 * represent the set of addresses that are required. These values
195 * are used as input to the VL_GetAddrsU RPC which returns a list
196 * of addresses. For each returned address a bucket in the provided
197 * arrays (serverFlags, serverNumber, serverUUID, serverUnique)
198 * are populated. The serverFlags array entries are filled with the
199 * 'Flags' value provided as input. 'serverNumber' is the server's
204 cm_GetAddrsU(cm_cell_t *cellp, cm_user_t *userp, cm_req_t *reqp,
205 afsUUID *Uuid, afs_int32 Unique, afs_int32 Flags,
207 afs_int32 serverFlags[],
208 afs_int32 serverNumber[],
209 afsUUID serverUUID[],
210 afs_int32 serverUnique[])
213 uuid2addrsEntry_t *entry;
215 entry = cm_getaddrsFind(Uuid, Unique);
219 struct rx_connection *rxconnp;
220 ListAddrByAttributes attrs;
226 memset(&uuid, 0, sizeof(uuid));
227 memset(&addrs, 0, sizeof(addrs));
228 memset(&attrs, 0, sizeof(attrs));
230 attrs.Mask = VLADDR_UUID;
234 code = cm_ConnByMServers(cellp->vlServersp, 0, userp, reqp, &connp);
237 rxconnp = cm_GetRxConn(connp);
238 code = VL_GetAddrsU(rxconnp, &attrs, &uuid, &unique, &nentries,
240 rx_PutConnection(rxconnp);
241 } while (cm_Analyze(connp, userp, reqp, NULL, cellp, 0, NULL, NULL,
242 &cellp->vlServersp, NULL, code));
244 code = cm_MapVLRPCError(code, reqp);
246 if (afsd_logp->enabled) {
247 struct uuid_fmtbuf uuidstr;
248 afsUUID_to_string(Uuid, &uuidstr);
252 "CALL VL_GetAddrsU serverNumber %s FAILURE, code 0x%x",
253 osi_LogSaveString(afsd_logp, uuidstr.buffer),
256 osi_Log1(afsd_logp, "CALL VL_GetAddrsU serverNumber %s SUCCESS",
257 osi_LogSaveString(afsd_logp, uuidstr.buffer));
261 return CM_ERROR_RETRY;
264 xdr_free((xdrproc_t) xdr_bulkaddrs, &addrs);
265 code = CM_ERROR_INVAL;
267 /* addrs will either be cached or freed by cm_getaddrsAdd() */
268 entry = cm_getaddrsAdd(&uuid, unique, nentries, &addrs);
276 addrp = entry->addrs.bulkaddrs_val;
277 for (n = 0; n < entry->nentries && (*index) < NMAXNSERVERS;
279 serverFlags[*index] = Flags;
280 serverNumber[*index] = addrp[n];
281 serverUUID[*index] = entry->uuid;
282 serverUnique[*index] = entry->unique;
284 cm_getaddrsPut(entry);
291 cm_getaddrsInit(void)
293 static osi_once_t once;
295 if (osi_Once(&once)) {
296 lock_InitializeRWLock(&cm_getaddrsLock, "cm_getaddrsLock",
297 LOCK_HIERARCHY_GETADDRS_GLOBAL);
303 cm_getaddrsShutdown(void)
305 lock_FinalizeRWLock(&cm_getaddrsLock);