[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: David S. Miller <davem@davemloft.net>
This commit is contained in:
@@ -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,
|
|||||||
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 @@ fill_in_record:
|
|||||||
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 @@ found_in_memory:
|
|||||||
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 @@ found_in_memory:
|
|||||||
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)
|
|||||||
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)
|
|||||||
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");
|
||||||
|
Reference in New Issue
Block a user