/** * lookup a vg cache entry given any member volume id. * * @param[in] dp disk partition object * @param[in] volid vg member volume id * @param[out] entry_out address in which to store volume group entry structure pointer * @param[out] hash_out address in which to store hash entry pointer * * @pre VOL_LOCK held * * @warning - it is up to the caller to get a ref to entry_out, if needed * - hash_out must not be referenced after dropping VOL_LOCK * * @return operation status * @retval 0 success * @retval ENOENT volume id not found * @retval EINVAL partition's VGC is invalid * * @internal */ static int _VVGC_lookup(struct DiskPartition64 * dp, VolumeId volid, VVGCache_entry_t ** entry_out, VVGCache_hash_entry_t ** hash_out) { int code = ENOENT; int bucket = VVGC_HASH(volid); struct VVGCache_hash_entry * ent, * nent; if (VVGCache.part[dp->index].state == VVGC_PART_STATE_INVALID) { return EINVAL; } *entry_out = NULL; for (queue_Scan(&VVGCache_hash_table.hash_buckets[bucket], ent, nent, VVGCache_hash_entry)) { if (ent->volid == volid && ent->dp == dp) { code = 0; *entry_out = ent->entry; if (hash_out) { *hash_out = ent; } break; } } return code; }
/** * add an entry to the hash table. * * @param[in] dp disk partition object * @param[in] volid volume id * @param[in] ent volume group object * @param[out] hash_out address in which to store pointer to hash entry * * @pre VOL_LOCK held * * @return operation status * @retval 0 success * @retval EEXIST hash entry for volid already exists, and it points to * a different VG entry * * @internal */ static int _VVGC_hash_entry_add(struct DiskPartition64 * dp, VolumeId volid, VVGCache_entry_t * ent, VVGCache_hash_entry_t ** hash_out) { int code = 0; VVGCache_hash_entry_t * hent; int hash = VVGC_HASH(volid); VVGCache_entry_t *nent; code = _VVGC_lookup(dp, volid, &nent, hash_out); if (!code) { if (ent != nent) { ViceLog(0, ("_VVGC_hash_entry_add: tried to add a duplicate " " nonmatching entry for vol %lu: original " "(%"AFS_PTR_FMT",%lu) new (%"AFS_PTR_FMT",%lu)\n", afs_printable_uint32_lu(volid), nent, afs_printable_uint32_lu(nent->rw), ent, afs_printable_uint32_lu(ent->rw))); return EEXIST; } ViceLog(1, ("_VVGC_hash_entry_add: tried to add duplicate " "hash entry for vol %lu, VG %lu", afs_printable_uint32_lu(volid), afs_printable_uint32_lu(ent->rw))); /* accept attempts to add matching duplicate entries; just * pretend we added it */ return 0; } code = _VVGC_hash_entry_alloc(&hent); if (code) { goto done; } hent->entry = ent; hent->dp = dp; hent->volid = volid; queue_Append(&VVGCache_hash_table.hash_buckets[hash], hent); done: if (hash_out) { *hash_out = hent; } return code; }
/** * looks up an entry on the to-delete list, if it exists. * * @param[in] dp the partition whose dlist we are looking at * @param[in] parent the parent volume ID we're looking for * @param[in] child the child volume ID we're looking for * * @return a pointer to the entry in the dlist for that entry * @retval NULL the requested entry does not exist in the dlist */ static VVGCache_dlist_entry_t * _VVGC_dlist_lookup_r(struct DiskPartition64 *dp, VolumeId parent, VolumeId child) { int bucket = VVGC_HASH(child); VVGCache_dlist_entry_t *ent, *nent; for (queue_Scan(&VVGCache.part[dp->index].dlist_hash_buckets[bucket], ent, nent, VVGCache_dlist_entry)) { if (ent->child == child && ent->parent == parent) { return ent; } } return NULL; }
/** * add a VGC entry to the partition's to-delete list. * * This adds a VGC entry (a parent/child pair) to a list of VGC entries to * be deleted from the VGC at the end of a VGC scan. This is necessary, * while a VGC scan is ocurring, volumes may be deleted. Since a VGC scan * scans a partition in VVGC_SCAN_TBL_LEN chunks, a VGC delete operation * may delete a volume, only for it to be added again when the VGC scan's * table adds it to the VGC. So when a VGC entry is deleted and a VGC scan * is running, this function must be called to ensure it does not come * back onto the VGC. * * @param[in] dp the partition to whose dlist we are adding * @param[in] parent the parent volumeID of the VGC entry * @param[in] child the child volumeID of the VGC entry * * @return operation status * @retval 0 success * @retval ENOMEM memory allocation error * * @pre VVGCache.part[dp->index].state == VVGC_PART_STATE_UPDATING * * @internal VGC use only */ int _VVGC_dlist_add_r(struct DiskPartition64 *dp, VolumeId parent, VolumeId child) { int bucket = VVGC_HASH(child); VVGCache_dlist_entry_t *entry; entry = malloc(sizeof(*entry)); if (!entry) { return ENOMEM; } entry->child = child; entry->parent = parent; queue_Append(&VVGCache.part[dp->index].dlist_hash_buckets[bucket], entry); return 0; }