Source
x
for (i = 0; i < permits->nr_permits; i++) {
if (permits->permits[i].key < key)
continue;
if (permits->permits[i].key > key)
break;
if (permits->permits[i].access != caller_access) {
changed = true;
break;
}
if (cb_break != afs_cb_break_sum(vnode, vnode->cb_interest)) {
if (afs_cb_is_broken(cb_break, vnode,
vnode->cb_interest)) {
changed = true;
break;
}
/* The cache is still good. */
rcu_read_unlock();
return;
}
}
goto someone_else_changed_it_unlock;
RCU_INIT_POINTER(vnode->permit_cache, NULL);
spin_unlock(&vnode->lock);
afs_put_permits(permits);
permits = NULL;
size = 0;
}
}
if (cb_break != afs_cb_break_sum(vnode, vnode->cb_interest))
if (afs_cb_is_broken(cb_break, vnode, vnode->cb_interest))
goto someone_else_changed_it;
/* We need a ref on any permits list we want to copy as we'll have to
* drop the lock to do memory allocation.
*/
if (permits && !refcount_inc_not_zero(&permits->usage))
goto someone_else_changed_it;
rcu_read_unlock();
replacement = new;
new = NULL;
found:
spin_unlock(&afs_permits_lock);
kfree(new);
spin_lock(&vnode->lock);
zap = rcu_access_pointer(vnode->permit_cache);
if (cb_break == afs_cb_break_sum(vnode, vnode->cb_interest) &&
if (!afs_cb_is_broken(cb_break, vnode, vnode->cb_interest) &&
zap == permits)
rcu_assign_pointer(vnode->permit_cache, replacement);
else
zap = replacement;
spin_unlock(&vnode->lock);
afs_put_permits(zap);
out_put:
afs_put_permits(permits);
return;