Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 39bf0949 authored by David S. Miller's avatar David S. Miller
Browse files

[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: default avatarDavid S. Miller <davem@davemloft.net>
parent 68c708fd
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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 */
+15 −5
Original line number Diff line number Diff line
@@ -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 @@ struct afs_vlocation *afs_vlocation_lookup(struct afs_cell *cell,
	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 @@ struct afs_vlocation *afs_vlocation_lookup(struct afs_cell *cell,
	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)
			vl->state = AFS_VL_CREATING;
			spin_unlock(&vl->lock);
			goto fill_in_record;
			continue;
		}

		/* 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 @@ struct afs_vlocation *afs_vlocation_lookup(struct afs_cell *cell,
			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");