LASSERT(ops->hs_object);
LASSERT(ops->hs_keycmp);
LASSERT(ops->hs_get != NULL);
- LASSERT(ops->hs_put_locked != NULL);
+ LASSERT(ops->hs_put != NULL || ops->hs_put_locked != NULL);
if ((flags & CFS_HASH_REHASH) != 0)
flags |= CFS_HASH_COUNTER; /* must have counter */
void *data, int start)
{
struct hlist_node *hnode;
- struct hlist_node *tmp;
+ struct hlist_node *next = NULL;
struct cfs_hash_bd bd;
__u32 version;
int count = 0;
int stop_on_change;
+ int has_put_locked;
int rc = 0;
int i, end = -1;
ENTRY;
stop_on_change = cfs_hash_with_rehash_key(hs) ||
- !cfs_hash_with_no_itemref(hs) ||
- hs->hs_ops->hs_put_locked == NULL;
+ !cfs_hash_with_no_itemref(hs);
+ has_put_locked = hs->hs_ops->hs_put_locked != NULL;
cfs_hash_lock(hs, 0);
again:
LASSERT(!cfs_hash_is_rehashing(hs));
version = cfs_hash_bd_version_get(&bd);
cfs_hash_bd_for_each_hlist(hs, &bd, hhead) {
- for (hnode = hhead->first; hnode != NULL;) {
- cfs_hash_bucket_validate(hs, &bd, hnode);
- cfs_hash_get(hs, hnode);
+ hnode = hhead->first;
+ if (hnode == NULL)
+ continue;
+ cfs_hash_get(hs, hnode);
+ for (; hnode != NULL; hnode = next) {
+ cfs_hash_bucket_validate(hs, &bd, hnode);
+ next = hnode->next;
+ if (next != NULL)
+ cfs_hash_get(hs, next);
cfs_hash_bd_unlock(hs, &bd, 0);
cfs_hash_unlock(hs, 0);
rc = func(hs, &bd, hnode, data);
- if (stop_on_change)
+ if (stop_on_change || !has_put_locked)
cfs_hash_put(hs, hnode);
+
cond_resched();
count++;
cfs_hash_lock(hs, 0);
cfs_hash_bd_lock(hs, &bd, 0);
- if (!stop_on_change) {
- tmp = hnode->next;
- cfs_hash_put_locked(hs, hnode);
- hnode = tmp;
- } else { /* bucket changed? */
- if (version !=
- cfs_hash_bd_version_get(&bd))
- break;
- /* safe to continue because no change */
- hnode = hnode->next;
- }
+ if (stop_on_change) {
+ if (version !=
+ cfs_hash_bd_version_get(&bd))
+ rc = -EINTR;
+ } else if (has_put_locked) {
+ cfs_hash_put_locked(hs, hnode);
+ }
if (rc) /* callback wants to break iteration */
break;
}
- if (rc) /* callback wants to break iteration */
+ if (next != NULL) {
+ if (has_put_locked) {
+ cfs_hash_put_locked(hs, next);
+ next = NULL;
+ }
break;
+ } else if (rc != 0) {
+ break;
+ }
}
cfs_hash_bd_unlock(hs, &bd, 0);
+ if (next != NULL && !has_put_locked) {
+ cfs_hash_put(hs, next);
+ next = NULL;
+ }
if (rc) /* callback wants to break iteration */
break;
}