/* vlocation.c: volume location management * * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> #include <linux/fs.h> #include <linux/pagemap.h> #include "volume.h" #include "cell.h" #include "cmservice.h" #include "fsclient.h" #include "vlclient.h" #include "kafstimod.h" #include <rxrpc/connection.h> #include "internal.h" #define AFS_VLDB_TIMEOUT HZ*1000 static void afs_vlocation_update_timer(struct afs_timer *timer); static void afs_vlocation_update_attend(struct afs_async_op *op); static void afs_vlocation_update_discard(struct afs_async_op *op); static void __afs_put_vlocation(struct afs_vlocation *vlocation); static void __afs_vlocation_timeout(struct afs_timer *timer) { struct afs_vlocation *vlocation = list_entry(timer, struct afs_vlocation, timeout); _debug("VL TIMEOUT [%s{u=%d}]", vlocation->vldb.name, atomic_read(&vlocation->usage)); afs_vlocation_do_timeout(vlocation); } static const struct afs_timer_ops afs_vlocation_timer_ops = { .timed_out = __afs_vlocation_timeout, }; static const struct afs_timer_ops afs_vlocation_update_timer_ops = { .timed_out = afs_vlocation_update_timer, }; static const struct afs_async_op_ops afs_vlocation_update_op_ops = { .attend = afs_vlocation_update_attend, .discard = afs_vlocation_update_discard, }; static LIST_HEAD(afs_vlocation_update_pendq); /* queue of VLs awaiting update */ static struct afs_vlocation *afs_vlocation_update; /* VL currently being updated */ static DEFINE_SPINLOCK(afs_vlocation_update_lock); /* lock guarding update queue */ #ifdef AFS_CACHING_SUPPORT static cachefs_match_val_t afs_vlocation_cache_match(void *target, const void *entry); static void afs_vlocation_cache_update(void *source, void *entry); struct cachefs_index_def afs_vlocation_cache_index_def = { .name = "vldb", .data_size = sizeof(struct afs_cache_vlocation), .keys[0] = { CACHEFS_INDEX_KEYS_ASCIIZ, 64 }, .match = afs_vlocation_cache_match, .update = afs_vlocation_cache_update, }; #endif /*****************************************************************************/ /* * iterate through the VL servers in a cell until one of them admits knowing * about the volume in question * - caller must have cell->vl_sem write-locked */ static int afs_vlocation_access_vl_by_name(struct afs_vlocation *vlocation, const char *name, unsigned namesz, struct afs_cache_vlocation *vldb) { struct afs_server *server = NULL; struct afs_cell *cell = vlocation->cell; int count, ret; _enter("%s,%*.*s,%u", cell->name, namesz, namesz, name, namesz); ret = -ENOMEDIUM; for (count = cell->vl_naddrs; count > 0; count--) { _debug("CellServ[%hu]: %08x", cell->vl_curr_svix, cell->vl_addrs[cell->vl_curr_svix].s_addr); /* try and create a server */ ret = afs_server_lookup(cell, &cell->vl_addrs[cell->vl_curr_svix], &server); switch (ret) { case 0: break; case -ENOMEM: case -ENONET: goto out; default: goto rotate; } /* attempt to access the VL server */ ret = afs_rxvl_get_entry_by_name(server, name, namesz, vldb); switch (ret) { case 0: afs_put_server(server); goto out; case -ENOMEM: case -ENONET: case -ENETUNREACH: case -EHOSTUNREACH: case -ECONNREFUSED: down_write(&server->sem); if (server->vlserver) { rxrpc_put_connection(server->vlserver); server->vlserver = NULL; } up_write(&server->sem); afs_put_server(server); if (ret == -ENOMEM || ret == -ENONET) goto out; goto rotate; case -ENOMEDIUM: afs_put_server(server); goto out; default: afs_put_server(server); ret = -ENOMEDIUM; goto rotate; } /* rotate the server records upon lookup failure */ rotate: cell->vl_curr_svix++; cell->vl_curr_svix %= cell->vl_naddrs; } out: _leave(" = %d", ret); return ret; } /* end afs_vlocation_access_vl_by_name() */ /*****************************************************************************/ /* * iterate through the VL servers in a cell until one of them admits knowing * about the volume in question * - caller must have cell->vl_sem write-locked */ static int afs_vlocation_access_vl_by_id(struct afs_vlocation *vlocation, afs_volid_t volid, afs_voltype_t voltype, struct afs_cache_vlocation *vldb) { struct afs_server *server = NULL; struct afs_cell *cell = vlocation->cell; int count, ret; _enter("%s,%x,%d,", cell->name, volid, voltype); ret = -ENOMEDIUM; for (count = cell->vl_naddrs; count > 0; count--) { _debug("CellServ[%hu]: %08x", cell->vl_curr_svix, cell->vl_addrs[cell->vl_curr_svix].s_addr); /* try and create a server */ ret = afs_server_lookup(cell, &cell->vl_addrs[cell->vl_curr_svix], &server); switch (ret) { case 0: break; case -ENOMEM: case -ENONET: goto out; default: goto rotate; } /* attempt to access the VL server */ ret = afs_rxvl_get_entry_by_id(server, volid, voltype, vldb); switch (ret) { case 0: afs_put_server(server); goto out; case -ENOMEM: case -ENONET: case -ENETUNREACH: case -EHOSTUNREACH: case -ECONNREFUSED: down_write(&server->sem); if (server->vlserver) { rxrpc_put_connection(server->vlserver); server->vlserver = NULL; } up_write(&server->sem); afs_put_server(server); if (ret == -ENOMEM || ret == -ENONET) goto out; goto rotate; case -ENOMEDIUM: afs_put_server(server); goto out; default: afs_put_server(server); ret = -ENOMEDIUM; goto rotate; } /* rotate the server records upon lookup failure */ rotate: cell->vl_curr_svix++; cell->vl_curr_svix %= cell->vl_naddrs; } out: _leave(" = %d", ret); return ret; } /* end afs_vlocation_access_vl_by_id() */ /*****************************************************************************/ /* * lookup volume location * - caller must have cell->vol_sem write-locked * - iterate through the VL servers in a cell until one of them admits knowing * about the volume in question * - lookup in the local cache if not able to find on the VL server * - insert/update in the local cache if did get a VL response */ int afs_vlocation_lookup(struct afs_cell *cell, const char *name, unsigned namesz, struct afs_vlocation **_vlocation) { struct afs_cache_vlocation vldb; struct afs_vlocation *vlocation; afs_voltype_t voltype; afs_volid_t vid; int active = 0, ret; _enter("{%s},%*.*s,%u,", cell->name, namesz, namesz, name, namesz); if (namesz > sizeof(vlocation->vldb.name)) { _leave(" = -ENAMETOOLONG"); return -ENAMETOOLONG; } /* search the cell's active list first */ list_for_each_entry(vlocation, &cell->vl_list, link) { if (namesz < sizeof(vlocation->vldb.name) && vlocation->vldb.name[namesz] != '\0') continue; if (memcmp(vlocation->vldb.name, name, namesz) == 0) goto found_in_memory; } /* search the cell's graveyard list second */ spin_lock(&cell->vl_gylock); list_for_each_entry(vlocation, &cell->vl_graveyard, link) { if (namesz < sizeof(vlocation->vldb.name) && vlocation->vldb.name[namesz] != '\0') continue; if (memcmp(vlocation->vldb.name, name, namesz) == 0) goto found_in_graveyard; } spin_unlock(&cell->vl_gylock); /* not in the cell's in-memory lists - create a new record */ vlocation = kmalloc(sizeof(struct afs_vlocation), GFP_KERNEL); if (!vlocation) return -ENOMEM; memset(vlocation, 0, sizeof(struct afs_vlocation)); atomic_set(&vlocation->usage, 1); INIT_LIST_HEAD(&vlocation->link); rwlock_init(&vlocation->lock); memcpy(vlocation->vldb.name, name, namesz); afs_timer_init(&vlocation->timeout, &afs_vlocation_timer_ops); afs_timer_init(&vlocation->upd_timer, &afs_vlocation_update_timer_ops); afs_async_op_init(&vlocation->upd_op, &afs_vlocation_update_op_ops); afs_get_cell(cell); vlocation->cell = cell; list_add_tail(&vlocation->link, &cell->vl_list); #ifdef AFS_CACHING_SUPPORT /* we want to store it in the cache, plus it might already be * encached */ cachefs_acquire_cookie(cell->cache, &afs_volume_cache_index_def, vlocation, &vlocation->cache); if (vlocation->valid) goto found_in_cache; #endif /* try to look up an unknown volume in the cell VL databases by name */ ret = afs_vlocation_access_vl_by_name(vlocation, name, namesz, &vldb); if (ret < 0) { printk("kAFS: failed to locate '%*.*s' in cell '%s'\n", namesz, namesz, name, cell->name); goto error; } goto found_on_vlserver; found_in_graveyard: /* found in the graveyard - resurrect */ _debug("found in graveyard"); atomic_inc(&vlocation->usage); list_del(&vlocation->link); list_add_tail(&vlocation->link, &cell->vl_list); spin_unlock(&cell->vl_gylock); afs_kafstimod_del_timer(&vlocation->timeout); goto active; found_in_memory: /* found in memory - check to see if it's active */ _debug("found in memory"); atomic_inc(&vlocation->usage); active: active = 1; #ifdef AFS_CACHING_SUPPORT found_in_cache: #endif /* try to look up a cached volume in the cell VL databases by ID */ _debug("found in cache"); _debug("Locally Cached: %s %02x { %08x(%x) %08x(%x) %08x(%x) }", vlocation->vldb.name, vlocation->vldb.vidmask, ntohl(vlocation->vldb.servers[0].s_addr), vlocation->vldb.srvtmask[0], ntohl(vlocation->vldb.servers[1].s_addr), vlocation->vldb.srvtmask[1], ntohl(vlocation->vldb.servers[2].s_addr), vlocation->vldb.srvtmask[2] ); _debug("Vids: %08x %08x %08x", vlocation->vldb.vid[0], vlocation->vldb.vid[1], vlocation->vldb.vid[2]); if (vlocation->vldb.vidmask & AFS_VOL_VTM_RW) { vid = vlocation->vldb.vid[0]; voltype = AFSVL_RWVOL; } else if (vlocation->vldb.vidmask & AFS_VOL_VTM_RO) { vid = vlocation->vldb.vid[1]; voltype = AFSVL_ROVOL; } else if (vlocation->vldb.vidmask & AFS_VOL_VTM_BAK) { vid = vlocation->vldb.vid[2]; voltype = AFSVL_BACKVOL; } else { BUG(); vid = 0; voltype = 0; } ret = afs_vlocation_access_vl_by_id(vlocation, vid, voltype, &vldb); switch (ret) { /* net error */ default: printk("kAFS: failed to volume '%*.*s' (%x) up in '%s': %d\n", namesz, namesz, name, vid, cell->name, ret); goto error; /* pulled from local cache into memory */ case 0: goto found_on_vlserver; /* uh oh... looks like the volume got deleted */ case -ENOMEDIUM: printk("kAFS: volume '%*.*s' (%x) does not exist '%s'\n", namesz, namesz, name, vid, cell->name); /* TODO: make existing record unavailable */ goto error; } found_on_vlserver: _debug("Done VL Lookup: %*.*s %02x { %08x(%x) %08x(%x) %08x(%x) }", namesz, namesz, name, vldb.vidmask, ntohl(vldb.servers[0].s_addr), vldb.srvtmask[0], ntohl(vldb.servers[1].s_addr), vldb.srvtmask[1], ntohl(vldb.servers[2].s_addr), vldb.srvtmask[2] ); _debug("Vids: %08x %08x %08x", vldb.vid[0], vldb.vid[1], vldb.vid[2]); if ((namesz < sizeof(vlocation->vldb.name) && vlocation->vldb.name[namesz] != '\0') || memcmp(vldb.name, name, namesz) != 0) printk("kAFS: name of volume '%*.*s' changed to '%s' on server\n", namesz, namesz, name, vldb.name); memcpy(&vlocation->vldb, &vldb, sizeof(vlocation->vldb)); afs_kafstimod_add_timer(&vlocation->upd_timer, 10 * HZ); #ifdef AFS_CACHING_SUPPORT /* update volume entry in local cache */ cachefs_update_cookie(vlocation->cache); #endif *_vlocation = vlocation; _leave(" = 0 (%p)",vlocation); return 0; error: if (vlocation) { if (active) { __afs_put_vlocation(vlocation); } else { list_del(&vlocation->link); #ifdef AFS_CACHING_SUPPORT cachefs_relinquish_cookie(vlocation->cache, 0); #endif afs_put_cell(vlocation->cell); kfree(vlocation); } } _leave(" = %d", ret); return ret; } /* end afs_vlocation_lookup() */ /*****************************************************************************/ /* * finish using a volume location record * - caller must have cell->vol_sem write-locked */ static void __afs_put_vlocation(struct afs_vlocation *vlocation) { struct afs_cell *cell; if (!vlocation) return; _enter("%s", vlocation->vldb.name); cell = vlocation->cell; /* sanity check */ BUG_ON(atomic_read(&vlocation->usage) <= 0); spin_lock(&cell->vl_gylock); if (likely(!atomic_dec_and_test(&vlocation->usage))) { spin_unlock(&cell->vl_gylock); _leave(""); return; } /* move to graveyard queue */ list_del(&vlocation->link); list_add_tail(&vlocation->link,&cell->vl_graveyard); /* remove from pending timeout queue (refcounted if actually being * updated) */ list_del_init(&vlocation->upd_op.link); /* time out in 10 secs */ afs_kafstimod_del_timer(&vlocation->upd_timer); afs_kafstimod_add_timer(&vlocation->timeout, 10 * HZ); spin_unlock(&cell->vl_gylock); _leave(" [killed]"); } /* end __afs_put_vlocation() */ /*****************************************************************************/ /* * finish using a volume location record */ void afs_put_vlocation(struct afs_vlocation *vlocation) { if (vlocation) { struct afs_cell *cell = vlocation->cell; down_write(&cell->vl_sem); __afs_put_vlocation(vlocation); up_write(&cell->vl_sem); } } /* end afs_put_vlocation() */ /*****************************************************************************/ /* * timeout vlocation record * - removes from the cell's graveyard if the usage count is zero */ void afs_vlocation_do_timeout(struct afs_vlocation *vlocation) { struct afs_cell *cell; _enter("%s", vlocation->vldb.name); cell = vlocation->cell; BUG_ON(atomic_read(&vlocation->usage) < 0); /* remove from graveyard if still dead */ spin_lock(&cell->vl_gylock); if (atomic_read(&vlocation->usage) == 0) list_del_init(&vlocation->link); else vlocation = NULL; spin_unlock(&cell->vl_gylock); if (!vlocation) { _leave(""); return; /* resurrected */ } /* we can now destroy it properly */ #ifdef AFS_CACHING_SUPPORT cachefs_relinquish_cookie(vlocation->cache, 0); #endif afs_put_cell(cell); kfree(vlocation); _leave(" [destroyed]"); } /* end afs_vlocation_do_timeout() */ /*****************************************************************************/ /* * send an update operation to the currently selected server */ static int afs_vlocation_update_begin(struct afs_vlocation *vlocation) { afs_voltype_t voltype; afs_volid_t vid; int ret; _enter("%s{ufs=%u ucs=%u}", vlocation->vldb.name, vlocation->upd_first_svix, vlocation->upd_curr_svix); /* try to look up a cached volume in the cell VL databases by ID */ if (vlocation->vldb.vidmask & AFS_VOL_VTM_RW) { vid = vlocation->vldb.vid[0]; voltype = AFSVL_RWVOL; } else if (vlocation->vldb.vidmask & AFS_VOL_VTM_RO) { vid = vlocation->vldb.vid[1]; voltype = AFSVL_ROVOL; } else if (vlocation->vldb.vidmask & AFS_VOL_VTM_BAK) { vid = vlocation->vldb.vid[2]; voltype = AFSVL_BACKVOL; } else { BUG(); vid = 0; voltype = 0; } /* contact the chosen server */ ret = afs_server_lookup( vlocation->cell, &vlocation->cell->vl_addrs[vlocation->upd_curr_svix], &vlocation->upd_op.server); switch (ret) { case 0: break; case -ENOMEM: case -ENONET: default: _leave(" = %d", ret); return ret; } /* initiate the update operation */ ret = afs_rxvl_get_entry_by_id_async(&vlocation->upd_op, vid, voltype); if (ret < 0) { _leave(" = %d", ret); return ret; } _leave(" = %d", ret); return ret; } /* end afs_vlocation_update_begin() */ /*****************************************************************************/ /* * abandon updating a VL record * - does not restart the update timer */ static void afs_vlocation_update_abandon(struct afs_vlocation *vlocation, afs_vlocation_upd_t state, int ret) { _enter("%s,%u", vlocation->vldb.name, state); if (ret < 0) printk("kAFS: Abandoning VL update '%s': %d\n", vlocation->vldb.name, ret); /* discard the server record */ afs_put_server(vlocation->upd_op.server); vlocation->upd_op.server = NULL; spin_lock(&afs_vlocation_update_lock); afs_vlocation_update = NULL; vlocation->upd_state = state; /* TODO: start updating next VL record on pending list */ spin_unlock(&afs_vlocation_update_lock); _leave(""); } /* end afs_vlocation_update_abandon() */ /*****************************************************************************/ /* * handle periodic update timeouts and busy retry timeouts * - called from kafstimod */ static void afs_vlocation_update_timer(struct afs_timer *timer) { struct afs_vlocation *vlocation = list_entry(timer, struct afs_vlocation, upd_timer); int ret; _enter("%s", vlocation->vldb.name); /* only update if not in the graveyard (defend against putting too) */ spin_lock(&vlocation->cell->vl_gylock); if (!atomic_read(&vlocation->usage)) goto out_unlock1; spin_lock(&afs_vlocation_update_lock); /* if we were woken up due to EBUSY sleep then restart immediately if * possible or else jump to front of pending queue */ if (vlocation->upd_state == AFS_VLUPD_BUSYSLEEP) { if (afs_vlocation_update) { list_add(&vlocation->upd_op.link, &afs_vlocation_update_pendq); } else { afs_get_vlocation(vlocation); afs_vlocation_update = vlocation; vlocation->upd_state = AFS_VLUPD_INPROGRESS; } goto out_unlock2; } /* put on pending queue if there's already another update in progress */ if (afs_vlocation_update) { vlocation->upd_state = AFS_VLUPD_PENDING; list_add_tail(&vlocation->upd_op.link, &afs_vlocation_update_pendq); goto out_unlock2; } /* hold a ref on it while actually updating */ afs_get_vlocation(vlocation); afs_vlocation_update = vlocation; vlocation->upd_state = AFS_VLUPD_INPROGRESS; spin_unlock(&afs_vlocation_update_lock); spin_unlock(&vlocation->cell->vl_gylock); /* okay... we can start the update */ _debug("BEGIN VL UPDATE [%s]", vlocation->vldb.name); vlocation->upd_first_svix = vlocation->cell->vl_curr_svix; vlocation->upd_curr_svix = vlocation->upd_first_svix; vlocation->upd_rej_cnt = 0; vlocation->upd_busy_cnt = 0; ret = afs_vlocation_update_begin(vlocation); if (ret < 0) { afs_vlocation_update_abandon(vlocation, AFS_VLUPD_SLEEP, ret); afs_kafstimod_add_timer(&vlocation->upd_timer, AFS_VLDB_TIMEOUT); afs_put_vlocation(vlocation); } _leave(""); return; out_unlock2: spin_unlock(&afs_vlocation_update_lock); out_unlock1: spin_unlock(&vlocation->cell->vl_gylock); _leave(""); return; } /* end afs_vlocation_update_timer() */ /*****************************************************************************/ /* * attend to an update operation upon which an event happened * - called in kafsasyncd context */ static void afs_vlocation_update_attend(struct afs_async_op *op) { struct afs_cache_vlocation vldb; struct afs_vlocation *vlocation = list_entry(op, struct afs_vlocation, upd_op); unsigned tmp; int ret; _enter("%s", vlocation->vldb.name); ret = afs_rxvl_get_entry_by_id_async2(op, &vldb); switch (ret) { case -EAGAIN: _leave(" [unfinished]"); return; case 0: _debug("END VL UPDATE: %d\n", ret); vlocation->valid = 1; _debug("Done VL Lookup: %02x { %08x(%x) %08x(%x) %08x(%x) }", vldb.vidmask, ntohl(vldb.servers[0].s_addr), vldb.srvtmask[0], ntohl(vldb.servers[1].s_addr), vldb.srvtmask[1], ntohl(vldb.servers[2].s_addr), vldb.srvtmask[2] ); _debug("Vids: %08x %08x %08x", vldb.vid[0], vldb.vid[1], vldb.vid[2]); afs_vlocation_update_abandon(vlocation, AFS_VLUPD_SLEEP, 0); down_write(&vlocation->cell->vl_sem); /* actually update the cache */ if (strncmp(vldb.name, vlocation->vldb.name, sizeof(vlocation->vldb.name)) != 0) printk("kAFS: name of volume '%s'" " changed to '%s' on server\n", vlocation->vldb.name, vldb.name); memcpy(&vlocation->vldb, &vldb, sizeof(vlocation->vldb)); #if 0 /* TODO update volume entry in local cache */ #endif up_write(&vlocation->cell->vl_sem); if (ret < 0) printk("kAFS: failed to update local cache: %d\n", ret); afs_kafstimod_add_timer(&vlocation->upd_timer, AFS_VLDB_TIMEOUT); afs_put_vlocation(vlocation); _leave(" [found]"); return; case -ENOMEDIUM: vlocation->upd_rej_cnt++; goto try_next; /* the server is locked - retry in a very short while */ case -EBUSY: vlocation->upd_busy_cnt++; if (vlocation->upd_busy_cnt > 3) goto try_next; /* too many retries */ afs_vlocation_update_abandon(vlocation, AFS_VLUPD_BUSYSLEEP, 0); afs_kafstimod_add_timer(&vlocation->upd_timer, HZ / 2); afs_put_vlocation(vlocation); _leave(" [busy]"); return; case -ENETUNREACH: case -EHOSTUNREACH: case -ECONNREFUSED: case -EREMOTEIO: /* record bad vlserver info in the cell too * - TODO: use down_write_trylock() if available */ if (vlocation->upd_curr_svix == vlocation->cell->vl_curr_svix) vlocation->cell->vl_curr_svix = vlocation->cell->vl_curr_svix % vlocation->cell->vl_naddrs; case -EBADRQC: case -EINVAL: case -EACCES: case -EBADMSG: goto try_next; default: goto abandon; } /* try contacting the next server */ try_next: vlocation->upd_busy_cnt = 0; /* discard the server record */ afs_put_server(vlocation->upd_op.server); vlocation->upd_op.server = NULL; tmp = vlocation->cell->vl_naddrs; if (tmp == 0) goto abandon; vlocation->upd_curr_svix++; if (vlocation->upd_curr_svix >= tmp) vlocation->upd_curr_svix = 0; if (vlocation->upd_first_svix >= tmp) vlocation->upd_first_svix = tmp - 1; /* move to the next server */ if (vlocation->upd_curr_svix != vlocation->upd_first_svix) { afs_vlocation_update_begin(vlocation); _leave(" [next]"); return; } /* run out of servers to try - was the volume rejected? */ if (vlocation->upd_rej_cnt > 0) { printk("kAFS: Active volume no longer valid '%s'\n", vlocation->vldb.name); vlocation->valid = 0; afs_vlocation_update_abandon(vlocation, AFS_VLUPD_SLEEP, 0); afs_kafstimod_add_timer(&vlocation->upd_timer, AFS_VLDB_TIMEOUT); afs_put_vlocation(vlocation); _leave(" [invalidated]"); return; } /* abandon the update */ abandon: afs_vlocation_update_abandon(vlocation, AFS_VLUPD_SLEEP, ret); afs_kafstimod_add_timer(&vlocation->upd_timer, HZ * 10); afs_put_vlocation(vlocation); _leave(" [abandoned]"); } /* end afs_vlocation_update_attend() */ /*****************************************************************************/ /* * deal with an update operation being discarded * - called in kafsasyncd context when it's dying due to rmmod * - the call has already been aborted and put()'d */ static void afs_vlocation_update_discard(struct afs_async_op *op) { struct afs_vlocation *vlocation = list_entry(op, struct afs_vlocation, upd_op); _enter("%s", vlocation->vldb.name); afs_put_server(op->server); op->server = NULL; afs_put_vlocation(vlocation); _leave(""); } /* end afs_vlocation_update_discard() */ /*****************************************************************************/ /* * match a VLDB record stored in the cache * - may also load target from entry */ #ifdef AFS_CACHING_SUPPORT static cachefs_match_val_t afs_vlocation_cache_match(void *target, const void *entry) { const struct afs_cache_vlocation *vldb = entry; struct afs_vlocation *vlocation = target; _enter("{%s},{%s}", vlocation->vldb.name, vldb->name); if (strncmp(vlocation->vldb.name, vldb->name, sizeof(vldb->name)) == 0 ) { if (!vlocation->valid || vlocation->vldb.rtime == vldb->rtime ) { vlocation->vldb = *vldb; vlocation->valid = 1; _leave(" = SUCCESS [c->m]"); return CACHEFS_MATCH_SUCCESS; } /* need to update cache if cached info differs */ else if (memcmp(&vlocation->vldb, vldb, sizeof(*vldb)) != 0) { /* delete if VIDs for this name differ */ if (memcmp(&vlocation->vldb.vid, &vldb->vid, sizeof(vldb->vid)) != 0) { _leave(" = DELETE"); return CACHEFS_MATCH_SUCCESS_DELETE; } _leave(" = UPDATE"); return CACHEFS_MATCH_SUCCESS_UPDATE; } else { _leave(" = SUCCESS"); return CACHEFS_MATCH_SUCCESS; } } _leave(" = FAILED"); return CACHEFS_MATCH_FAILED; } /* end afs_vlocation_cache_match() */ #endif /*****************************************************************************/ /* * update a VLDB record stored in the cache */ #ifdef AFS_CACHING_SUPPORT static void afs_vlocation_cache_update(void *source, void *entry) { struct afs_cache_vlocation *vldb = entry; struct afs_vlocation *vlocation = source; _enter(""); *vldb = vlocation->vldb; } /* end afs_vlocation_cache_update() */ #endif