diff options
author | David S. Miller <davem@sunset.davemloft.net> | 2007-04-26 20:39:14 -0700 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-04-26 20:39:14 -0700 |
commit | 39bf09493042200b967cdf2ee6e3f670b7963903 (patch) | |
tree | 081f76ef36a7ac43dd756dea1f9201caba7c821b | |
parent | 68c708fd5e90f6d178c84bb7e641589eb2842319 (diff) | |
download | linux-39bf09493042200b967cdf2ee6e3f670b7963903.tar.gz linux-39bf09493042200b967cdf2ee6e3f670b7963903.tar.bz2 linux-39bf09493042200b967cdf2ee6e3f670b7963903.zip |
[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>
-rw-r--r-- | fs/afs/internal.h | 2 | ||||
-rw-r--r-- | fs/afs/vlocation.c | 20 |
2 files changed, 16 insertions, 6 deletions
diff --git a/fs/afs/internal.h b/fs/afs/internal.h index 73bfa0b2d99e..6dd3197d1d8d 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -219,7 +219,7 @@ struct afs_vlocation { struct afs_volume *vols[3]; /* volume access record pointer (index by type) */ wait_queue_head_t waitq; /* status change waitqueue */ 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 */ unsigned short upd_rej_cnt; /* ENOMEDIUM count during update */ unsigned short upd_busy_cnt; /* EBUSY count during update */ diff --git a/fs/afs/vlocation.c b/fs/afs/vlocation.c index 7d9815e9ae0f..74cce174882a 100644 --- a/fs/afs/vlocation.c +++ b/fs/afs/vlocation.c @@ -178,7 +178,7 @@ static struct afs_vlocation *afs_vlocation_alloc(struct afs_cell *cell, 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); } @@ -414,8 +414,10 @@ fill_in_record: ret = afs_vlocation_fill_in_record(vl, key); if (ret < 0) goto error_abandon; + spin_lock(&vl->lock); vl->state = AFS_VL_VALID; wake_up(&vl->waitq); + spin_unlock(&vl->lock); /* schedule for regular updates */ afs_vlocation_queue_for_updates(vl); @@ -434,22 +436,23 @@ found_in_memory: 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; + 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"); + spin_unlock(&vl->lock); ret = wait_event_interruptible( vl->waitq, vl->state == AFS_VL_NEW || @@ -457,15 +460,19 @@ found_in_memory: 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; wake_up(&vl->waitq); + spin_unlock(&vl->lock); error: ASSERT(vl != NULL); afs_put_vlocation(vl); @@ -663,10 +670,12 @@ static void afs_vlocation_updater(struct work_struct *work) vl->upd_busy_cnt = 0; 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_VALID; + wake_up(&vl->waitq); break; case -ENOMEDIUM: vl->state = AFS_VL_VOLUME_DELETED; @@ -675,6 +684,7 @@ static void afs_vlocation_updater(struct work_struct *work) vl->state = AFS_VL_UNCERTAIN; break; } + spin_unlock(&vl->lock); /* and then reschedule */ _debug("reschedule"); |