cregit-Linux how code gets into the kernel

Release 4.11 drivers/misc/vmw_vmci/vmci_resource.c

/*
 * VMware VMCI Driver
 *
 * Copyright (C) 2012 VMware, Inc. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation version 2 and no later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 */

#include <linux/vmw_vmci_defs.h>
#include <linux/hash.h>
#include <linux/types.h>
#include <linux/rculist.h>
#include <linux/completion.h>

#include "vmci_resource.h"
#include "vmci_driver.h"



#define VMCI_RESOURCE_HASH_BITS         7

#define VMCI_RESOURCE_HASH_BUCKETS      (1 << VMCI_RESOURCE_HASH_BITS)


struct vmci_hash_table {
	
spinlock_t lock;
	
struct hlist_head entries[VMCI_RESOURCE_HASH_BUCKETS];
};


static struct vmci_hash_table vmci_resource_table = {
	.lock = __SPIN_LOCK_UNLOCKED(vmci_resource_table.lock),
};


static unsigned int vmci_resource_hash(struct vmci_handle handle) { return hash_32(handle.resource, VMCI_RESOURCE_HASH_BITS); }

Contributors

PersonTokensPropCommitsCommitProp
George Zhang21100.00%1100.00%
Total21100.00%1100.00%

/* * Gets a resource (if one exists) matching given handle from the hash table. */
static struct vmci_resource *vmci_resource_lookup(struct vmci_handle handle, enum vmci_resource_type type) { struct vmci_resource *r, *resource = NULL; unsigned int idx = vmci_resource_hash(handle); rcu_read_lock(); hlist_for_each_entry_rcu(r, &vmci_resource_table.entries[idx], node) { u32 cid = r->handle.context; u32 rid = r->handle.resource; if (r->type == type && rid == handle.resource && (cid == handle.context || cid == VMCI_INVALID_ID)) { resource = r; break; } } rcu_read_unlock(); return resource; }

Contributors

PersonTokensPropCommitsCommitProp
George Zhang105100.00%1100.00%
Total105100.00%1100.00%

/* * Find an unused resource ID and return it. The first * VMCI_RESERVED_RESOURCE_ID_MAX are reserved so we start from * its value + 1. * Returns VMCI resource id on success, VMCI_INVALID_ID on failure. */
static u32 vmci_resource_find_id(u32 context_id, enum vmci_resource_type resource_type) { static u32 resource_id = VMCI_RESERVED_RESOURCE_ID_MAX + 1; u32 old_rid = resource_id; u32 current_rid; /* * Generate a unique resource ID. Keep on trying until we wrap around * in the RID space. */ do { struct vmci_handle handle; current_rid = resource_id; resource_id++; if (unlikely(resource_id == VMCI_INVALID_ID)) { /* Skip the reserved rids. */ resource_id = VMCI_RESERVED_RESOURCE_ID_MAX + 1; } handle = vmci_make_handle(context_id, current_rid); if (!vmci_resource_lookup(handle, resource_type)) return current_rid; } while (resource_id != old_rid); return VMCI_INVALID_ID; }

Contributors

PersonTokensPropCommitsCommitProp
George Zhang94100.00%1100.00%
Total94100.00%1100.00%


int vmci_resource_add(struct vmci_resource *resource, enum vmci_resource_type resource_type, struct vmci_handle handle) { unsigned int idx; int result; spin_lock(&vmci_resource_table.lock); if (handle.resource == VMCI_INVALID_ID) { handle.resource = vmci_resource_find_id(handle.context, resource_type); if (handle.resource == VMCI_INVALID_ID) { result = VMCI_ERROR_NO_HANDLE; goto out; } } else if (vmci_resource_lookup(handle, resource_type)) { result = VMCI_ERROR_ALREADY_EXISTS; goto out; } resource->handle = handle; resource->type = resource_type; INIT_HLIST_NODE(&resource->node); kref_init(&resource->kref); init_completion(&resource->done); idx = vmci_resource_hash(resource->handle); hlist_add_head_rcu(&resource->node, &vmci_resource_table.entries[idx]); result = VMCI_SUCCESS; out: spin_unlock(&vmci_resource_table.lock); return result; }

Contributors

PersonTokensPropCommitsCommitProp
George Zhang170100.00%1100.00%
Total170100.00%1100.00%


void vmci_resource_remove(struct vmci_resource *resource) { struct vmci_handle handle = resource->handle; unsigned int idx = vmci_resource_hash(handle); struct vmci_resource *r; /* Remove resource from hash table. */ spin_lock(&vmci_resource_table.lock); hlist_for_each_entry(r, &vmci_resource_table.entries[idx], node) { if (vmci_handle_is_equal(r->handle, resource->handle)) { hlist_del_init_rcu(&r->node); break; } } spin_unlock(&vmci_resource_table.lock); synchronize_rcu(); vmci_resource_put(resource); wait_for_completion(&resource->done); }

Contributors

PersonTokensPropCommitsCommitProp
George Zhang99100.00%1100.00%
Total99100.00%1100.00%


struct vmci_resource * vmci_resource_by_handle(struct vmci_handle resource_handle, enum vmci_resource_type resource_type) { struct vmci_resource *r, *resource = NULL; rcu_read_lock(); r = vmci_resource_lookup(resource_handle, resource_type); if (r && (resource_type == r->type || resource_type == VMCI_RESOURCE_TYPE_ANY)) { resource = vmci_resource_get(r); } rcu_read_unlock(); return resource; }

Contributors

PersonTokensPropCommitsCommitProp
George Zhang68100.00%1100.00%
Total68100.00%1100.00%

/* * Get a reference to given resource. */
struct vmci_resource *vmci_resource_get(struct vmci_resource *resource) { kref_get(&resource->kref); return resource; }

Contributors

PersonTokensPropCommitsCommitProp
George Zhang23100.00%1100.00%
Total23100.00%1100.00%


static void vmci_release_resource(struct kref *kref) { struct vmci_resource *resource = container_of(kref, struct vmci_resource, kref); /* Verify the resource has been unlinked from hash table */ WARN_ON(!hlist_unhashed(&resource->node)); /* Signal that container of this resource can now be destroyed */ complete(&resource->done); }

Contributors

PersonTokensPropCommitsCommitProp
George Zhang48100.00%1100.00%
Total48100.00%1100.00%

/* * Resource's release function will get called if last reference. * If it is the last reference, then we are sure that nobody else * can increment the count again (it's gone from the resource hash * table), so there's no need for locking here. */
int vmci_resource_put(struct vmci_resource *resource) { /* * We propagate the information back to caller in case it wants to know * whether entry was freed. */ return kref_put(&resource->kref, vmci_release_resource) ? VMCI_SUCCESS_ENTRY_DEAD : VMCI_SUCCESS; }

Contributors

PersonTokensPropCommitsCommitProp
George Zhang26100.00%1100.00%
Total26100.00%1100.00%


struct vmci_handle vmci_resource_handle(struct vmci_resource *resource) { return resource->handle; }

Contributors

PersonTokensPropCommitsCommitProp
George Zhang16100.00%1100.00%
Total16100.00%1100.00%


Overall Contributors

PersonTokensPropCommitsCommitProp
George Zhang73399.59%150.00%
Ingo Molnar30.41%150.00%
Total736100.00%2100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.