aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorDavid S. Miller <davem@sunset.davemloft.net>2007-04-26 23:39:14 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-04-26 23:39:14 -0400
commit39bf09493042200b967cdf2ee6e3f670b7963903 (patch)
tree081f76ef36a7ac43dd756dea1f9201caba7c821b /fs
parent68c708fd5e90f6d178c84bb7e641589eb2842319 (diff)
[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>
Diffstat (limited to 'fs')
-rw-r--r--fs/afs/internal.h2
-rw-r--r--fs/afs/vlocation.c20
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 {
219 struct afs_volume *vols[3]; /* volume access record pointer (index by type) */ 219 struct afs_volume *vols[3]; /* volume access record pointer (index by type) */
220 wait_queue_head_t waitq; /* status change waitqueue */ 220 wait_queue_head_t waitq; /* status change waitqueue */
221 time_t update_at; /* time at which record should be updated */ 221 time_t update_at; /* time at which record should be updated */
222 rwlock_t lock; /* access lock */ 222 spinlock_t lock; /* access lock */
223 afs_vlocation_state_t state; /* volume location state */ 223 afs_vlocation_state_t state; /* volume location state */
224 unsigned short upd_rej_cnt; /* ENOMEDIUM count during update */ 224 unsigned short upd_rej_cnt; /* ENOMEDIUM count during update */
225 unsigned short upd_busy_cnt; /* EBUSY count during update */ 225 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,
178 INIT_LIST_HEAD(&vl->grave); 178 INIT_LIST_HEAD(&vl->grave);
179 INIT_LIST_HEAD(&vl->update); 179 INIT_LIST_HEAD(&vl->update);
180 init_waitqueue_head(&vl->waitq); 180 init_waitqueue_head(&vl->waitq);
181 rwlock_init(&vl->lock); 181 spin_lock_init(&vl->lock);
182 memcpy(vl->vldb.name, name, namesz); 182 memcpy(vl->vldb.name, name, namesz);
183 } 183 }
184 184
@@ -414,8 +414,10 @@ fill_in_record:
414 ret = afs_vlocation_fill_in_record(vl, key); 414 ret = afs_vlocation_fill_in_record(vl, key);
415 if (ret < 0) 415 if (ret < 0)
416 goto error_abandon; 416 goto error_abandon;
417 spin_lock(&vl->lock);
417 vl->state = AFS_VL_VALID; 418 vl->state = AFS_VL_VALID;
418 wake_up(&vl->waitq); 419 wake_up(&vl->waitq);
420 spin_unlock(&vl->lock);
419 421
420 /* schedule for regular updates */ 422 /* schedule for regular updates */
421 afs_vlocation_queue_for_updates(vl); 423 afs_vlocation_queue_for_updates(vl);
@@ -434,22 +436,23 @@ found_in_memory:
434 up_write(&cell->vl_sem); 436 up_write(&cell->vl_sem);
435 437
436 /* see if it was an abandoned record that we might try filling in */ 438 /* see if it was an abandoned record that we might try filling in */
439 spin_lock(&vl->lock);
437 while (vl->state != AFS_VL_VALID) { 440 while (vl->state != AFS_VL_VALID) {
438 afs_vlocation_state_t state = vl->state; 441 afs_vlocation_state_t state = vl->state;
439 442
440 _debug("invalid [state %d]", state); 443 _debug("invalid [state %d]", state);
441 444
442 if ((state == AFS_VL_NEW || state == AFS_VL_NO_VOLUME)) { 445 if ((state == AFS_VL_NEW || state == AFS_VL_NO_VOLUME)) {
443 if (cmpxchg(&vl->state, state, AFS_VL_CREATING) == 446 vl->state = AFS_VL_CREATING;
444 state) 447 spin_unlock(&vl->lock);
445 goto fill_in_record; 448 goto fill_in_record;
446 continue;
447 } 449 }
448 450
449 /* must now wait for creation or update by someone else to 451 /* must now wait for creation or update by someone else to
450 * complete */ 452 * complete */
451 _debug("wait"); 453 _debug("wait");
452 454
455 spin_unlock(&vl->lock);
453 ret = wait_event_interruptible( 456 ret = wait_event_interruptible(
454 vl->waitq, 457 vl->waitq,
455 vl->state == AFS_VL_NEW || 458 vl->state == AFS_VL_NEW ||
@@ -457,15 +460,19 @@ found_in_memory:
457 vl->state == AFS_VL_NO_VOLUME); 460 vl->state == AFS_VL_NO_VOLUME);
458 if (ret < 0) 461 if (ret < 0)
459 goto error; 462 goto error;
463 spin_lock(&vl->lock);
460 } 464 }
465 spin_unlock(&vl->lock);
461 466
462success: 467success:
463 _leave(" = %p",vl); 468 _leave(" = %p",vl);
464 return vl; 469 return vl;
465 470
466error_abandon: 471error_abandon:
472 spin_lock(&vl->lock);
467 vl->state = AFS_VL_NEW; 473 vl->state = AFS_VL_NEW;
468 wake_up(&vl->waitq); 474 wake_up(&vl->waitq);
475 spin_unlock(&vl->lock);
469error: 476error:
470 ASSERT(vl != NULL); 477 ASSERT(vl != NULL);
471 afs_put_vlocation(vl); 478 afs_put_vlocation(vl);
@@ -663,10 +670,12 @@ static void afs_vlocation_updater(struct work_struct *work)
663 vl->upd_busy_cnt = 0; 670 vl->upd_busy_cnt = 0;
664 671
665 ret = afs_vlocation_update_record(vl, NULL, &vldb); 672 ret = afs_vlocation_update_record(vl, NULL, &vldb);
673 spin_lock(&vl->lock);
666 switch (ret) { 674 switch (ret) {
667 case 0: 675 case 0:
668 afs_vlocation_apply_update(vl, &vldb); 676 afs_vlocation_apply_update(vl, &vldb);
669 vl->state = AFS_VL_VALID; 677 vl->state = AFS_VL_VALID;
678 wake_up(&vl->waitq);
670 break; 679 break;
671 case -ENOMEDIUM: 680 case -ENOMEDIUM:
672 vl->state = AFS_VL_VOLUME_DELETED; 681 vl->state = AFS_VL_VOLUME_DELETED;
@@ -675,6 +684,7 @@ static void afs_vlocation_updater(struct work_struct *work)
675 vl->state = AFS_VL_UNCERTAIN; 684 vl->state = AFS_VL_UNCERTAIN;
676 break; 685 break;
677 } 686 }
687 spin_unlock(&vl->lock);
678 688
679 /* and then reschedule */ 689 /* and then reschedule */
680 _debug("reschedule"); 690 _debug("reschedule");