vlocation.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 955 行 · 第 1/2 页
C
955 行
/* 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*1000static 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 spinlock_t afs_vlocation_update_lock = SPIN_LOCK_UNLOCKED; /* lock guarding update queue */#ifdef AFS_CACHING_SUPPORTstatic 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; }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?