Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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>

+16 -6
+1 -1
fs/afs/internal.h
··· 219 219 struct afs_volume *vols[3]; /* volume access record pointer (index by type) */ 220 220 wait_queue_head_t waitq; /* status change waitqueue */ 221 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 223 afs_vlocation_state_t state; /* volume location state */ 224 224 unsigned short upd_rej_cnt; /* ENOMEDIUM count during update */ 225 225 unsigned short upd_busy_cnt; /* EBUSY count during update */
+15 -5
fs/afs/vlocation.c
··· 178 178 INIT_LIST_HEAD(&vl->grave); 179 179 INIT_LIST_HEAD(&vl->update); 180 180 init_waitqueue_head(&vl->waitq); 181 - rwlock_init(&vl->lock); 181 + spin_lock_init(&vl->lock); 182 182 memcpy(vl->vldb.name, name, namesz); 183 183 } 184 184 ··· 414 414 ret = afs_vlocation_fill_in_record(vl, key); 415 415 if (ret < 0) 416 416 goto error_abandon; 417 + spin_lock(&vl->lock); 417 418 vl->state = AFS_VL_VALID; 418 419 wake_up(&vl->waitq); 420 + spin_unlock(&vl->lock); 419 421 420 422 /* schedule for regular updates */ 421 423 afs_vlocation_queue_for_updates(vl); ··· 436 434 up_write(&cell->vl_sem); 437 435 438 436 /* see if it was an abandoned record that we might try filling in */ 437 + spin_lock(&vl->lock); 439 438 while (vl->state != AFS_VL_VALID) { 440 439 afs_vlocation_state_t state = vl->state; 441 440 442 441 _debug("invalid [state %d]", state); 443 442 444 443 if ((state == AFS_VL_NEW || state == AFS_VL_NO_VOLUME)) { 445 - if (cmpxchg(&vl->state, state, AFS_VL_CREATING) == 446 - state) 447 - goto fill_in_record; 448 - continue; 444 + vl->state = AFS_VL_CREATING; 445 + spin_unlock(&vl->lock); 446 + goto fill_in_record; 449 447 } 450 448 451 449 /* must now wait for creation or update by someone else to 452 450 * complete */ 453 451 _debug("wait"); 454 452 453 + spin_unlock(&vl->lock); 455 454 ret = wait_event_interruptible( 456 455 vl->waitq, 457 456 vl->state == AFS_VL_NEW || ··· 460 457 vl->state == AFS_VL_NO_VOLUME); 461 458 if (ret < 0) 462 459 goto error; 460 + spin_lock(&vl->lock); 463 461 } 462 + spin_unlock(&vl->lock); 464 463 465 464 success: 466 465 _leave(" = %p",vl); 467 466 return vl; 468 467 469 468 error_abandon: 469 + spin_lock(&vl->lock); 470 470 vl->state = AFS_VL_NEW; 471 471 wake_up(&vl->waitq); 472 + spin_unlock(&vl->lock); 472 473 error: 473 474 ASSERT(vl != NULL); 474 475 afs_put_vlocation(vl); ··· 670 663 vl->upd_busy_cnt = 0; 671 664 672 665 ret = afs_vlocation_update_record(vl, NULL, &vldb); 666 + spin_lock(&vl->lock); 673 667 switch (ret) { 674 668 case 0: 675 669 afs_vlocation_apply_update(vl, &vldb); 676 670 vl->state = AFS_VL_VALID; 671 + wake_up(&vl->waitq); 677 672 break; 678 673 case -ENOMEDIUM: 679 674 vl->state = AFS_VL_VOLUME_DELETED; ··· 684 675 vl->state = AFS_VL_UNCERTAIN; 685 676 break; 686 677 } 678 + spin_unlock(&vl->lock); 687 679 688 680 /* and then reschedule */ 689 681 _debug("reschedule");