From patchwork Fri Jan 10 02:30:51 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tamas K Lengyel X-Patchwork-Id: 11326509 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 6E654139A for ; Fri, 10 Jan 2020 02:32:12 +0000 (UTC) Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 545A72073A for ; Fri, 10 Jan 2020 02:32:12 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 545A72073A Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=tklengyel.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=xen-devel-bounces@lists.xenproject.org Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1ipk4o-0004lg-Le; Fri, 10 Jan 2020 02:31:06 +0000 Received: from us1-rack-iad1.inumbo.com ([172.99.69.81]) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1ipk4m-0004kx-Mi for xen-devel@lists.xenproject.org; Fri, 10 Jan 2020 02:31:04 +0000 X-Inumbo-ID: 3adf1b64-3351-11ea-a985-bc764e2007e4 Received: from mail-il1-f193.google.com (unknown [209.85.166.193]) by us1-rack-iad1.inumbo.com (Halon) with ESMTPS id 3adf1b64-3351-11ea-a985-bc764e2007e4; Fri, 10 Jan 2020 02:30:56 +0000 (UTC) Received: by mail-il1-f193.google.com with SMTP id v15so604745iln.0 for ; Thu, 09 Jan 2020 18:30:56 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=D/yjllHkFnMQGLT8VfSEgGxQb9zI/JFOCa8xhRGm7k8=; b=qgj8beyiTkTH26v44LjI6wKmGPc1BK9QGxiJITZf5ksGkA0Rgrz2Pq2KaqXzTmh1qm SkdR7fwETtadONjbqE08dxou2WEuHIt/3j+YEVZwLoRQRrl9po6xIC92V0osyvVGR8Gg nPvsMYY/LY0/aK1q4+s98jCaANybAcbhDFXWN60rh2si7vo5sLyK62+Pf9d4i0IrWLBL Aab/QF79dY8ax4tUiIW4F/KJ0P7Rnm4iwhaaJx8GFfXAGVogC8GTqt1YsHaLaVyz7DxV h1/fVLLL2w5YI7se15q3W3rihE2ZZOj4fMmlWhCRQL7VKw3CpeXr3K6E7hGrcclNYxZy w0bw== X-Gm-Message-State: APjAAAUOHfpl8LH8fk13pfWDEtWynpewx+ZXCqgpPSvfPkkhB8Ozz4BI qptmD2+h3LfXWsa3gBgQlvcHbMEP1uk= X-Google-Smtp-Source: APXvYqz6E5a9E7Erm8umj69G1U4RuTdQc0VwHwYHiG5fwEQaz7pTi1wWoakMOoB2JKeUhvcIFiD2XQ== X-Received: by 2002:a92:1f16:: with SMTP id i22mr664477ile.206.1578623455486; Thu, 09 Jan 2020 18:30:55 -0800 (PST) Received: from l1.lan ([2601:280:4c00:797:7e7a:91ff:fe03:32f2]) by smtp.gmail.com with ESMTPSA id p12sm233622ilk.66.2020.01.09.18.30.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 09 Jan 2020 18:30:54 -0800 (PST) From: Tamas K Lengyel To: xen-devel@lists.xenproject.org Date: Thu, 9 Jan 2020 19:30:51 -0700 Message-Id: <20200110023052.21159-1-tamas@tklengyel.com> X-Mailer: git-send-email 2.20.1 MIME-Version: 1.0 Subject: [Xen-devel] [PATCH 1/2] MAINTAINERS: adjust path of actually maintained memshr code in tools X-BeenThere: xen-devel@lists.xenproject.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Cc: Tamas K Lengyel , Julien Grall , Wei Liu , Konrad Rzeszutek Wilk , George Dunlap , Andrew Cooper , Ian Jackson , Stefano Stabellini , Jan Beulich Errors-To: xen-devel-bounces@lists.xenproject.org Sender: "Xen-devel" Only tools/tests/mem-sharing is maintained under the tools folder. Signed-off-by: Tamas K Lengyel --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index a42fef6ab9..21744ace6d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -504,7 +504,7 @@ X86 MEMORY SHARING M: Tamas K Lengyel S: Odd Fixes F: xen/arch/x86/mm/mem_sharing.c -F: tools/memshr +F: tools/tests/mem-sharing/ X86 SHADOW PAGETABLES M: Tim Deegan From patchwork Fri Jan 10 02:30:52 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tamas K Lengyel X-Patchwork-Id: 11326511 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id DCEF0139A for ; Fri, 10 Jan 2020 02:32:36 +0000 (UTC) Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id A09D42073A for ; Fri, 10 Jan 2020 02:32:36 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org A09D42073A Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=tklengyel.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=xen-devel-bounces@lists.xenproject.org Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1ipk4m-0004kr-5n; Fri, 10 Jan 2020 02:31:04 +0000 Received: from all-amaz-eas1.inumbo.com ([34.197.232.57] helo=us1-amaz-eas2.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1ipk4l-0004kl-BV for xen-devel@lists.xenproject.org; Fri, 10 Jan 2020 02:31:03 +0000 X-Inumbo-ID: 3d029362-3351-11ea-bbef-12813bfff9fa Received: from mail-io1-f53.google.com (unknown [209.85.166.53]) by us1-amaz-eas2.inumbo.com (Halon) with ESMTPS id 3d029362-3351-11ea-bbef-12813bfff9fa; Fri, 10 Jan 2020 02:30:59 +0000 (UTC) Received: by mail-io1-f53.google.com with SMTP id c16so393812ioo.8 for ; Thu, 09 Jan 2020 18:30:59 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=S0OuIP8+ucUCDVu7t6xzNjlZC8xt+10xUjUxDwWISgA=; b=OGBFnDoX/JJeApchl17WmToGfuAznOrh6x++C46R4g2XXhpvn4hgcHgtZjja3Cxp0P edmj+eWUtNJR/E6wyLIC/UUF6mOndJRo+D6TJiGvRkALF18RNJcB5JBD69djiisyyVXB jqdWcY51stFOdgBLAbrLm5lPDKnno5irC3MtNqhgPRJ2j4h/Jeri10avLOcaWHkaMWDP naxNZDifwe8a8ZcRUJULecfv7m1d02/pJj787LQRfvFxfXd0DQ/P3L0jLJTaOQ9t9pNR Y2KOWqqc/awo2d2GcDPHnCYlAmitfUAQ75tdx/9ujr3DT5hUWhLyFpmpcaxTpvdMc5uN UiyQ== X-Gm-Message-State: APjAAAWawLvftj5jG1RWJsqdfLG50z4cOoS4/me8xO/iPiRouXWnPeWR aK9dcAtqL5g5pRMypG9jHOrCsh3E+Ek= X-Google-Smtp-Source: APXvYqzlDbTN196V9ba2dQPos0Arpukk9n/laoHDYX/TOsRIizyqC210epIZclWoluUvmZnL6A0mXw== X-Received: by 2002:a6b:4e08:: with SMTP id c8mr500480iob.64.1578623457340; Thu, 09 Jan 2020 18:30:57 -0800 (PST) Received: from l1.lan ([2601:280:4c00:797:7e7a:91ff:fe03:32f2]) by smtp.gmail.com with ESMTPSA id p12sm233622ilk.66.2020.01.09.18.30.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 09 Jan 2020 18:30:56 -0800 (PST) From: Tamas K Lengyel To: xen-devel@lists.xenproject.org Date: Thu, 9 Jan 2020 19:30:52 -0700 Message-Id: <20200110023052.21159-2-tamas@tklengyel.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200110023052.21159-1-tamas@tklengyel.com> References: <20200110023052.21159-1-tamas@tklengyel.com> MIME-Version: 1.0 Subject: [Xen-devel] [PATCH 2/2] Remove undocumented and unmaintained tools/memshr library X-BeenThere: xen-devel@lists.xenproject.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Cc: Tamas K Lengyel , Ian Jackson , Wei Liu Errors-To: xen-devel-bounces@lists.xenproject.org Sender: "Xen-devel" The library has been largely untouched for over a decade at this point, it is undocumented and it's unclear what it was originally used for. Remove it from tree, if anyone needs it in the future it can be carved out from git history. Signed-off-by: Tamas K Lengyel Acked-by: Wei Liu --- tools/Makefile | 1 - tools/memshr/Makefile | 49 -- tools/memshr/bidir-daemon.c | 103 --- tools/memshr/bidir-daemon.h | 24 - tools/memshr/bidir-hash.c | 1355 --------------------------------- tools/memshr/bidir-hash.h | 114 --- tools/memshr/bidir-namedefs.h | 79 -- tools/memshr/interface.c | 224 ------ tools/memshr/memshr-priv.h | 33 - tools/memshr/memshr.h | 51 -- tools/memshr/shm.c | 262 ------- tools/memshr/shm.h | 49 -- 12 files changed, 2344 deletions(-) delete mode 100644 tools/memshr/Makefile delete mode 100644 tools/memshr/bidir-daemon.c delete mode 100644 tools/memshr/bidir-daemon.h delete mode 100644 tools/memshr/bidir-hash.c delete mode 100644 tools/memshr/bidir-hash.h delete mode 100644 tools/memshr/bidir-namedefs.h delete mode 100644 tools/memshr/interface.c delete mode 100644 tools/memshr/memshr-priv.h delete mode 100644 tools/memshr/memshr.h delete mode 100644 tools/memshr/shm.c delete mode 100644 tools/memshr/shm.h diff --git a/tools/Makefile b/tools/Makefile index 7b1f6c4d28..c10946e3b1 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -19,7 +19,6 @@ SUBDIRS-$(CONFIG_X86) += firmware SUBDIRS-y += console SUBDIRS-y += xenmon SUBDIRS-y += xenstat -SUBDIRS-$(CONFIG_Linux) += memshr SUBDIRS-$(CONFIG_NetBSD) += xenbackendd SUBDIRS-y += libfsimage SUBDIRS-$(CONFIG_Linux) += libvchan diff --git a/tools/memshr/Makefile b/tools/memshr/Makefile deleted file mode 100644 index 31d2dd7ada..0000000000 --- a/tools/memshr/Makefile +++ /dev/null @@ -1,49 +0,0 @@ -XEN_ROOT = $(CURDIR)/../.. -include $(XEN_ROOT)/tools/Rules.mk - -LIBMEMSHR-BUILD := libmemshr.a - -CFLAGS += -Werror -CFLAGS += -Wno-unused -CFLAGS += $(CFLAGS_xeninclude) -CFLAGS += $(CFLAGS_libxenctrl) -CFLAGS += -D_GNU_SOURCE -CFLAGS += -fPIC - -LIB-SRCS := interface.c -LIB-SRCS += shm.c -LIB-SRCS += bidir-daemon.c -LIB-SRCS += bidir-hash.c - -LIB-OBJS := interface.o -LIB-OBJS += shm.o -LIB-OBJS += bidir-daemon.o -LIB-OBJS += bidir-hash-fgprtshr.o -LIB-OBJS += bidir-hash-blockshr.o - -all: build - -build: $(LIBMEMSHR-BUILD) - -bidir-hash-fgprtshr.o: bidir-hash.c - $(CC) $(CFLAGS) -DFINGERPRINT_MAP -c -o $*.o bidir-hash.c - -bidir-hash-blockshr.o: bidir-hash.c - $(CC) $(CFLAGS) -DBLOCK_MAP -c -o $*.o bidir-hash.c - -libmemshr.a: $(LIB-OBJS) - $(AR) rc $@ $^ - -install: all - -uninstall: - -clean: - rm -rf *.a *.o *~ $(DEPS_RM) - -.PHONY: distclean -distclean: clean - -.PHONY: all build clean install distclean uninstall - --include $(DEPS_INCLUDE) diff --git a/tools/memshr/bidir-daemon.c b/tools/memshr/bidir-daemon.c deleted file mode 100644 index ddb7c00319..0000000000 --- a/tools/memshr/bidir-daemon.c +++ /dev/null @@ -1,103 +0,0 @@ -/****************************************************************************** - * - * Copyright (c) 2009 Citrix Systems, Inc. (Grzegorz Milos) - * - * 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; either version 2 of the License, or - * (at your option) any 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; If not, see . - */ -#include -#include -#include -#include - -#include "bidir-hash.h" -#include "memshr-priv.h" - -static struct blockshr_hash *blks_hash; - -/* Callback in the iterator, remember this value, and leave */ -int find_one(vbdblk_t k, share_tuple_t v, void *priv) -{ - share_tuple_t *rv = (share_tuple_t *) priv; - *rv = v; - /* Break out of iterator loop */ - return 1; -} - -void* bidir_daemon(void *unused) -{ - uint32_t nr_ent, max_nr_ent, tab_size, max_load, min_load; - - while(1) - { - blockshr_hash_sizes( blks_hash, - &nr_ent, - &max_nr_ent, - &tab_size, - &max_load, - &min_load); - /* Remove some hints as soon as we get to 90% capacity */ - if(10 * nr_ent > 9 * max_nr_ent) - { - share_tuple_t next_remove; - int to_remove; - int ret; - - to_remove = 0.1 * max_nr_ent; - while(to_remove > 0) - { - /* We use the iterator to get one entry */ - next_remove.handle = 0; - ret = blockshr_hash_iterator(blks_hash, find_one, &next_remove); - - if ( !ret ) - if ( next_remove.handle == 0 ) - ret = -ESRCH; - - if ( !ret ) - ret = blockshr_shrhnd_remove(blks_hash, next_remove, NULL); - - if(ret <= 0) - { - /* We failed to remove an entry, because of a serious hash - * table error */ - DPRINTF("Could not remove handle %"PRId64", error: %d\n", - next_remove.handle, ret); - /* Force to exit the loop early */ - to_remove = 0; - } else - if(ret > 0) - { - /* Managed to remove the entry. Note next_remove not - * incremented, in case there are duplicates */ - to_remove--; - } - } - } - - sleep(1); - } -} - -void bidir_daemon_launch(void) -{ - pthread_t thread; - - pthread_create(&thread, NULL, bidir_daemon, NULL); -} - -void bidir_daemon_initialize(struct blockshr_hash *blks) -{ - blks_hash = blks; - bidir_daemon_launch(); -} diff --git a/tools/memshr/bidir-daemon.h b/tools/memshr/bidir-daemon.h deleted file mode 100644 index f683280678..0000000000 --- a/tools/memshr/bidir-daemon.h +++ /dev/null @@ -1,24 +0,0 @@ -/****************************************************************************** - * - * Copyright (c) 2009 Citrix Systems, Inc. (Grzegorz Milos) - * - * 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; either version 2 of the License, or - * (at your option) any 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; If not, see . - */ - -#ifndef __BIDIR_DAEMON_H__ -#define __BIDIR_DAEMON_H__ - -void bidir_daemon_initialize(struct blockshr_hash *blks); - -#endif /* __BIDIR_DAEMON_H__ */ diff --git a/tools/memshr/bidir-hash.c b/tools/memshr/bidir-hash.c deleted file mode 100644 index c5cc71e3ca..0000000000 --- a/tools/memshr/bidir-hash.c +++ /dev/null @@ -1,1355 +0,0 @@ -/****************************************************************************** - * - * Copyright (c) 2009 Citrix Systems, Inc. (Grzegorz Milos) - * - * 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; either version 2 of the License, or - * (at your option) any 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; If not, see . - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "bidir-hash.h" - -static const uint32_t hash_sizes[] = {53, 97, 193, 389, 769, 1543, 3079, 6151, - 12289, 24593, 49157, 98317, 196613, 393241, 786433, 1572869, 3145739, - 6291469, 12582917, 25165843, 50331653, 100663319, 201326611, 402653189, - 805306457, 1610612741}; -static const uint16_t hash_sizes_len = - sizeof(hash_sizes)/sizeof(hash_sizes[0]); -static const float hash_max_load_fact = 0.65; -static const float hash_min_load_fact = 0.10; - -/* How many buckets will be covered by a single rw lock */ -#define BUCKETS_PER_LOCK 64 -#define nr_locks(_nr_buckets) (1 + (_nr_buckets) / BUCKETS_PER_LOCK) - - -#define HASH_LOCK \ - pthread_rwlock_t hash_lock - -#define BUCKET_LOCK \ - pthread_rwlock_t bucket_lock - -struct hash_entry -{ - __k_t key; - __v_t value; - /* This structure will belong to two buckets, one in each hash table */ - struct hash_entry *key_next; - struct hash_entry *value_next; -}; - -struct bucket -{ - struct hash_entry *hash_entry; -}; - -struct bucket_lock -{ - BUCKET_LOCK; -}; - -struct __hash -{ - int lock_alive; - HASH_LOCK; /* protects: - * *_tab, tab_size, size_idx, *_load - * (all writes with wrlock) - */ - uint32_t nr_ent; /* # entries held in hashtables */ - struct bucket *key_tab; /* forward mapping hashtable */ - struct bucket *value_tab; /* backward mapping hashtable */ - struct bucket_lock *key_lock_tab; /* key table bucket locks */ - struct bucket_lock *value_lock_tab; /* value table bucket locks */ - uint32_t tab_size; /* # buckets is hashtables */ - uint16_t size_idx; /* table size index */ - uint32_t max_load; /* # entries before rehash */ - uint32_t min_load; /* # entries before rehash */ -}; - -struct __hash *__hash_init (struct __hash *h, uint32_t min_size); -int __key_lookup (struct __hash *h, __k_t k, __v_t *vp); -int __value_lookup(struct __hash *h, __v_t v, __k_t *kp); -int __insert (struct __hash *h, __k_t k, __v_t v); -int __key_remove (struct __hash *h, __k_t k, __v_t *vp); -int __value_remove(struct __hash *h, __v_t v, __k_t *kp); -int __hash_destroy(struct __hash *h, - void (*entry_consumer)(__k_t k, __v_t v, void *p), - void *d); -int __hash_iterator(struct __hash *h, - int (*entry_consumer)(__k_t k, __v_t v, void *p), - void *d); -static void hash_resize(struct __hash *h); - -#if defined(__arm__) -static inline void atomic_inc(uint32_t *v) -{ - unsigned long tmp; - int result; - - __asm__ __volatile__("@ atomic_inc\n" -"1: ldrex %0, [%3]\n" -" add %0, %0, #1\n" -" strex %1, %0, [%3]\n" -" teq %1, #0\n" -" bne 1b" - : "=&r" (result), "=&r" (tmp), "+Qo" (*v) - : "r" (v) - : "cc"); -} -static inline void atomic_dec(uint32_t *v) -{ - unsigned long tmp; - int result; - - __asm__ __volatile__("@ atomic_dec\n" -"1: ldrex %0, [%3]\n" -" sub %0, %0, #1\n" -" strex %1, %0, [%3]\n" -" teq %1, #0\n" -" bne 1b" - : "=&r" (result), "=&r" (tmp), "+Qo" (*v) - : "r" (v) - : "cc"); -} - -#elif defined(__aarch64__) - -static inline void atomic_inc(uint32_t *v) -{ - unsigned long tmp; - int result; - - asm volatile("// atomic_inc\n" -"1: ldxr %w0, [%3]\n" -" add %w0, %w0, #1\n" -" stxr %w1, %w0, [%3]\n" -" cbnz %w1, 1b" - : "=&r" (result), "=&r" (tmp), "+o" (v) - : "r" (v) - : "cc"); -} - -static inline void atomic_dec(uint32_t *v) -{ - unsigned long tmp; - int result; - - asm volatile("// atomic_dec\n" -"1: ldxr %w0, [%3]\n" -" sub %w0, %w0, #1\n" -" stxr %w1, %w0, [%3]\n" -" cbnz %w1, 1b" - : "=&r" (result), "=&r" (tmp), "+o" (v) - : "r" (v) - : "cc"); -} - -#else /* __x86__ */ -static inline void atomic_inc(uint32_t *v) -{ - asm volatile ( - "lock ; incl %0" - : "=m" (*(volatile uint32_t *)v) - : "m" (*(volatile uint32_t *)v) ); -} -static inline void atomic_dec(uint32_t *v) -{ - asm volatile ( - "lock ; decl %0" - : "=m" (*(volatile uint32_t *)v) - : "m" (*(volatile uint32_t *)v) ); -} -#endif - -#ifdef BIDIR_USE_STDMALLOC - -static void* alloc_entry(struct __hash *h, int size) -{ - return malloc(size); -} - -static void alloc_buckets(struct __hash *h, - int nr_buckets, - struct bucket **bucket_tab, - struct bucket_lock **bucket_locks_tab) -{ - *bucket_tab = (struct bucket*) - malloc(nr_buckets * sizeof(struct bucket)); - *bucket_locks_tab = (struct bucket_lock*) - malloc(nr_locks(nr_buckets) * sizeof(struct bucket_lock)); -} - -static void free_entry(struct __hash *h, void *p) -{ - free(p); -} - -static void free_buckets(struct __hash *h, - struct bucket *buckets, - struct bucket_lock *bucket_locks) -{ - free(buckets); - free(bucket_locks); -} - -static int max_entries(struct __hash *h) -{ - /* There are no explicit restrictions to how many entries we can store */ - return -1; -} - -#else - -/*****************************************************************************/ -/** Memory allocator for shared memory region **/ -/*****************************************************************************/ -#define SHM_TABLE_SLOTS 4 - -struct shm_hdr -{ - int hash_allocated; - pthread_mutex_t mutex; - int free_tab_slots[SHM_TABLE_SLOTS]; - - unsigned long freelist_offset; - - unsigned long entries_offset; - unsigned long nr_entries; - - unsigned long tabs_offset; - unsigned long max_tab_size; - unsigned long max_lock_tab_size; - - struct __hash hash; -}; - -static unsigned long get_shm_baddr(void *hdr) -{ - return ((unsigned long)hdr - offsetof(struct shm_hdr, hash)); -} - - -/** Locations of various structures/memory areas **/ -static struct shm_hdr* get_shm_hdr(struct __hash *h) -{ - return (struct shm_hdr *) - ((unsigned long)h - offsetof(struct shm_hdr, hash)); -} - -static uint32_t* get_shm_freelist(struct shm_hdr *hdr) -{ - unsigned long shm_baddr = (unsigned long)hdr; - return ((uint32_t *)(shm_baddr + hdr->freelist_offset)); -} - -static struct hash_entry* get_shm_entries(struct shm_hdr *hdr) -{ - unsigned long shm_baddr = (unsigned long)hdr; - return ((struct hash_entry *)(shm_baddr + hdr->entries_offset)); -} - -static struct bucket* get_shm_tab(struct shm_hdr *hdr, int i) -{ - unsigned long shm_baddr = (unsigned long)hdr; - return ((struct bucket *) - ((shm_baddr + hdr->tabs_offset) + - i * (hdr->max_tab_size + hdr->max_lock_tab_size))); -} - -static struct bucket_lock* get_shm_lock_tab(struct shm_hdr *hdr, int i) -{ - unsigned long shm_baddr = (unsigned long)hdr; - return ((struct bucket_lock *) - ((shm_baddr + hdr->tabs_offset) + - i * (hdr->max_tab_size + hdr->max_lock_tab_size) + - hdr->max_tab_size)); -} - -static int get_shm_slot(struct shm_hdr *hdr, void *p) -{ - unsigned long shm_baddr = (unsigned long)hdr; - return ((unsigned long)p - (shm_baddr + hdr->tabs_offset)) / - (hdr->max_tab_size + hdr->max_lock_tab_size); -} - -/* Shared memory allocator locks */ -static int shm_mutex_init(struct shm_hdr *h) -{ - int ret; - pthread_mutexattr_t _attr; - - ret = pthread_mutexattr_init(&_attr); - if(ret == 0) - ret = pthread_mutexattr_setpshared(&_attr, PTHREAD_PROCESS_SHARED); - if(ret == 0) - ret = pthread_mutex_init(&h->mutex, &_attr); - if(ret == 0) - ret = pthread_mutexattr_destroy(&_attr); - - return ret; -}; - -static int shm_mutex_lock(struct shm_hdr *h) -{ - return pthread_mutex_lock(&h->mutex); -} - -static int shm_mutex_unlock(struct shm_hdr *h) -{ - return pthread_mutex_unlock(&h->mutex); -} - - -/* Shared memory allocator freelist */ -static void shm_add_to_freelist(struct shm_hdr *hdr, uint32_t sl) -{ - uint32_t *freelist = get_shm_freelist(hdr); - - shm_mutex_lock(hdr); - freelist[sl+1] = freelist[0]; - freelist[0] = sl; - shm_mutex_unlock(hdr); -} - -static uint32_t shm_get_from_freelist(struct shm_hdr *hdr) -{ - uint32_t *freelist = get_shm_freelist(hdr); - uint32_t slot; - - shm_mutex_lock(hdr); - slot = freelist[0]; - freelist[0] = freelist[slot+1]; - shm_mutex_unlock(hdr); - - return (slot == 0 ? -1 : slot); -} - - -#define SHM_ALLOC_MAIN(_n) - -static unsigned long shm_init_offsets( - struct shm_hdr *hdr, int nr_entries) -{ - hdr->freelist_offset = sizeof(struct shm_hdr); - - /* Freelist needs one extra slot in the array for the freelist head */ - hdr->entries_offset = - hdr->freelist_offset + (nr_entries + 1) * sizeof(uint32_t); - hdr->nr_entries = nr_entries; - - hdr->tabs_offset = hdr->entries_offset + - nr_entries * sizeof(struct hash_entry); - /* We want to allocate table 1.5 larger than the number of entries - we want to hold in it */ - hdr->max_tab_size = - (nr_entries * 3 / 2) * sizeof(struct bucket); - hdr->max_lock_tab_size = - nr_locks(hdr->max_tab_size) * sizeof(struct bucket_lock); - - return hdr->tabs_offset + (hdr->max_tab_size + hdr->max_lock_tab_size) * 4; -} - -struct __hash* __shm_hash_init(unsigned long shm_baddr, unsigned long shm_size) -{ - uint32_t i; - struct shm_hdr *hdr; - - /* Some sanity checks */ - hdr = (struct shm_hdr *)shm_baddr; - memset(hdr, 0, sizeof(struct shm_hdr)); - - /* Find the maximum number of entries we can store in the given shm_size */ - for(i=1; shm_init_offsets(hdr, i) < shm_size; i++){}; - shm_init_offsets(hdr, (i-1)); - - memset(get_shm_freelist(hdr), 0, - (hdr->nr_entries + 1) * sizeof(uint32_t)); - if(shm_mutex_init(hdr) != 0) - return NULL; - for(i=0; inr_entries; i++) - shm_add_to_freelist(hdr, i); - for(i=0; ifree_tab_slots[i] = 1; - - shm_mutex_lock(hdr); - assert(!hdr->hash_allocated); - hdr->hash_allocated = 1; - shm_mutex_unlock(hdr); - - return __hash_init(&hdr->hash, 1000); -} - -struct __hash* __shm_hash_get(unsigned long shm_baddr) -{ - struct shm_hdr *hdr = (struct shm_hdr *)shm_baddr; - - return (hdr->hash_allocated ? &hdr->hash : NULL); -} - -static void* alloc_entry(struct __hash *h, int size) -{ - struct shm_hdr *hdr = get_shm_hdr(h); - uint32_t slot = shm_get_from_freelist(hdr); - - assert(size == sizeof(struct hash_entry)); - if(slot == -1) - return NULL; - - return (get_shm_entries(hdr) + slot); -} - -static void alloc_buckets(struct __hash *h, - int nr_buckets, - struct bucket **buckets_tab, - struct bucket_lock **bucket_locks_tab) -{ - struct shm_hdr *hdr = get_shm_hdr(h); - int free_slot; - - *buckets_tab = NULL; - *bucket_locks_tab = NULL; - - if(((nr_buckets * sizeof(struct bucket)) > hdr->max_tab_size) || - ((nr_locks(nr_buckets) * sizeof(struct bucket_lock)) > - hdr->max_lock_tab_size)) - return; - - shm_mutex_lock(hdr); - for(free_slot=0; free_slotfree_tab_slots[free_slot]) - break; - if(free_slot == SHM_TABLE_SLOTS) - { - shm_mutex_unlock(hdr); - return; - } - hdr->free_tab_slots[free_slot] = 0; - shm_mutex_unlock(hdr); - *buckets_tab = get_shm_tab(hdr, free_slot); - *bucket_locks_tab = get_shm_lock_tab(hdr, free_slot); -} - -static void free_entry(struct __hash *h, void *p) -{ - struct shm_hdr *hdr = get_shm_hdr(h); - uint32_t slot; - - slot = ((uint32_t)((struct hash_entry *)p - - get_shm_entries(hdr))); - shm_add_to_freelist(hdr, slot); -} - -static void free_buckets(struct __hash *h, - struct bucket *buckets, - struct bucket_lock *bucket_locks) -{ - struct shm_hdr *hdr = get_shm_hdr(h); - int slot; - - if(!buckets || !bucket_locks) - { - assert(!buckets && !bucket_locks); - return; - } - slot = get_shm_slot(hdr, buckets); - assert(slot < SHM_TABLE_SLOTS); - assert((char *)bucket_locks == (char *)buckets + hdr->max_tab_size); - shm_mutex_lock(hdr); - assert(hdr->free_tab_slots[slot] == 0); - hdr->free_tab_slots[slot] = 1; - shm_mutex_unlock(hdr); -} - -static int max_entries(struct __hash *h) -{ - struct shm_hdr *hdr = get_shm_hdr(h); - - return hdr->nr_entries; -} - -#endif /* !BIDIR_USE_STDMALLOC */ - - -/* The structures may be stored in shared memory region, with base address */ -/* stored in shm_base_addr. All the pointers in the above structures need */ -/* to be relative to this base address (otherwise they would not make */ -/* sense to other processes). Bellow accessor functions are used to */ -/* convert between canonical (base address relative) and local addresses. */ -/* C2L stands for CANONICAL_TO_LOCAL, and vice versa */ -#define C2L(_h, _p) ((typeof(_p))((unsigned long)(_p) + \ - get_shm_baddr(_h))) -#define L2C(_h, _p) ((typeof(_p))((unsigned long)(_p) - \ - get_shm_baddr(_h))) - - -#define HASH_LOCK_INIT(_h) ({ \ - int _ret; \ - pthread_rwlockattr_t _attr; \ - \ - h->lock_alive = 1; \ - _ret = pthread_rwlockattr_init(&_attr); \ - if(_ret == 0) \ - _ret = pthread_rwlockattr_setpshared(&_attr, \ - PTHREAD_PROCESS_SHARED); \ - if(_ret == 0) \ - _ret = pthread_rwlock_init(&(_h)->hash_lock, &_attr); \ - if(_ret == 0) \ - _ret = pthread_rwlockattr_destroy(&_attr); \ - \ - _ret; \ -}) - -#define HASH_LOCK_RDLOCK(_h) ({ \ - int _ret; \ - \ - if(!_h->lock_alive) _ret = ENOLCK; \ - else \ - { \ - struct timespec _ts; \ - /* 10s timeout, long but ~matches disk spin-up times */ \ - _ts.tv_sec = time(NULL) + 10; \ - _ts.tv_nsec = 0; \ - _ret = pthread_rwlock_timedrdlock(&(_h)->hash_lock, &_ts); \ - if(_ret == ETIMEDOUT) _h->lock_alive = 0; \ - } \ - _ret; \ -}) - -#define HASH_LOCK_RDUNLOCK(_h) \ - pthread_rwlock_unlock(&(_h)->hash_lock) - -#define HASH_LOCK_WRLOCK(_h) ({ \ - int _ret; \ - \ - if(!_h->lock_alive) _ret = ENOLCK; \ - else \ - { \ - struct timespec _ts; \ - _ts.tv_sec = time(NULL) + 10; \ - _ts.tv_nsec = 0UL; \ - _ret = pthread_rwlock_timedwrlock(&(_h)->hash_lock, &_ts); \ - if(_ret == ETIMEDOUT) _h->lock_alive = 0; \ - } \ - _ret; \ -}) - -#define HASH_LOCK_TRYWRLOCK(_h) ({ \ - int _ret = (_h->lock_alive ? \ - pthread_rwlock_trywrlock(&(_h)->hash_lock) : \ - ENOLCK); \ - _ret; \ -}) - -#define HASH_LOCK_WRUNLOCK(_h) \ - pthread_rwlock_unlock(&(_h)->hash_lock) - - -#define BUCKET_LOCK_INIT(_h, _b) ({ \ - int _ret; \ - pthread_rwlockattr_t _attr; \ - \ - _ret = pthread_rwlockattr_init(&_attr); \ - if(_ret == 0) \ - _ret = pthread_rwlockattr_setpshared(&_attr, \ - PTHREAD_PROCESS_SHARED); \ - if(_ret == 0) \ - _ret = pthread_rwlock_init(&(_b)->bucket_lock, &_attr); \ - if(_ret == 0) \ - _ret = pthread_rwlockattr_destroy(&_attr); \ - \ - _ret; \ -}) - - -#define BUCKET_LOCK_RDLOCK(_h, _lock_tab, _idx) ({ \ - int _ret; \ - struct timespec _ts; \ - struct bucket_lock *_lock = &(_lock_tab)[(_idx) / BUCKETS_PER_LOCK]; \ - \ - _ts.tv_sec = time(NULL) + 10; \ - _ts.tv_nsec = 0; \ - _ret = pthread_rwlock_timedrdlock(&(_lock)->bucket_lock, &_ts); \ - if(_ret == ETIMEDOUT) (_h)->lock_alive = 0; \ - _ret; \ -}) - - -#define BUCKET_LOCK_RDUNLOCK(_h, _lock_tab, _idx) ({ \ - struct bucket_lock *_lock = &(_lock_tab)[(_idx) / BUCKETS_PER_LOCK]; \ - pthread_rwlock_unlock(&(_lock)->bucket_lock); \ -}) - -#define BUCKET_LOCK_WRLOCK(_h, _lock_tab, _idx) ({ \ - int _ret; \ - struct timespec _ts; \ - struct bucket_lock *_lock = &(_lock_tab)[(_idx) / BUCKETS_PER_LOCK]; \ - \ - _ts.tv_sec = time(NULL) + 10; \ - _ts.tv_nsec = 0; \ - _ret = pthread_rwlock_timedwrlock(&(_lock)->bucket_lock, &_ts); \ - if(_ret == ETIMEDOUT) (_h)->lock_alive = 0; \ - _ret; \ -}) - -#define BUCKET_LOCK_WRUNLOCK(_h, _lock_tab, _idx) ({ \ - struct bucket_lock *_lock = &(_lock_tab)[(_idx) / BUCKETS_PER_LOCK]; \ - pthread_rwlock_unlock(&(_lock)->bucket_lock); \ -}) - -#define TWO_BUCKETS_LOCK_WRLOCK(_h, _blt1, _idx1, _blt2, _idx2) ({ \ - int _ret; \ - pthread_rwlock_t *_l1, *_l2; \ - struct timespec _ts; \ - struct bucket_lock *_bl1 = &(_blt1)[(_idx1) / BUCKETS_PER_LOCK]; \ - struct bucket_lock *_bl2 = &(_blt2)[(_idx2) / BUCKETS_PER_LOCK]; \ - \ - assert((_bl1) != (_bl2)); \ - if((_bl1) < (_bl2)) \ - { \ - _l1 = &(_bl1)->bucket_lock; \ - _l2 = &(_bl2)->bucket_lock; \ - } \ - else \ - { \ - _l1 = &(_bl2)->bucket_lock; \ - _l2 = &(_bl1)->bucket_lock; \ - } \ - _ts.tv_sec = time(NULL) + 10; \ - _ts.tv_nsec = 0; \ - _ret = pthread_rwlock_timedwrlock(_l1, &_ts); \ - _ts.tv_sec = time(NULL) + 10; \ - _ts.tv_nsec = 0; \ - if(_ret == 0) \ - _ret = pthread_rwlock_timedwrlock(_l2, &_ts); \ - if(_ret == ETIMEDOUT) (_h)->lock_alive = 0; \ - \ - _ret; \ -}) - -#define TWO_BUCKETS_LOCK_WRUNLOCK(_h, _blt1, _idx1, _blt2, _idx2) ({ \ - int _ret; \ - struct bucket_lock *_bl1 = &(_blt1)[(_idx1) / BUCKETS_PER_LOCK]; \ - struct bucket_lock *_bl2 = &(_blt2)[(_idx2) / BUCKETS_PER_LOCK]; \ - \ - _ret = pthread_rwlock_unlock(&(_bl1)->bucket_lock); \ - if(_ret == 0) \ - _ret = pthread_rwlock_unlock(&(_bl2)->bucket_lock); \ - \ - _ret; \ -}) - - - - -static uint32_t hash_to_idx(struct __hash *h, uint32_t hash) -{ - return (hash % h->tab_size); -} - -static void alloc_tab(struct __hash *h, - int size, - struct bucket **buckets_tab, - struct bucket_lock **bucket_locks_tab) -{ - int i; - - alloc_buckets(h, size, buckets_tab, bucket_locks_tab); - if(!(*buckets_tab) || !(*bucket_locks_tab)) - goto error_out; - memset(*buckets_tab, 0, size * sizeof(struct bucket)); - memset(*bucket_locks_tab, 0, nr_locks(size) * sizeof(struct bucket_lock)); - for(i=0; i hash_sizes[hash_sizes_len-1]) return NULL; - /* Find least size greater than init_size */ - for(size_idx = 0; size_idx < hash_sizes_len; size_idx++) - if(hash_sizes[size_idx] >= min_size) - break; - size = hash_sizes[size_idx]; - - if(!h) return NULL; - alloc_tab(h, size, &buckets, &bucket_locks); - if(!buckets || !bucket_locks) goto alloc_fail; - h->key_tab = L2C(h, buckets); - h->key_lock_tab = L2C(h, bucket_locks); - alloc_tab(h, size, &buckets, &bucket_locks); - if(!buckets || !bucket_locks) goto alloc_fail; - h->value_tab = L2C(h, buckets); - h->value_lock_tab = L2C(h, bucket_locks); - /* Init all h variables */ - if(HASH_LOCK_INIT(h) != 0) goto alloc_fail; - h->nr_ent = 0; - h->tab_size = size; - h->size_idx = size_idx; - h->max_load = (uint32_t)ceilf(hash_max_load_fact * size); - h->min_load = (uint32_t)ceilf(hash_min_load_fact * size); - - return h; - -alloc_fail: - if(h->key_tab || h->key_lock_tab) - free_buckets(h, C2L(h, h->key_tab), C2L(h, h->key_lock_tab)); - return NULL; -} - -#undef __prim -#undef __prim_t -#undef __prim_tab -#undef __prim_lock_tab -#undef __prim_hash -#undef __prim_cmp -#undef __prim_next -#undef __sec -#undef __sec_t - -#define __prim key -#define __prim_t __k_t -#define __prim_tab key_tab -#define __prim_lock_tab key_lock_tab -#define __prim_hash __key_hash -#define __prim_cmp __key_cmp -#define __prim_next key_next -#define __sec value -#define __sec_t __v_t -int __key_lookup(struct __hash *h, __prim_t k, __sec_t *vp) -{ - struct hash_entry *entry; - struct bucket *b; - struct bucket_lock *blt; - uint32_t idx; - - if(HASH_LOCK_RDLOCK(h) != 0) return -ENOLCK; - idx = hash_to_idx(h, __prim_hash(k)); - b = C2L(h, &h->__prim_tab[idx]); - blt = C2L(h, h->__prim_lock_tab); - if(BUCKET_LOCK_RDLOCK(h, blt, idx) != 0) return -ENOLCK; - entry = b->hash_entry; - while(entry != NULL) - { - entry = C2L(h, entry); - if(__prim_cmp(k, entry->__prim)) - { - /* Unlock here */ - *vp = entry->__sec; - BUCKET_LOCK_RDUNLOCK(h, blt, idx); - HASH_LOCK_RDUNLOCK(h); - return 1; - } - entry = entry->__prim_next; - } - BUCKET_LOCK_RDUNLOCK(h, blt, idx); - HASH_LOCK_RDUNLOCK(h); - return 0; -} - -/* value lookup is an almost exact copy of key lookup */ -#undef __prim -#undef __prim_t -#undef __prim_tab -#undef __prim_lock_tab -#undef __prim_hash -#undef __prim_cmp -#undef __prim_next -#undef __sec -#undef __sec_t - -#define __prim value -#define __prim_t __v_t -#define __prim_tab value_tab -#define __prim_lock_tab value_lock_tab -#define __prim_hash __value_hash -#define __prim_cmp __value_cmp -#define __prim_next value_next -#define __sec key -#define __sec_t __k_t -int __value_lookup(struct __hash *h, __prim_t k, __sec_t *vp) -{ - struct hash_entry *entry; - struct bucket *b; - struct bucket_lock *blt; - uint32_t idx; - - if(HASH_LOCK_RDLOCK(h) != 0) return -ENOLCK; - idx = hash_to_idx(h, __prim_hash(k)); - b = C2L(h, &h->__prim_tab[idx]); - blt = C2L(h, h->__prim_lock_tab); - if(BUCKET_LOCK_RDLOCK(h, blt, idx) != 0) return -ENOLCK; - entry = b->hash_entry; - while(entry != NULL) - { - entry = C2L(h, entry); - if(__prim_cmp(k, entry->__prim)) - { - /* Unlock here */ - *vp = entry->__sec; - BUCKET_LOCK_RDUNLOCK(h, blt, idx); - HASH_LOCK_RDUNLOCK(h); - return 1; - } - entry = entry->__prim_next; - } - BUCKET_LOCK_RDUNLOCK(h, blt, idx); - HASH_LOCK_RDUNLOCK(h); - return 0; -} - -int __insert(struct __hash *h, __k_t k, __v_t v) -{ - uint32_t k_idx, v_idx; - struct hash_entry *entry; - struct bucket *bk, *bv; - struct bucket_lock *bltk, *bltv; - - /* Allocate new entry before any locks (in case it fails) */ - entry = (struct hash_entry*) - alloc_entry(h, sizeof(struct hash_entry)); - if(!entry) return 0; - - if(HASH_LOCK_RDLOCK(h) != 0) return -ENOLCK; - /* Read from nr_ent is atomic(TODO check), no need for fancy accessors */ - if(h->nr_ent+1 > h->max_load) - { - /* Resize needs the write lock, drop read lock temporarily */ - HASH_LOCK_RDUNLOCK(h); - hash_resize(h); - if(HASH_LOCK_RDLOCK(h) != 0) return -ENOLCK; - } - - /* Init the entry */ - entry->key = k; - entry->value = v; - - /* Work out the indicies */ - k_idx = hash_to_idx(h, __key_hash(k)); - v_idx = hash_to_idx(h, __value_hash(v)); - - /* Insert */ - bk = C2L(h, &h->key_tab[k_idx]); - bv = C2L(h, &h->value_tab[v_idx]); - bltk = C2L(h, h->key_lock_tab); - bltv = C2L(h, h->value_lock_tab); - if(TWO_BUCKETS_LOCK_WRLOCK(h, bltk, k_idx, bltv, v_idx) != 0) - return -ENOLCK; - entry->key_next = bk->hash_entry; - bk->hash_entry = L2C(h, entry); - entry->value_next = bv->hash_entry; - bv->hash_entry = L2C(h, entry); - TWO_BUCKETS_LOCK_WRUNLOCK(h, bltk, k_idx, bltv, v_idx); - - /* Book keeping */ - atomic_inc(&h->nr_ent); - - HASH_LOCK_RDUNLOCK(h); - - return 1; -} - - -#undef __prim -#undef __prim_t -#undef __prim_tab -#undef __prim_lock_tab -#undef __prim_hash -#undef __prim_cmp -#undef __prim_next -#undef __sec -#undef __sec_t -#undef __sec_tab -#undef __sec_lock_tab -#undef __sec_hash -#undef __sec_next - -#define __prim key -#define __prim_t __k_t -#define __prim_tab key_tab -#define __prim_lock_tab key_lock_tab -#define __prim_hash __key_hash -#define __prim_cmp __key_cmp -#define __prim_next key_next -#define __sec value -#define __sec_t __v_t -#define __sec_tab value_tab -#define __sec_lock_tab value_lock_tab -#define __sec_hash __value_hash -#define __sec_next value_next - -int __key_remove(struct __hash *h, __prim_t k, __sec_t *vp) -{ - struct hash_entry *e, *es, **pek, **pev; - struct bucket *bk, *bv; - struct bucket_lock *bltk, *bltv; - uint32_t old_kidx, kidx, vidx, min_load, nr_ent; - __prim_t ks; - __sec_t vs; - - if(HASH_LOCK_RDLOCK(h) != 0) return -ENOLCK; - -again: - old_kidx = kidx = hash_to_idx(h, __prim_hash(k)); - bk = C2L(h, &h->__prim_tab[kidx]); - bltk = C2L(h, h->__prim_lock_tab); - if(BUCKET_LOCK_RDLOCK(h, bltk, kidx) != 0) return -ENOLCK; - pek = &(bk->hash_entry); - e = *pek; - while(e != NULL) - { - e = C2L(h, e); - if(__prim_cmp(k, e->__prim)) - { - goto found; - } - pek = &(e->__prim_next); - e = *pek; - } - - BUCKET_LOCK_RDUNLOCK(h, bltk, kidx); - HASH_LOCK_RDUNLOCK(h); - - return 0; - -found: - /* - * Make local copy of key and value. - */ - es = e; - ks = e->__prim; - vs = e->__sec; - kidx = hash_to_idx(h, __prim_hash(ks)); - /* Being paranoid: check if kidx has not changed, so that we unlock the - * right bucket */ - assert(old_kidx == kidx); - vidx = hash_to_idx(h, __sec_hash(vs)); - bk = C2L(h, &h->__prim_tab[kidx]); - bv = C2L(h, &h->__sec_tab[vidx]); - bltk = C2L(h, h->__prim_lock_tab); - bltv = C2L(h, h->__sec_lock_tab); - BUCKET_LOCK_RDUNLOCK(h, bltk, kidx); - if(TWO_BUCKETS_LOCK_WRLOCK(h, bltk, kidx, bltv, vidx) != 0) return -ENOLCK; - pek = &(bk->hash_entry); - pev = &(bv->hash_entry); - - /* Find the entry in both tables */ - e = *pek; - while(e != NULL) - { - e = C2L(h, e); - if(e == es) - { - /* Being paranoid: make sure that the key and value are - * still the same. This is still not 100%, because, in - * principle, the entry could have got deleted, when we - * didn't hold the locks for a little while, and exactly - * the same entry reinserted. If the __k_t & __v_t are - * simple types than it probably doesn't matter, but if - * either is a pointer type, the actual structure might - * now be different. The chances that happens are very - * slim, but still, if that's a problem, the user needs to - * pay attention to the structure re-allocation */ - if((memcmp(&(e->__prim), &ks, sizeof(__prim_t))) || - (memcmp(&(e->__sec), &vs, sizeof(__sec_t)))) - break; - goto found_again; - } - pek = &(e->__prim_next); - e = *pek; - } - - TWO_BUCKETS_LOCK_WRUNLOCK(h, bltk, kidx, bltv, vidx); - - /* Entry got removed in the meantime, try again */ - goto again; - -found_again: - /* We are now comitted to the removal */ - e = *pev; - while(e != NULL) - { - e = C2L(h, e); - if(e == es) - { - /* Both pek and pev are pointing to the right place, remove */ - *pek = e->__prim_next; - *pev = e->__sec_next; - - atomic_dec(&h->nr_ent); - nr_ent = h->nr_ent; - /* read min_load still under the hash lock! */ - min_load = h->min_load; - - TWO_BUCKETS_LOCK_WRUNLOCK(h, bltk, kidx, bltv, vidx); - HASH_LOCK_RDUNLOCK(h); - - if(nr_ent < min_load) - hash_resize(h); - if(vp != NULL) - *vp = e->__sec; - free_entry(h, e); - return 1; - } - pev = &(e->__sec_next); - e = *pev; - } - - /* We should never get here!, no need to unlock anything */ - return -ENOLCK; -} - -#undef __prim -#undef __prim_t -#undef __prim_tab -#undef __prim_lock_tab -#undef __prim_hash -#undef __prim_cmp -#undef __prim_next -#undef __sec -#undef __sec_t -#undef __sec_tab -#undef __sec_lock_tab -#undef __sec_hash -#undef __sec_next - -#define __prim value -#define __prim_t __v_t -#define __prim_tab value_tab -#define __prim_lock_tab value_lock_tab -#define __prim_hash __value_hash -#define __prim_cmp __value_cmp -#define __prim_next value_next -#define __sec key -#define __sec_t __k_t -#define __sec_tab key_tab -#define __sec_lock_tab key_lock_tab -#define __sec_hash __key_hash -#define __sec_next key_next - -int __value_remove(struct __hash *h, __prim_t k, __sec_t *vp) -{ - struct hash_entry *e, *es, **pek, **pev; - struct bucket *bk, *bv; - struct bucket_lock *bltk, *bltv; - uint32_t old_kidx, kidx, vidx, min_load, nr_ent; - __prim_t ks; - __sec_t vs; - - if(HASH_LOCK_RDLOCK(h) != 0) return -ENOLCK; - -again: - old_kidx = kidx = hash_to_idx(h, __prim_hash(k)); - bk = C2L(h, &h->__prim_tab[kidx]); - bltk = C2L(h, h->__prim_lock_tab); - if(BUCKET_LOCK_RDLOCK(h, bltk, kidx) != 0) return -ENOLCK; - pek = &(bk->hash_entry); - e = *pek; - while(e != NULL) - { - e = C2L(h, e); - if(__prim_cmp(k, e->__prim)) - { - goto found; - } - pek = &(e->__prim_next); - e = *pek; - } - - BUCKET_LOCK_RDUNLOCK(h, bltk, kidx); - HASH_LOCK_RDUNLOCK(h); - - return 0; - -found: - /* - * Make local copy of key and value. - */ - es = e; - ks = e->__prim; - vs = e->__sec; - kidx = hash_to_idx(h, __prim_hash(ks)); - /* Being paranoid: check if kidx has not changed, so that we unlock the - * right bucket */ - assert(old_kidx == kidx); - vidx = hash_to_idx(h, __sec_hash(vs)); - bk = C2L(h, &h->__prim_tab[kidx]); - bv = C2L(h, &h->__sec_tab[vidx]); - bltk = C2L(h, h->__prim_lock_tab); - bltv = C2L(h, h->__sec_lock_tab); - BUCKET_LOCK_RDUNLOCK(h, bltk, kidx); - if(TWO_BUCKETS_LOCK_WRLOCK(h, bltk, kidx, bltv, vidx) != 0) return -ENOLCK; - pek = &(bk->hash_entry); - pev = &(bv->hash_entry); - - /* Find the entry in both tables */ - e = *pek; - while(e != NULL) - { - e = C2L(h, e); - if(e == es) - { - /* Being paranoid: make sure that the key and value are - * still the same. This is still not 100%, because, in - * principle, the entry could have got deleted, when we - * didn't hold the locks for a little while, and exactly - * the same entry reinserted. If the __k_t & __v_t are - * simple types than it probably doesn't matter, but if - * either is a pointer type, the actual structure might - * now be different. The chances that happens are very - * slim, but still, if that's a problem, the user needs to - * pay attention to the structure re-allocation */ - if((memcmp(&(e->__prim), &ks, sizeof(__prim_t))) || - (memcmp(&(e->__sec), &vs, sizeof(__sec_t)))) - break; - goto found_again; - } - pek = &(e->__prim_next); - e = *pek; - } - - TWO_BUCKETS_LOCK_WRUNLOCK(h, bltk, kidx, bltv, vidx); - - /* Entry got removed in the meantime, try again */ - goto again; - -found_again: - /* We are now comitted to the removal */ - e = *pev; - while(e != NULL) - { - e = C2L(h, e); - if(e == es) - { - /* Both pek and pev are pointing to the right place, remove */ - *pek = e->__prim_next; - *pev = e->__sec_next; - - atomic_dec(&h->nr_ent); - nr_ent = h->nr_ent; - /* read min_load still under the hash lock! */ - min_load = h->min_load; - - TWO_BUCKETS_LOCK_WRUNLOCK(h, bltk, kidx, bltv, vidx); - HASH_LOCK_RDUNLOCK(h); - - if(nr_ent < min_load) - hash_resize(h); - if(vp != NULL) - *vp = e->__sec; - free_entry(h, e); - return 1; - } - pev = &(e->__sec_next); - e = *pev; - } - - /* We should never get here!, no need to unlock anything */ - return -ENOLCK; -} - - -int __hash_destroy(struct __hash *h, - void (*entry_consumer)(__k_t k, __v_t v, void *p), - void *d) -{ - struct hash_entry *e, *n; - struct bucket *b; - int i; - - if(HASH_LOCK_WRLOCK(h) != 0) return -ENOLCK; - - /* No need to lock individual buckets, with hash write lock */ - for(i=0; i < h->tab_size; i++) - { - b = C2L(h, &h->key_tab[i]); - e = b->hash_entry; - while(e != NULL) - { - e = C2L(h, e); - n = e->key_next; - if(entry_consumer) - entry_consumer(e->key, e->value, d); - free_entry(h, e); - e = n; - } - } - free_buckets(h, C2L(h, h->key_tab), C2L(h, h->key_lock_tab)); - free_buckets(h, C2L(h, h->value_tab), C2L(h, h->value_lock_tab)); - - HASH_LOCK_WRUNLOCK(h); - h->lock_alive = 0; - - return 0; -} - -static void hash_resize(struct __hash *h) -{ - int new_size_idx, i, lock_ret; - uint32_t size, old_size, kidx, vidx; - struct bucket *t1, *t2, *b; - struct bucket_lock *l1, *l2; - struct hash_entry *e, *n; - - /* We may fail to allocate the lock, if the resize is triggered while - we are iterating (under read lock) */ - lock_ret = HASH_LOCK_TRYWRLOCK(h); - if(lock_ret != 0) return; - - new_size_idx = h->size_idx; - /* Work out the new size */ - if(h->nr_ent >= h->max_load) - new_size_idx = h->size_idx+1; - if(h->nr_ent < h->min_load) - new_size_idx = h->size_idx-1; - if((new_size_idx == h->size_idx) || - (new_size_idx >= hash_sizes_len) || - (new_size_idx < 0)) - { - HASH_LOCK_WRUNLOCK(h); - return; - } - - size = hash_sizes[new_size_idx]; - - /* Allocate the new sizes */ - t1 = t2 = NULL; - l1 = l2 = NULL; - alloc_tab(h, size, &t1, &l1); - if(!t1 || !l1) goto alloc_fail; - alloc_tab(h, size, &t2, &l2); - if(!t2 || !l2) goto alloc_fail; - - old_size = h->tab_size; - h->tab_size = size; - h->size_idx = new_size_idx; - h->max_load = (uint32_t)ceilf(hash_max_load_fact * size); - h->min_load = (uint32_t)ceilf(hash_min_load_fact * size); - - /* Move the entries */ - for(i=0; i < old_size; i++) - { - b = C2L(h, &h->key_tab[i]); - e = b->hash_entry; - while(e != NULL) - { - e = C2L(h, e); - n = e->key_next; - kidx =hash_to_idx(h, __key_hash(e->key)); - vidx =hash_to_idx(h, __value_hash(e->value)); - /* Move to the correct bucket */ - e->key_next = t1[kidx].hash_entry; - t1[kidx].hash_entry = L2C(h, e); - e->value_next = t2[vidx].hash_entry; - t2[vidx].hash_entry = L2C(h, e); - e = n; - } - } - free_buckets(h, C2L(h, h->key_tab), C2L(h, h->key_lock_tab)); - free_buckets(h, C2L(h, h->value_tab), C2L(h, h->value_lock_tab)); - h->key_tab = L2C(h, t1); - h->key_lock_tab = L2C(h, l1); - h->value_tab = L2C(h, t2); - h->value_lock_tab = L2C(h, l2); - - HASH_LOCK_WRUNLOCK(h); - - return; - -alloc_fail: - /* If we failed to resize, adjust max/min load. This will stop us from - * retrying resize too frequently */ - if(new_size_idx > h->size_idx) - h->max_load = (h->max_load + 2 * h->tab_size) / 2 + 1; - else - if (new_size_idx < h->size_idx) - h->min_load = h->min_load / 2; - HASH_LOCK_WRUNLOCK(h); - if(t1 || l1) free_buckets(h, t1, l1); - if(t2 || l2) free_buckets(h, t2, l2); - return; -} - -int __hash_iterator(struct __hash *h, - int (*entry_consumer)(__k_t k, __v_t v, void *p), - void *d) -{ - struct hash_entry *e, *n; - struct bucket *b; - struct bucket_lock *blt; - int i, brk_early; - - if(HASH_LOCK_RDLOCK(h) != 0) return -ENOLCK; - - for(i=0; i < h->tab_size; i++) - { - b = C2L(h, &h->key_tab[i]); - blt = C2L(h, h->key_lock_tab); - if(BUCKET_LOCK_RDLOCK(h, blt, i) != 0) return -ENOLCK; - e = b->hash_entry; - while(e != NULL) - { - e = C2L(h, e); - n = e->key_next; - brk_early = entry_consumer(e->key, e->value, d); - if(brk_early) - { - BUCKET_LOCK_RDUNLOCK(h, blt, i); - goto out; - } - e = n; - } - BUCKET_LOCK_RDUNLOCK(h, blt, i); - } -out: - HASH_LOCK_RDUNLOCK(h); - return 0; -} - -void __hash_sizes(struct __hash *h, - uint32_t *nr_ent, - uint32_t *max_nr_ent, - uint32_t *tab_size, - uint32_t *max_load, - uint32_t *min_load) -{ - if(nr_ent != NULL) *nr_ent = h->nr_ent; - if(max_nr_ent != NULL) *max_nr_ent = max_entries(h); - if(tab_size != NULL) *tab_size = h->tab_size; - if(max_load != NULL) *max_load = h->max_load; - if(min_load != NULL) *min_load = h->min_load; -} - diff --git a/tools/memshr/bidir-hash.h b/tools/memshr/bidir-hash.h deleted file mode 100644 index d32c8e4781..0000000000 --- a/tools/memshr/bidir-hash.h +++ /dev/null @@ -1,114 +0,0 @@ -/****************************************************************************** - * - * Copyright (c) 2009 Citrix Systems, Inc. (Grzegorz Milos) - * - * 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; either version 2 of the License, or - * (at your option) any 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; If not, see . - */ -#ifndef __BIDIR_HASH_H__ -#define __BIDIR_HASH_H__ - -#include -#include -#include "memshr-priv.h" - -typedef struct vbdblk { - uint64_t sec; - uint16_t disk_id; -} vbdblk_t; - - -#if defined FINGERPRINT_MAP || BLOCK_MAP -#define DEFINE_SINGLE_MAP -#endif - -/*******************************************************/ -/* Fingerprint map */ -/*******************************************************/ -#if defined FINGERPRINT_MAP || !defined DEFINE_SINGLE_MAP - -#undef BIDIR_NAME_PREFIX -#undef BIDIR_KEY -#undef BIDIR_VALUE -#undef BIDIR_KEY_T -#undef BIDIR_VALUE_T -static uint32_t fgprtshr_fgprt_hash(uint32_t h) -{ - return h; -} - -static uint32_t fgprtshr_mfn_hash(uint64_t m) -{ - return (uint32_t)m; -} - -static int fgprtshr_fgprt_cmp(uint32_t h1, uint32_t h2) -{ - return (h1 == h2); -} - -static int fgprtshr_mfn_cmp(uint32_t m1, uint32_t m2) -{ - return (m1 == m2); -} -#define BIDIR_NAME_PREFIX fgprtshr -#define BIDIR_KEY fgprt -#define BIDIR_VALUE mfn -#define BIDIR_KEY_T uint32_t -#define BIDIR_VALUE_T xen_mfn_t -#include "bidir-namedefs.h" - -#endif /* FINGERPRINT_MAP */ - - -/*******************************************************/ -/* Block<->Memory sharing handles */ -/*******************************************************/ -#if defined BLOCK_MAP || !defined DEFINE_SINGLE_MAP - -#undef BIDIR_NAME_PREFIX -#undef BIDIR_KEY -#undef BIDIR_VALUE -#undef BIDIR_KEY_T -#undef BIDIR_VALUE_T - -/* TODO better hashes! */ -static inline uint32_t blockshr_block_hash(vbdblk_t block) -{ - return (uint32_t)(block.sec) ^ (uint32_t)(block.disk_id); -} - -static inline uint32_t blockshr_shrhnd_hash(share_tuple_t shrhnd) -{ - return ((uint32_t) shrhnd.handle); -} - -static inline int blockshr_block_cmp(vbdblk_t b1, vbdblk_t b2) -{ - return (b1.sec == b2.sec) && (b1.disk_id == b2.disk_id); -} - -static inline int blockshr_shrhnd_cmp(share_tuple_t h1, share_tuple_t h2) -{ - return ( !memcmp(&h1, &h2, sizeof(share_tuple_t)) ); -} -#define BIDIR_NAME_PREFIX blockshr -#define BIDIR_KEY block -#define BIDIR_VALUE shrhnd -#define BIDIR_KEY_T vbdblk_t -#define BIDIR_VALUE_T share_tuple_t -#include "bidir-namedefs.h" - -#endif /* BLOCK_MAP */ - -#endif /* __BIDIR_HASH_H__ */ diff --git a/tools/memshr/bidir-namedefs.h b/tools/memshr/bidir-namedefs.h deleted file mode 100644 index 6ab4b3de8c..0000000000 --- a/tools/memshr/bidir-namedefs.h +++ /dev/null @@ -1,79 +0,0 @@ -/****************************************************************************** - * - * Copyright (c) 2009 Citrix Systems, Inc. (Grzegorz Milos) - * - * 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; either version 2 of the License, or - * (at your option) any 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; If not, see . - */ -#include "memshr-priv.h" - -/* Macros used to assemble the names */ -#define BIDIR_NAME_ONE_INTERNAL(prefix, name) \ - prefix ## _ ## name -#define BIDIR_NAME_TWO_INTERNAL(prefix, name1, name2) \ - prefix ## _ ## name1 ## _ ## name2 - -#define BIDIR_NAME_ONE(prefix, name) \ - BIDIR_NAME_ONE_INTERNAL(prefix, name) -#define BIDIR_NAME_TWO(prefix, name1, name2) \ - BIDIR_NAME_TWO_INTERNAL(prefix, name1, name2) - -#define INTERNAL_NAME_ONE(name) BIDIR_NAME_ONE(BIDIR_NAME_PREFIX, name) -#define INTERNAL_NAME_TWO(name1, name2) \ - BIDIR_NAME_TWO(BIDIR_NAME_PREFIX, name1, name2) - -/* Function/type names */ -#define __k_t BIDIR_KEY_T -#define __v_t BIDIR_VALUE_T - -#define __hash INTERNAL_NAME_ONE(hash) -#define __shm_hash_init INTERNAL_NAME_ONE(shm_hash_init) -#define __shm_hash_get INTERNAL_NAME_ONE(shm_hash_get) -#define __hash_init INTERNAL_NAME_ONE(hash_init) -#define __key_lookup INTERNAL_NAME_TWO(BIDIR_KEY, lookup) -#define __value_lookup INTERNAL_NAME_TWO(BIDIR_VALUE, lookup) -#define __insert INTERNAL_NAME_ONE(insert) -#define __key_remove INTERNAL_NAME_TWO(BIDIR_KEY, remove) -#define __value_remove INTERNAL_NAME_TWO(BIDIR_VALUE, remove) -#define __hash_destroy INTERNAL_NAME_ONE(hash_destroy) -#define __hash_iterator INTERNAL_NAME_ONE(hash_iterator) - -#define __key_hash INTERNAL_NAME_TWO(BIDIR_KEY, hash) -#define __key_cmp INTERNAL_NAME_TWO(BIDIR_KEY, cmp) -#define __value_hash INTERNAL_NAME_TWO(BIDIR_VALUE, hash) -#define __value_cmp INTERNAL_NAME_TWO(BIDIR_VALUE, cmp) - -#define __hash_sizes INTERNAL_NAME_ONE(hash_sizes) - - -/* Final function exports */ -struct __hash* __shm_hash_init(unsigned long shm_baddr, unsigned long shm_size); -struct __hash* __shm_hash_get(unsigned long shm_baddr); -struct __hash *__hash_init (struct __hash *h, uint32_t min_size); -int __key_lookup (struct __hash *h, __k_t k, __v_t *vp); -int __value_lookup(struct __hash *h, __v_t v, __k_t *kp); -int __insert (struct __hash *h, __k_t k, __v_t v); -int __key_remove (struct __hash *h, __k_t k, __v_t *vp); -int __value_remove(struct __hash *h, __v_t v, __k_t *kp); -int __hash_destroy(struct __hash *h, - void (*entry_consumer)(__k_t k, __v_t v, void *p), - void *d); -int __hash_iterator(struct __hash *h, - int (*entry_consumer)(__k_t k, __v_t v, void *p), - void *d); -void __hash_sizes(struct __hash *h, - uint32_t *nr_ent, - uint32_t *max_nr_ent, - uint32_t *tab_size, - uint32_t *max_load, - uint32_t *min_load); diff --git a/tools/memshr/interface.c b/tools/memshr/interface.c deleted file mode 100644 index ba43c3de66..0000000000 --- a/tools/memshr/interface.c +++ /dev/null @@ -1,224 +0,0 @@ -/****************************************************************************** - * - * Copyright (c) 2009 Citrix Systems, Inc. (Grzegorz Milos) - * - * 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; either version 2 of the License, or - * (at your option) any 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; If not, see . - */ -#include -#include - -#include "memshr.h" -#include "memshr-priv.h" -#include "bidir-hash.h" -#include "shm.h" -#include "bidir-daemon.h" - -typedef struct { - int enabled; - domid_t domid; - xc_interface *xc_handle; -} memshr_vbd_info_t; - -memshr_vbd_info_t vbd_info = {0, DOMID_INVALID}; - - -typedef struct { - struct shared_memshr_info *shared_info; - struct fgprtshr_hash *fgprts; - struct blockshr_hash *blks; -} private_memshr_info_t; - -private_memshr_info_t memshr; - -#define SHARED_INFO (memshr.shared_info) - -void memshr_set_domid(int domid) -{ - vbd_info.domid = domid; -} - -void memshr_daemon_initialize(void) -{ - void *shm_base_addr; - struct fgprtshr_hash *h; - - memset(&memshr, 0, sizeof(private_memshr_info_t)); - - if((SHARED_INFO = shm_shared_info_open(1)) == NULL) - { - DPRINTF("Failed to init shared info.\n"); - return; - } - - if((memshr.fgprts = shm_fgprtshr_hash_open(1)) == NULL) - { - DPRINTF("Failed to init fgprtshr hash.\n"); - return; - } - memshr.shared_info->fgprtshr_hash_inited = 1; - - if((memshr.blks = shm_blockshr_hash_open(1)) == NULL) - { - DPRINTF("Failed to init blockshr hash.\n"); - return; - } - memshr.shared_info->blockshr_hash_inited = 1; - - bidir_daemon_initialize(memshr.blks); -} - - -void memshr_vbd_initialize(void) -{ - xc_interface *xc_handle; - - memset(&memshr, 0, sizeof(private_memshr_info_t)); - - if((SHARED_INFO = shm_shared_info_open(0)) == NULL) - { - DPRINTF("Failed to open shared info.\n"); - return; - } - - if(!SHARED_INFO->fgprtshr_hash_inited) - { - DPRINTF("fgprtshr hash not inited.\n"); - return; - } - - if((memshr.fgprts = shm_fgprtshr_hash_open(0)) == NULL) - { - DPRINTF("Failed to open fgprtshr_hash.\n"); - return; - } - - if((memshr.blks = shm_blockshr_hash_open(0)) == NULL) - { - DPRINTF("Failed to open blockshr_hash.\n"); - return; - } - - if(vbd_info.domid == DOMID_INVALID) - return; - - if((xc_handle = xc_interface_open(0,0,0)) == 0) - { - DPRINTF("Failed to open XC interface.\n"); - return; - } - - vbd_info.xc_handle = xc_handle; - vbd_info.enabled = 1; -} - -uint16_t memshr_vbd_image_get(const char* file) -{ - uint16_t id; - - if(pthread_mutex_lock(&SHARED_INFO->lock)) goto error_out; - id = shm_vbd_image_get(file, SHARED_INFO->vbd_images); - if(pthread_mutex_unlock(&SHARED_INFO->lock)) goto error_out; - - return id; -error_out: - return 0; -} - -void memshr_vbd_image_put(uint16_t memshr_id) -{ - if(pthread_mutex_lock(&SHARED_INFO->lock)) return; - shm_vbd_image_put(memshr_id, SHARED_INFO->vbd_images); - if(pthread_mutex_unlock(&SHARED_INFO->lock)) return; -} - -int memshr_vbd_issue_ro_request(char *buf, - grant_ref_t gref, - uint16_t file_id, - uint64_t sec, - int secs, - share_tuple_t *hnd) -{ - vbdblk_t blk; - share_tuple_t source_st, client_st; - uint64_t c_hnd; - int ret; - - *hnd = (share_tuple_t){ 0, 0, 0 }; - if(!vbd_info.enabled) - return -1; - - if(secs != 8) - return -2; - - /* Nominate the granted page for sharing */ - ret = xc_memshr_nominate_gref(vbd_info.xc_handle, - vbd_info.domid, - gref, - &c_hnd); - /* If page couldn't be made sharable, we cannot do anything about it */ - if(ret != 0) - return -3; - - client_st = (share_tuple_t){ vbd_info.domid, gref, c_hnd }; - *hnd = client_st; - - /* Check if we've read matching disk block previously */ - blk.sec = sec; - blk.disk_id = file_id; - if(blockshr_block_lookup(memshr.blks, blk, &source_st) > 0) - { - ret = xc_memshr_share_grefs(vbd_info.xc_handle, source_st.domain, source_st.frame, - source_st.handle, vbd_info.domid, gref, c_hnd); - if(!ret) return 0; - /* Handles failed to be shared => at least one of them must be invalid, - remove the relevant ones from the map */ - switch(ret) - { - case XENMEM_SHARING_OP_S_HANDLE_INVALID: - ret = blockshr_shrhnd_remove(memshr.blks, source_st, NULL); - if(ret) DPRINTF("Could not rm invl s_hnd: %u %"PRId64" %"PRId64"\n", - source_st.domain, source_st.frame, source_st.handle); - break; - case XENMEM_SHARING_OP_C_HANDLE_INVALID: - ret = blockshr_shrhnd_remove(memshr.blks, client_st, NULL); - if(ret) DPRINTF("Could not rm invl c_hnd: %u %"PRId64" %"PRId64"\n", - client_st.domain, client_st.frame, client_st.handle); - break; - default: - break; - } - return -5; - } - - return -4; -} - -void memshr_vbd_complete_ro_request(share_tuple_t hnd, - uint16_t file_id, - uint64_t sec, - int secs) -{ - vbdblk_t blk; - - if(!vbd_info.enabled) - return; - - if(secs != 8) - return; - - blk.sec = sec; - blk.disk_id = file_id; - if(blockshr_insert(memshr.blks, blk, hnd) < 0) - DPRINTF("Could not insert block hint into hash.\n"); -} diff --git a/tools/memshr/memshr-priv.h b/tools/memshr/memshr-priv.h deleted file mode 100644 index f2c3f1f91d..0000000000 --- a/tools/memshr/memshr-priv.h +++ /dev/null @@ -1,33 +0,0 @@ -/****************************************************************************** - * - * Copyright (c) 2009 Citrix Systems, Inc. (Grzegorz Milos) - * - * 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; either version 2 of the License, or - * (at your option) any 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; If not, see . - */ -#ifndef __MEMSHR_PRIV_H__ -#define __MEMSHR_PRIV_H__ - -#include -#include -#include "memshr.h" - -#if 1 -#define DPRINTF(_f, _a...) syslog(LOG_INFO, _f, ##_a) -#else -#define DPRINTF(_f, _a...) ((void)0) -#endif - -#define EPRINTF(_f, _a...) syslog(LOG_ERR, "memshr:%s: " _f, __func__, ##_a) - -#endif /* __MEMSHR_PRIV_H__ */ diff --git a/tools/memshr/memshr.h b/tools/memshr/memshr.h deleted file mode 100644 index f3f898cd2c..0000000000 --- a/tools/memshr/memshr.h +++ /dev/null @@ -1,51 +0,0 @@ -/****************************************************************************** - * - * Copyright (c) 2009 Citrix Systems, Inc. (Grzegorz Milos) - * - * 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; either version 2 of the License, or - * (at your option) any 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; If not, see . - */ -#ifndef __MEMSHR_H__ -#define __MEMSHR_H__ - -#include -#include -#include - -typedef uint64_t xen_mfn_t; - -typedef struct share_tuple -{ - uint32_t domain; - uint64_t frame; - uint64_t handle; -} share_tuple_t; - -extern void memshr_set_domid(int domid); -extern void memshr_daemon_initialize(void); -extern void memshr_vbd_initialize(void); -extern uint16_t memshr_vbd_image_get(const char* file); -extern void memshr_vbd_image_put(uint16_t memshr_id); -extern int memshr_vbd_issue_ro_request(char *buf, - grant_ref_t gref, - uint16_t file_id, - uint64_t sec, - int secs, - share_tuple_t *hnd); -extern void memshr_vbd_complete_ro_request( - share_tuple_t hnd, - uint16_t file_id, - uint64_t sec, - int secs); - -#endif /* __MEMSHR_H__ */ diff --git a/tools/memshr/shm.c b/tools/memshr/shm.c deleted file mode 100644 index 00e9a51532..0000000000 --- a/tools/memshr/shm.c +++ /dev/null @@ -1,262 +0,0 @@ -/****************************************************************************** - * - * Copyright (c) 2009 Citrix Systems, Inc. (Grzegorz Milos) - * - * 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; either version 2 of the License, or - * (at your option) any 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; If not, see . - */ -#include -#include -#include -#include -#include -#include -#include -#include - -#include "memshr-priv.h" -#include "bidir-hash.h" -#include "shm.h" - -#define MEMSHR_INFO_SHM_FILE "/memshr-info" -#define MEMSHR_INFO_MAGIC 0x15263748 - -#define FGPRT_HASH_SHM_FILE "/blktap-fgprts" -#define FGPRT_HASH_PAGES 10000 - -#define BLOCK_HASH_SHM_FILE "/blktap-blks" -#define BLOCK_HASH_PAGES 10000 - -typedef struct shm_area { - void* base_addr; - size_t size; - int fd; -} shm_area_t; - -typedef struct { - struct shm_area shared_info_area; - struct shm_area fgprts_area; - struct shm_area blocks_area; -} private_shm_info_t; - -private_shm_info_t shm_info; - - - -static int shm_area_open(const char *file, size_t size, int unlink, shm_area_t *shma) -{ - /* TODO: If blktapctrl can be restarted while system is running, this needs - * to be cleverer */ - if(unlink) shm_unlink(file); - - shma->size = size; - shma->fd = shm_open(file, - (O_CREAT | O_RDWR), - (S_IREAD | S_IWRITE)); - - if(shma->fd < 0) return -1; - - if(ftruncate(shma->fd, size) < 0) return -2; - - shma->base_addr = mmap(NULL, - size, - PROT_READ | PROT_WRITE, - MAP_SHARED, - shma->fd, - 0); - - if(shma->base_addr == MAP_FAILED) return -2; - - return 0; -} - -static void shm_area_close(shm_area_t *shma) -{ - munmap(shma->base_addr, shma->size); - close(shma->fd); -} - - -shared_memshr_info_t * shm_shared_info_open(int unlink) -{ - shared_memshr_info_t *shared_info; - pthread_mutexattr_t lock_attr; - int nr_pages, i; - - nr_pages = (sizeof(shared_memshr_info_t) >> XC_PAGE_SHIFT) + 1; - if(shm_area_open(MEMSHR_INFO_SHM_FILE, - nr_pages * XC_PAGE_SIZE, - unlink, - &(shm_info.shared_info_area)) < 0) - { - DPRINTF("Failed to open shma for shared info.\n"); - return NULL; - } - shared_info = (shared_memshr_info_t *) - shm_info.shared_info_area.base_addr; - if(unlink) - { - memset(shared_info, 0, sizeof(shared_memshr_info_t)); - if(pthread_mutexattr_init(&lock_attr) || - pthread_mutexattr_setpshared(&lock_attr, PTHREAD_PROCESS_SHARED) || - pthread_mutex_init(&shared_info->lock, &lock_attr) || - pthread_mutexattr_destroy(&lock_attr)) - { - DPRINTF("Failed to init shared info lock.\n"); - return NULL; - } - strcpy(shared_info->vbd_images[0].file, "list-head"); - for(i=1; ivbd_images[i].next = i; - shared_info->vbd_images[i].prev = i; - } - shared_info->magic = MEMSHR_INFO_MAGIC; - } - else - if(shared_info->magic != MEMSHR_INFO_MAGIC) - { - DPRINTF("Incorrect magic in shared info.\n"); - return NULL; - } - - return shared_info; -} - - -struct fgprtshr_hash * shm_fgprtshr_hash_open(int unlink) -{ - struct fgprtshr_hash *h; - if(shm_area_open(FGPRT_HASH_SHM_FILE, - FGPRT_HASH_PAGES * XC_PAGE_SIZE, - unlink, - &(shm_info.fgprts_area)) < 0) - { - DPRINTF("Failed to init shma for fgprtshr_hash.\n"); - return NULL; - } - - if(unlink) - { - h = fgprtshr_shm_hash_init( - (unsigned long) shm_info.fgprts_area.base_addr, - FGPRT_HASH_PAGES * XC_PAGE_SIZE); - } else - { - h = fgprtshr_shm_hash_get( - (unsigned long) shm_info.fgprts_area.base_addr); - } - - return h; -} - -struct blockshr_hash * shm_blockshr_hash_open(int unlink) -{ - struct blockshr_hash *h; - if(shm_area_open(BLOCK_HASH_SHM_FILE, - BLOCK_HASH_PAGES * XC_PAGE_SIZE, - unlink, - &(shm_info.blocks_area)) < 0) - { - DPRINTF("Failed to init shma for blockshr_hash.\n"); - return NULL; - } - - if(unlink) - { - h = blockshr_shm_hash_init( - (unsigned long) shm_info.blocks_area.base_addr, - BLOCK_HASH_PAGES * XC_PAGE_SIZE); - } else - { - h = blockshr_shm_hash_get( - (unsigned long) shm_info.blocks_area.base_addr); - } - - return h; -} - -uint16_t shm_vbd_image_get(const char* file, vbd_image_info_t *vbd_imgs) -{ - vbd_image_info_t *img, *next_img; - int i, img_id; - - /* Try to find the file in the existing list first */ - img = vbd_imgs; - while(img->next != 0) - { - img = vbd_imgs + img->next; - if(strncmp(img->file, file, MAX_NAME_LEN) == 0) - { - img->ref_cnt++; - return (uint16_t)(img - vbd_imgs); - } - } - - /* Couldn't find an existing entry. We need to add one. Find empty slot */ - for(i=1; inext == i) && (img->prev == i)) - break; - } - /* No entries left! */ - if(i == MAX_NR_VBD_IMAGES) - { - DPRINTF("No space in vbds table.\n"); - return 0; - } - if(strlen(file) > MAX_NAME_LEN - 1) - { - DPRINTF("Filename: %s too long (>%d).\n", file, MAX_NAME_LEN - 1); - return 0; - } - /* Init the entry */ - img_id = (img - vbd_imgs); - next_img = vbd_imgs + vbd_imgs[0].next; - strcpy(img->file, file); - img->ref_cnt = 1; - img->next = vbd_imgs[0].next; - img->prev = 0; - next_img->prev = img_id; - vbd_imgs[0].next = img_id; - - return img_id; -} - - -void shm_vbd_image_put(uint16_t memshr_id, vbd_image_info_t *vbd_imgs) -{ - vbd_image_info_t *img, *next_img, *prev_img; - - img = vbd_imgs + memshr_id; - if(img->ref_cnt == 0) - { - DPRINTF("Incorrect image put.\n"); - return; - } - - img->ref_cnt--; - - /* Remove from list if ref_cnt is zero */ - if(img->ref_cnt == 0) - { - next_img = vbd_imgs + img->next; - prev_img = vbd_imgs + img->prev; - prev_img->next = img->next; - next_img->prev = img->prev; - img->next = img->prev = (img - vbd_imgs); - memset(img->file, 0, MAX_NAME_LEN); - } -} - diff --git a/tools/memshr/shm.h b/tools/memshr/shm.h deleted file mode 100644 index adb6eb9754..0000000000 --- a/tools/memshr/shm.h +++ /dev/null @@ -1,49 +0,0 @@ -/****************************************************************************** - * - * Copyright (c) 2009 Citrix Systems, Inc. (Grzegorz Milos) - * - * 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; either version 2 of the License, or - * (at your option) any 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; If not, see . - */ -#ifndef __SHM_H__ -#define __SHM_H__ - -#include -#include - -#define MAX_NAME_LEN 1000 - -typedef struct vbd_image_info { - char file[MAX_NAME_LEN]; - int ref_cnt; - uint16_t next; - uint16_t prev; -} vbd_image_info_t; - -#define MAX_NR_VBD_IMAGES 4096 - -typedef struct shared_memshr_info { - unsigned long magic; - pthread_mutex_t lock; - int fgprtshr_hash_inited; - int blockshr_hash_inited; - vbd_image_info_t vbd_images[MAX_NR_VBD_IMAGES]; -} shared_memshr_info_t; - -shared_memshr_info_t * shm_shared_info_open(int unlink); -struct fgprtshr_hash * shm_fgprtshr_hash_open(int unlink); -struct blockshr_hash * shm_blockshr_hash_open(int unlink); -uint16_t shm_vbd_image_get(const char* file, vbd_image_info_t *vbd_imgs); -void shm_vbd_image_put(uint16_t memshr_id, vbd_image_info_t *vbd_imgs); - -#endif /* __SHM_H__ */