diff options
| author | David S. Miller <davem@sunset.davemloft.net> | 2007-04-26 23:39:14 -0400 |
|---|---|---|
| committer | David S. Miller <davem@sunset.davemloft.net> | 2007-04-26 23:39:14 -0400 |
| commit | 39bf09493042200b967cdf2ee6e3f670b7963903 (patch) | |
| tree | 081f76ef36a7ac43dd756dea1f9201caba7c821b | |
| parent | 68c708fd5e90f6d178c84bb7e641589eb2842319 (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>
| -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 { | |||
| 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 | ||
| 462 | success: | 467 | success: |
| 463 | _leave(" = %p",vl); | 468 | _leave(" = %p",vl); |
| 464 | return vl; | 469 | return vl; |
| 465 | 470 | ||
| 466 | error_abandon: | 471 | error_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); | ||
| 469 | error: | 476 | error: |
| 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"); |
