#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
+#include <linux/sched.h>
#include "internal.h"
-unsigned afs_vlocation_timeout = 10; /* volume location timeout in seconds */
-unsigned afs_vlocation_update_timeout = 10 * 60;
+static unsigned afs_vlocation_timeout = 10; /* volume location timeout in seconds */
+static unsigned afs_vlocation_update_timeout = 10 * 60;
static void afs_vlocation_reaper(struct work_struct *);
static void afs_vlocation_updater(struct work_struct *);
* about the volume in question
*/
static int afs_vlocation_access_vl_by_name(struct afs_vlocation *vl,
+ struct key *key,
struct afs_cache_vlocation *vldb)
{
struct afs_cell *cell = vl->cell;
_debug("CellServ[%hu]: %08x", cell->vl_curr_svix, addr.s_addr);
/* attempt to access the VL server */
- ret = afs_vl_get_entry_by_name(&addr, vl->vldb.name, vldb,
+ ret = afs_vl_get_entry_by_name(&addr, key, vl->vldb.name, vldb,
&afs_sync_call);
switch (ret) {
case 0:
* about the volume in question
*/
static int afs_vlocation_access_vl_by_id(struct afs_vlocation *vl,
+ struct key *key,
afs_volid_t volid,
afs_voltype_t voltype,
struct afs_cache_vlocation *vldb)
_debug("CellServ[%hu]: %08x", cell->vl_curr_svix, addr.s_addr);
/* attempt to access the VL server */
- ret = afs_vl_get_entry_by_id(&addr, volid, voltype, vldb,
+ ret = afs_vl_get_entry_by_id(&addr, key, volid, voltype, vldb,
&afs_sync_call);
switch (ret) {
case 0:
INIT_LIST_HEAD(&vl->grave);
INIT_LIST_HEAD(&vl->update);
init_waitqueue_head(&vl->waitq);
- rwlock_init(&vl->lock);
+ spin_lock_init(&vl->lock);
memcpy(vl->vldb.name, name, namesz);
}
* update record if we found it in the cache
*/
static int afs_vlocation_update_record(struct afs_vlocation *vl,
+ struct key *key,
struct afs_cache_vlocation *vldb)
{
afs_voltype_t voltype;
/* contact the server to make sure the volume is still available
* - TODO: need to handle disconnected operation here
*/
- ret = afs_vlocation_access_vl_by_id(vl, vid, voltype, vldb);
+ ret = afs_vlocation_access_vl_by_id(vl, key, vid, voltype, vldb);
switch (ret) {
/* net error */
default:
* fill in a volume location record, consulting the cache and the VL server
* both
*/
-static int afs_vlocation_fill_in_record(struct afs_vlocation *vl)
+static int afs_vlocation_fill_in_record(struct afs_vlocation *vl,
+ struct key *key)
{
struct afs_cache_vlocation vldb;
int ret;
/* try to update a known volume in the cell VL databases by
* ID as the name may have changed */
_debug("found in cache");
- ret = afs_vlocation_update_record(vl, &vldb);
+ ret = afs_vlocation_update_record(vl, key, &vldb);
} else {
/* try to look up an unknown volume in the cell VL databases by
* name */
- ret = afs_vlocation_access_vl_by_name(vl, &vldb);
+ ret = afs_vlocation_access_vl_by_name(vl, key, &vldb);
if (ret < 0) {
printk("kAFS: failed to locate '%s' in cell '%s'\n",
vl->vldb.name, vl->cell->name);
/*
* queue a vlocation record for updates
*/
-void afs_vlocation_queue_for_updates(struct afs_vlocation *vl)
+static void afs_vlocation_queue_for_updates(struct afs_vlocation *vl)
{
struct afs_vlocation *xvl;
* - insert/update in the local cache if did get a VL response
*/
struct afs_vlocation *afs_vlocation_lookup(struct afs_cell *cell,
+ struct key *key,
const char *name,
size_t namesz)
{
struct afs_vlocation *vl;
int ret;
- _enter("{%s},%*.*s,%zu",
- cell->name, (int) namesz, (int) namesz, name, namesz);
+ _enter("{%s},{%x},%*.*s,%zu",
+ cell->name, key_serial(key),
+ (int) namesz, (int) namesz, name, namesz);
- if (namesz > sizeof(vl->vldb.name)) {
+ if (namesz >= sizeof(vl->vldb.name)) {
_leave(" = -ENAMETOOLONG");
return ERR_PTR(-ENAMETOOLONG);
}
up_write(&cell->vl_sem);
fill_in_record:
- ret = afs_vlocation_fill_in_record(vl);
+ ret = afs_vlocation_fill_in_record(vl, key);
if (ret < 0)
goto error_abandon;
+ spin_lock(&vl->lock);
vl->state = AFS_VL_VALID;
+ spin_unlock(&vl->lock);
wake_up(&vl->waitq);
/* schedule for regular updates */
up_write(&cell->vl_sem);
/* see if it was an abandoned record that we might try filling in */
+ spin_lock(&vl->lock);
while (vl->state != AFS_VL_VALID) {
afs_vlocation_state_t state = vl->state;
_debug("invalid [state %d]", state);
- if ((state == AFS_VL_NEW || state == AFS_VL_NO_VOLUME)) {
- if (cmpxchg(&vl->state, state, AFS_VL_CREATING) ==
- state)
- goto fill_in_record;
- continue;
+ if (state == AFS_VL_NEW || state == AFS_VL_NO_VOLUME) {
+ vl->state = AFS_VL_CREATING;
+ spin_unlock(&vl->lock);
+ goto fill_in_record;
}
/* must now wait for creation or update by someone else to
* complete */
_debug("wait");
- ret = wait_event_interruptible(
- vl->waitq,
- vl->state == AFS_VL_NEW ||
- vl->state == AFS_VL_VALID ||
- vl->state == AFS_VL_NO_VOLUME);
+ spin_unlock(&vl->lock);
+ ret = wait_event_interruptible(vl->waitq,
+ vl->state == AFS_VL_NEW ||
+ vl->state == AFS_VL_VALID ||
+ vl->state == AFS_VL_NO_VOLUME);
if (ret < 0)
goto error;
+ spin_lock(&vl->lock);
}
+ spin_unlock(&vl->lock);
success:
_leave(" = %p",vl);
return vl;
error_abandon:
+ spin_lock(&vl->lock);
vl->state = AFS_VL_NEW;
+ spin_unlock(&vl->lock);
wake_up(&vl->waitq);
error:
ASSERT(vl != NULL);
/*
* discard all the volume location records for rmmod
*/
-void __exit afs_vlocation_purge(void)
+void afs_vlocation_purge(void)
{
afs_vlocation_timeout = 0;
vl->upd_rej_cnt = 0;
vl->upd_busy_cnt = 0;
- ret = afs_vlocation_update_record(vl, &vldb);
+ ret = afs_vlocation_update_record(vl, NULL, &vldb);
+ spin_lock(&vl->lock);
switch (ret) {
case 0:
afs_vlocation_apply_update(vl, &vldb);
vl->state = AFS_VL_UNCERTAIN;
break;
}
+ spin_unlock(&vl->lock);
+ wake_up(&vl->waitq);
/* and then reschedule */
_debug("reschedule");