Commit 39bf0949 authored by David S. Miller's avatar David S. Miller

[AFS]: Eliminate cmpxchg() usage in vlocation code.

cmpxchg() is not available on every processor so can't
be used in generic code.

Replace with spinlock protection on the ->state changes,
wakeups, and wait loops.

Add what appears to be a missing wakeup on transition
to AFS_VL_VALID state in afs_vlocation_updater().
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 68c708fd
...@@ -219,7 +219,7 @@ struct afs_vlocation { ...@@ -219,7 +219,7 @@ struct afs_vlocation {
struct afs_volume *vols[3]; /* volume access record pointer (index by type) */ struct afs_volume *vols[3]; /* volume access record pointer (index by type) */
wait_queue_head_t waitq; /* status change waitqueue */ wait_queue_head_t waitq; /* status change waitqueue */
time_t update_at; /* time at which record should be updated */ time_t update_at; /* time at which record should be updated */
rwlock_t lock; /* access lock */ spinlock_t lock; /* access lock */
afs_vlocation_state_t state; /* volume location state */ afs_vlocation_state_t state; /* volume location state */
unsigned short upd_rej_cnt; /* ENOMEDIUM count during update */ unsigned short upd_rej_cnt; /* ENOMEDIUM count during update */
unsigned short upd_busy_cnt; /* EBUSY count during update */ unsigned short upd_busy_cnt; /* EBUSY count during update */
......
...@@ -178,7 +178,7 @@ static struct afs_vlocation *afs_vlocation_alloc(struct afs_cell *cell, ...@@ -178,7 +178,7 @@ static struct afs_vlocation *afs_vlocation_alloc(struct afs_cell *cell,
INIT_LIST_HEAD(&vl->grave); INIT_LIST_HEAD(&vl->grave);
INIT_LIST_HEAD(&vl->update); INIT_LIST_HEAD(&vl->update);
init_waitqueue_head(&vl->waitq); init_waitqueue_head(&vl->waitq);
rwlock_init(&vl->lock); spin_lock_init(&vl->lock);
memcpy(vl->vldb.name, name, namesz); memcpy(vl->vldb.name, name, namesz);
} }
...@@ -414,8 +414,10 @@ struct afs_vlocation *afs_vlocation_lookup(struct afs_cell *cell, ...@@ -414,8 +414,10 @@ struct afs_vlocation *afs_vlocation_lookup(struct afs_cell *cell,
ret = afs_vlocation_fill_in_record(vl, key); ret = afs_vlocation_fill_in_record(vl, key);
if (ret < 0) if (ret < 0)
goto error_abandon; goto error_abandon;
spin_lock(&vl->lock);
vl->state = AFS_VL_VALID; vl->state = AFS_VL_VALID;
wake_up(&vl->waitq); wake_up(&vl->waitq);
spin_unlock(&vl->lock);
/* schedule for regular updates */ /* schedule for regular updates */
afs_vlocation_queue_for_updates(vl); afs_vlocation_queue_for_updates(vl);
...@@ -434,22 +436,23 @@ struct afs_vlocation *afs_vlocation_lookup(struct afs_cell *cell, ...@@ -434,22 +436,23 @@ struct afs_vlocation *afs_vlocation_lookup(struct afs_cell *cell,
up_write(&cell->vl_sem); up_write(&cell->vl_sem);
/* see if it was an abandoned record that we might try filling in */ /* see if it was an abandoned record that we might try filling in */
spin_lock(&vl->lock);
while (vl->state != AFS_VL_VALID) { while (vl->state != AFS_VL_VALID) {
afs_vlocation_state_t state = vl->state; afs_vlocation_state_t state = vl->state;
_debug("invalid [state %d]", state); _debug("invalid [state %d]", state);
if ((state == AFS_VL_NEW || state == AFS_VL_NO_VOLUME)) { if ((state == AFS_VL_NEW || state == AFS_VL_NO_VOLUME)) {
if (cmpxchg(&vl->state, state, AFS_VL_CREATING) == vl->state = AFS_VL_CREATING;
state) spin_unlock(&vl->lock);
goto fill_in_record; goto fill_in_record;
continue;
} }
/* must now wait for creation or update by someone else to /* must now wait for creation or update by someone else to
* complete */ * complete */
_debug("wait"); _debug("wait");
spin_unlock(&vl->lock);
ret = wait_event_interruptible( ret = wait_event_interruptible(
vl->waitq, vl->waitq,
vl->state == AFS_VL_NEW || vl->state == AFS_VL_NEW ||
...@@ -457,15 +460,19 @@ struct afs_vlocation *afs_vlocation_lookup(struct afs_cell *cell, ...@@ -457,15 +460,19 @@ struct afs_vlocation *afs_vlocation_lookup(struct afs_cell *cell,
vl->state == AFS_VL_NO_VOLUME); vl->state == AFS_VL_NO_VOLUME);
if (ret < 0) if (ret < 0)
goto error; goto error;
spin_lock(&vl->lock);
} }
spin_unlock(&vl->lock);
success: success:
_leave(" = %p",vl); _leave(" = %p",vl);
return vl; return vl;
error_abandon: error_abandon:
spin_lock(&vl->lock);
vl->state = AFS_VL_NEW; vl->state = AFS_VL_NEW;
wake_up(&vl->waitq); wake_up(&vl->waitq);
spin_unlock(&vl->lock);
error: error:
ASSERT(vl != NULL); ASSERT(vl != NULL);
afs_put_vlocation(vl); afs_put_vlocation(vl);
...@@ -663,10 +670,12 @@ static void afs_vlocation_updater(struct work_struct *work) ...@@ -663,10 +670,12 @@ static void afs_vlocation_updater(struct work_struct *work)
vl->upd_busy_cnt = 0; vl->upd_busy_cnt = 0;
ret = afs_vlocation_update_record(vl, NULL, &vldb); ret = afs_vlocation_update_record(vl, NULL, &vldb);
spin_lock(&vl->lock);
switch (ret) { switch (ret) {
case 0: case 0:
afs_vlocation_apply_update(vl, &vldb); afs_vlocation_apply_update(vl, &vldb);
vl->state = AFS_VL_VALID; vl->state = AFS_VL_VALID;
wake_up(&vl->waitq);
break; break;
case -ENOMEDIUM: case -ENOMEDIUM:
vl->state = AFS_VL_VOLUME_DELETED; vl->state = AFS_VL_VOLUME_DELETED;
...@@ -675,6 +684,7 @@ static void afs_vlocation_updater(struct work_struct *work) ...@@ -675,6 +684,7 @@ static void afs_vlocation_updater(struct work_struct *work)
vl->state = AFS_VL_UNCERTAIN; vl->state = AFS_VL_UNCERTAIN;
break; break;
} }
spin_unlock(&vl->lock);
/* and then reschedule */ /* and then reschedule */
_debug("reschedule"); _debug("reschedule");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment