proxying PCP metrics to perfmon in samba 3

James Peach jpeach at sgi.com
Wed Jan 4 05:53:54 GMT 2006


Hi guys,

Attached is the current version of my code that exports PCP metrics to
perfmon using the HKEY_PERFORMANCE_DATA registry interface. I use a lot
of PCP and perfmon terminology below, and it's really hard to keep it
the concepts straight. Please ask me to clarify if I'm being confusing.

There are a number of differences between the perfmon and the PCP data
models. The PCP data model is richer in data types and has more
efficient lookup operations. The perfmon data model is more structured
(a somewhat object-oriented design).

In reg_perfobj.c we define a new data structure which tells us how to
map PCP metrics to perfmon objects and counters. This data structure is
created at runtime by querying PCP client APIs. We do not keep any
external state, so we can never get out of sync with PCP.

However, in the perfmon data model, objects have instances, where as in
PCP, metrics (counters in perfmon terminology) have instances. This
means that when we construct perfmon objects and counters, it is
necessary to divide PCP metrics that have the same instance domain into
distinct perfmon objects.

So if we have this set of PCP metrics:

    foo.metric.one        -+
    foo.metric.two         +-- no instance domain
    foo.metric.three      -+

    foo.metricset.one     -+
    foo.metricset.two      +-- instance domain 1
    foo.metricset.three   -+

We would construct 2 perfmon objects:
    foo.metric, with counters one, two and three
    foo.metricset, with counters one, two and three

Note that PCP metric names are quite terse. Since we dynamically create
all the state necessary to publish the PCP metrics, the user will be
presented with counter and object names that will be quite unexpected
if they are used to using perfmon against a Windows system. To minimise
this discomfort, I have added a static mapping, which will provide
common names and semantics perfmon objects that will be
indistinguishable from those published by windows.

There's no support for perfmon instances having parent objects, because
I don't think there is enough information in the PCP data model to do
this sensibly. I don't know if there are any apps that would depend on
this.

The attached patch is missing the following necessary functions:

    1. Fetching metrics. I haven't filled in the code path that actually
    fetches metric values from pmcd.

    2. Splitting objects on instance domain boundaries. The dynamic
    perfmon object creation code doesn't yet know anything about instance
    domains.

    3. Unit conversion. Perfmon has no way to represent the units of a
    metric. The proposed solution is to always convert the metric into
    "sensible" units like MiB/sec. The counter name can be generated to
    include the units.

    4. Merging the dynamic and static PCP mappings into a single data
    structure.

To build samba after applying the patch, you will need the PCP RPM. The
best option is to use pcp-2.4.0-1.2.src.rpm on SLES9, but earlier
versions will probably be ok too. Check oss.sgi.com/projects/pcp if you
need to build from source. I have proper configure.in checks for PCP,
which I will post when we get closer to checking this in.

So, comments and help with the patch will be gratefully received. Also,
as a matter of policy, are we happy to depend on PCP for gathering
performance metrics?

-- 
James Peach | jpeach at sgi.com | SGI Australian Software Group
I don't speak for SGI.
-------------- next part --------------
Index: source/Makefile.in
===================================================================
--- source/Makefile.in	(revision 11815)
+++ source/Makefile.in	(working copy)
@@ -10,11 +10,12 @@
 prefix=@prefix@
 exec_prefix=@exec_prefix@
 
+PCPDEFS=-DHAVE_PCP -DHAVE_PCP_PMAPI_H -DHAVE_PCP_IMPL_H -DHAVE_PCP_PMDA_H
 LIBS=@LIBS@
 CC=@CC@
 SHLD=@SHLD@
 CFLAGS=@CFLAGS@
-CPPFLAGS=@CPPFLAGS@
+CPPFLAGS=$(PCPDEFS) @CPPFLAGS@
 EXEEXT=@EXEEXT@
 LDFLAGS=@LDFLAGS@
 AR=@AR@
@@ -165,6 +166,8 @@
 
 TDB_OBJ = $(TDBBASE_OBJ) tdb/tdbutil.o tdb/tdbback.o
 
+PCP_OBJ = lib/pcp.o
+
 SMBLDAP_OBJ = @SMBLDAP@ @SMBLDAPUTIL@
 
 VERSION_OBJ = lib/version.o
@@ -266,7 +269,8 @@
 
 REGISTRY_OBJ = registry/reg_frontend.o registry/reg_cachehook.o registry/reg_printing.o \
                registry/reg_db.o registry/reg_eventlog.o registry/reg_shares.o \
-               registry/reg_util.o registry/reg_dynamic.o registry/reg_perfcount.o
+               registry/reg_util.o registry/reg_dynamic.o registry/reg_perfcount.o \
+	       registry/reg_perfobj.o
 
 RPC_LSA_OBJ = rpc_server/srv_lsa.o rpc_server/srv_lsa_nt.o
 
@@ -417,7 +421,7 @@
 		$(LIBMSRPC_OBJ) \
 		$(LIBADS_OBJ) $(KRBCLIENT_OBJ) $(LIBADS_SERVER_OBJ) \
 		$(REGISTRY_OBJ) $(POPT_LIB_OBJ) \
-		$(BUILDOPT_OBJ) $(SMBLDAP_OBJ)
+		$(BUILDOPT_OBJ) $(SMBLDAP_OBJ) $(PCP_OBJ)
 
 PRINTING_OBJ = printing/pcap.o printing/print_svid.o printing/print_aix.o \
                printing/print_cups.o printing/print_generic.o \
@@ -880,7 +884,7 @@
 	@echo Linking $@
 	@$(CC) $(FLAGS) @PIE_LDFLAGS@ -o $@ $(SMBD_OBJ) $(LDFLAGS) $(LDAP_LIBS) \
 		$(KRB5LIBS) $(DYNEXP) $(PRINT_LIBS) $(AUTH_LIBS) \
-		$(ACL_LIBS) $(PASSDB_LIBS) $(LIBS) @POPTLIBS@
+		$(ACL_LIBS) $(PASSDB_LIBS) $(LIBS) @POPTLIBS@ -lpcp
 
 bin/nmbd at EXEEXT@: $(NMBD_OBJ) @BUILD_POPT@ bin/.dummy
 	@echo Linking $@
Index: source/lib/debug.c
===================================================================
--- source/lib/debug.c	(revision 11815)
+++ source/lib/debug.c	(working copy)
@@ -927,9 +927,11 @@
 	syslog_level = level;
 #endif
 
+#ifdef jpeach
 	/* Don't print a header if we're logging to stdout. */
 	if( stdout_logging )
 		return( True );
+#endif
 
 	/* Print the header if timestamps are turned on.  If parameters are
 	 * not yet loaded, then default to timestamps on.
Index: source/libsmb/ntlmssp_sign.c
===================================================================
--- source/libsmb/ntlmssp_sign.c	(revision 11815)
+++ source/libsmb/ntlmssp_sign.c	(working copy)
@@ -139,7 +139,7 @@
 {
 	NTSTATUS nt_status;
 
-	if (!ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SIGN) {
+	if (!(ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SIGN)) {
 		DEBUG(3, ("NTLMSSP Signing not negotiated - cannot sign packet!\n"));
 		return NT_STATUS_INVALID_PARAMETER;
 	}
@@ -238,7 +238,7 @@
 {	
 	NTSTATUS nt_status;
 
-	if (!ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SEAL) {
+	if (!(ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SEAL)) {
 		DEBUG(3, ("NTLMSSP Sealing not negotiated - cannot seal packet!\n"));
 		return NT_STATUS_INVALID_PARAMETER;
 	}
Index: source/rpc_server/srv_reg_nt.c
===================================================================
--- source/rpc_server/srv_reg_nt.c	(revision 11815)
+++ source/rpc_server/srv_reg_nt.c	(working copy)
@@ -26,6 +26,7 @@
 
 #include "includes.h"
 #include "regfio.h"
+#include "rpc_perfcount.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_RPC_SRV
@@ -333,16 +334,23 @@
 
 	if ( !(regvals = TALLOC_ZERO_P( p->mem_ctx, REGVAL_CTR )) ) 
 		return WERR_NOMEM;
-	
+
 	/* Handle QueryValue calls on HKEY_PERFORMANCE_DATA */
 	if(regkey->type == REG_KEY_HKPD) 
 	{
 		if(strequal(name, "Global"))
 		{
-			uint32 outbuf_len;
+			size_t outbuf_len;
 			prs_struct prs_hkpd;
+
 			prs_init(&prs_hkpd, q_u->bufsize, p->mem_ctx, MARSHALL);
 			status = reg_perfcount_get_hkpd(&prs_hkpd, q_u->bufsize, &outbuf_len, NULL);
+			if (!NT_STATUS_IS_OK(status))
+			{
+				prs_mem_free(&prs_hkpd);
+				goto done;
+			}
+
 			regval_ctr_addvalue(regvals, "HKPD", REG_BINARY,
 					    prs_hkpd.data_p, outbuf_len);
 			val = dup_registry_value(regval_ctr_specific_value(regvals, 0));
@@ -350,13 +358,16 @@
 		}
 		else if(strequal(name, "Counter 009"))
 		{
-			uint32 base_index;
-			uint32 buffer_size;
-			char *buffer;
-			
-			buffer = NULL;
-			base_index = reg_perfcount_get_base_index();
-			buffer_size = reg_perfcount_get_counter_names(base_index, &buffer);
+			ssize_t buffer_size;
+			char *	buffer = NULL;
+
+			buffer_size = reg_perfcount_get_counter_names(&buffer);
+			if (buffer_size <= 0)
+			{
+				status = WERR_NOMEM;
+				goto done;
+			}
+
 			regval_ctr_addvalue(regvals, "Counter 009", 
 					    REG_MULTI_SZ, buffer, buffer_size);
 			
@@ -364,19 +375,22 @@
 			
 			if(buffer_size > 0)
 			{
-				SAFE_FREE(buffer);
+				talloc_free(buffer);
 				status = WERR_OK;
 			}
 		}
 		else if(strequal(name, "Explain 009"))
 		{		
-			uint32 base_index;
-			uint32 buffer_size;
-			char *buffer;
+			ssize_t buffer_size;
+			char *	buffer = NULL;
 			
-			buffer = NULL;
-			base_index = reg_perfcount_get_base_index();
-			buffer_size = reg_perfcount_get_counter_help(base_index, &buffer);
+			buffer_size = reg_perfcount_get_counter_help(&buffer);
+			if (buffer_size <= 0)
+			{
+			    status = WERR_NOMEM;
+			    goto done;
+			}
+
 			regval_ctr_addvalue(regvals, "Explain 009", 
 					    REG_MULTI_SZ, buffer, buffer_size);
 			
@@ -384,7 +398,7 @@
 			
 			if(buffer_size > 0)
 			{
-				SAFE_FREE(buffer);
+				talloc_free(buffer);
 				status = WERR_OK;
 			}
 		}
@@ -393,8 +407,15 @@
 			/* we probably have a request for a specific object here */
 			uint32 outbuf_len;
 			prs_struct prs_hkpd;
+
 			prs_init(&prs_hkpd, q_u->bufsize, p->mem_ctx, MARSHALL);
 			status = reg_perfcount_get_hkpd(&prs_hkpd, q_u->bufsize, &outbuf_len, name);
+			if (!NT_STATUS_IS_OK(status))
+			{
+				prs_mem_free(&prs_hkpd);
+				goto done;
+			}
+			
 			regval_ctr_addvalue(regvals, "HKPD", REG_BINARY,
 					    prs_hkpd.data_p, outbuf_len);
 			
@@ -423,6 +444,7 @@
 	    }
 	}
 
+done:
 	init_reg_r_query_value(q_u->ptr_buf, r_u, val, status);
 	
 	TALLOC_FREE( regvals );
Index: source/rpc_parse/parse_prs.c
===================================================================
--- source/rpc_parse/parse_prs.c	(revision 11815)
+++ source/rpc_parse/parse_prs.c	(working copy)
@@ -480,38 +480,6 @@
 }
 
 /******************************************************************
- Align on a 2 byte boundary
- *****************************************************************/
- 
-BOOL prs_align_uint16(prs_struct *ps)
-{
-	BOOL ret;
-	uint8 old_align = ps->align;
-
-	ps->align = 2;
-	ret = prs_align(ps);
-	ps->align = old_align;
-	
-	return ret;
-}
-
-/******************************************************************
- Align on a 8 byte boundary
- *****************************************************************/
- 
-BOOL prs_align_uint64(prs_struct *ps)
-{
-	BOOL ret;
-	uint8 old_align = ps->align;
-
-	ps->align = 8;
-	ret = prs_align(ps);
-	ps->align = old_align;
-	
-	return ret;
-}
-
-/******************************************************************
  Align on a specific byte boundary
  *****************************************************************/
  
@@ -527,8 +495,6 @@
 	return ret;
 }
 
-
-
 /*******************************************************************
  Align only if required (for the unistr2 string mainly)
  ********************************************************************/
Index: source/include/includes.h
===================================================================
--- source/include/includes.h	(revision 11815)
+++ source/include/includes.h	(working copy)
@@ -940,8 +940,6 @@
 #include "rpc_ds.h"
 #include "rpc_echo.h"
 #include "rpc_shutdown.h"
-#include "rpc_perfcount.h"
-#include "rpc_perfcount_defs.h"
 
 #include "nt_printing.h"
 
Index: source/include/ntdomain.h
===================================================================
--- source/include/ntdomain.h	(revision 11815)
+++ source/include/ntdomain.h	(working copy)
@@ -46,6 +46,11 @@
 	const char *sess_key; /* If we have to do encrypt/decrypt on the fly. */
 } prs_struct;
 
+/* Align the stream to the corresponding boundary. */
+#define prs_align_uint64(p) prs_align_custom((p), 8)
+#define prs_align_uint32(p) prs_align_custom((p), 4)
+#define prs_align_uint16(p) prs_align_custom((p), 2)
+
 /*
  * Defines for io member of prs_struct.
  */
Index: source/include/rpc_perfcount.h
===================================================================
--- source/include/rpc_perfcount.h	(revision 11815)
+++ source/include/rpc_perfcount.h	(working copy)
@@ -1,106 +1,243 @@
+/* 
+ *  Unix SMB/CIFS implementation.
+ *  Windows performance counters.
+ *
+ *  Copyright (C) Marcin Krzysztof Porwit    2005
+ *  Copyright (C) Gerald (Jerry) Carter      2005
+ *
+ *  Copyright (C) 2005 Silicon Graphics, Inc. All rights reserved.
+ *	James Peach, <jpeach at sgi.com>
+ *  
+ *  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, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
 #ifndef _RPC_PERFCOUNT_H
 #define _RPC_PERFCOUNT_H
 
-typedef struct perf_counter_definition
-{
-	/* sizeof(PERF_COUNTER_DEFINITION) */
-	uint32 ByteLength;
-	uint32 CounterNameTitleIndex;
-	uint32 CounterNameTitlePointer;
-	uint32 CounterHelpTitleIndex;
-	uint32 CounterHelpTitlePointer;
-	uint32 DefaultScale;
-	uint32 DetailLevel;
-	uint32 CounterType;
-	uint32 CounterSize;
-	uint32 CounterOffset;
-}
-PERF_COUNTER_DEFINITION;
+/* Align a value up to the nearest 8-byte or 4-byte boundary. */
+#define ALIGN64(val) (((val - 1) - ((val - 1) % 8)) + 8)
+#define ALIGN32(val) (((val - 1) - ((val - 1) % 4)) + 4)
 
+/* Return the offset of the next 8-byte boundary from the offset of the given
+ * structure member.
+ */
+#define MEMBER_ALIGN64(structure, member) \
+    ALIGN64(offsetof(structure, member))
+
+/* Return the number of bytes needed to align the given struture member up to
+ * the next 8-byte boundary.
+ */
+#define MEMBER_ALIGN64_SPACE(structure, member) \
+    ALIGN64(offsetof(structure, member) - offsetof(structure, member)) 
+
+/* Return true if val is 64-but aligned. */
+#define IS_ALIGN64(val) (ALIGN64(val) == (val))
+
+/* NOTE:
+ *
+ * type_name_SZ is used for the size of the object as it will apear ON THE
+ * WIRE. Each type_name_SZ definition follows the fields that appear on the
+ * wire and preceeds the fields that are used for the internal dta structure.
+ */
+
+/* This structure holds the value of a counter or a counter instance. In PCP
+ * terminology, it would be a pmAtomValue, except you need to know the counter
+ * definition to decode it.
+ */
 typedef struct perf_counter_block
 {
 	/* Total size of the data block, including all data plus this header */
-	uint32 ByteLength;
-	uint8 *data;
+	uint32_t ByteLength;
+
+#define PERF_COUNTER_BLOCK_SZ (sizeof(uint32_t))
+
 }
 PERF_COUNTER_BLOCK;
 
+union counter_value
+{
+    uint32_t	dword_val;  /* PERF_SIZE_DWORD */
+    uint64_t	large_val;  /* PERF_SIZE_LARGE */
+    uint8_t *	varlen_val; /* PERF_SIZE_VARIABLE_LEN */
+};
+
+/* This structure holds all the metadata associated with a counter (a metric in
+ * PCP terminology).
+ */
+typedef struct perf_counter_definition
+{
+	uint32_t ByteLength;
+	uint32_t CounterNameTitleIndex;
+	uint32_t CounterNameTitlePointer;
+	uint32_t CounterHelpTitleIndex;
+	uint32_t CounterHelpTitlePointer;
+	uint32_t DefaultScale;
+	uint32_t DetailLevel;
+	uint32_t CounterType;
+	uint32_t CounterSize;
+	uint32_t CounterOffset;
+
+#define PERF_COUNTER_DEFINITION_SZ  (10 * sizeof(uint32_t))
+
+	PERF_COUNTER_BLOCK cblock;
+
+	/* Pointer into parent PERF_OBJECT_TYPE's counter_value block. */
+	union counter_value * cvals;
+}
+PERF_COUNTER_DEFINITION;
+
+/* This structure holds both the name an value of a counter instance. The
+ * instance name data is appended to the end of this structure, hence the need
+ * for all the different length fields.
+ */
 typedef struct perf_instance_definition
 {
-	/* Total size of the instance definition, including the length of the terminated Name string */
-	uint32 ByteLength;
-	uint32 ParentObjectTitleIndex;
-	uint32 ParentObjectTitlePointer;
-	uint32 UniqueID;
-	/* From the start of the PERF_INSTANCE_DEFINITION, the byte offset to the start of the Name string */
-	uint32 NameOffset;
-	uint32 NameLength;
+	/* Total size of the instance definition, including the length of
+	 * the terminated Name string
+	 */
+	uint32_t ByteLength;
+	uint32_t ParentObjectTitleIndex;
+	uint32_t ParentObjectTitlePointer;
+	uint32_t UniqueID;
+	/* From the start of the PERF_INSTANCE_DEFINITION, the byte offset
+	 * to the start of the Name string
+	 */
+	uint32_t NameOffset;
+	uint32_t NameLength;
+
+#define PERF_INSTANCE_DEFINITION_SZ (6 * sizeof(uint32_t))
+
 	/* Unicode string containing the name for the instance */
-	uint8 *data;
-	PERF_COUNTER_BLOCK counter_data;
+	uint8_t * name;
+
+	PERF_COUNTER_BLOCK cblock;
+
+	/* Pointer into parent PERF_OBJECT_TYPE's counter_value block. */
+	union counter_value * cvals;
 }
 PERF_INSTANCE_DEFINITION;
 
+/* This structure groups a bunch of logically related counters. This is kinda
+ * equivalent to a PCP PMDA, except that in the PMNS, the boundaries between
+ * PMDAs are not very visible.
+ */
 typedef struct perf_object_type
 {
-	/* Total size of the object block, including all PERF_INSTANCE_DEFINITIONs,
-	   PERF_COUNTER_DEFINITIONs and PERF_COUNTER_BLOCKs in bytes */
-	uint32 TotalByteLength;
-	/* Size of this PERF_OBJECT_TYPE plus all PERF_COUNTER_DEFINITIONs in bytes */
-	uint32 DefinitionLength;
+	/* Total size of the object block, including all
+	 * PERF_INSTANCE_DEFINITIONs, PERF_COUNTER_DEFINITIONs and
+	 * PERF_COUNTER_BLOCKs in bytes.
+	 */
+	uint32_t TotalByteLength;
+	/* Size of this PERF_OBJECT_TYPE plus all PERF_COUNTER_DEFINITIONs in
+	 * bytes
+	 */
+	uint32_t DefinitionLength;
 	/* Size of this PERF_OBJECT_TYPE */
-	uint32 HeaderLength;
-	uint32 ObjectNameTitleIndex;
-	uint32 ObjectNameTitlePointer;
-	uint32 ObjectHelpTitleIndex;
-	uint32 ObjectHelpTitlePointer;
-	uint32 DetailLevel;
-	uint32 NumCounters;
-	uint32 DefaultCounter;
-	uint32 NumInstances;
-	uint32 CodePage;
+	uint32_t HeaderLength;
+	uint32_t ObjectNameTitleIndex;
+	uint32_t ObjectNameTitlePointer;
+	uint32_t ObjectHelpTitleIndex;
+	uint32_t ObjectHelpTitlePointer;
+	uint32_t DetailLevel;
+	uint32_t NumCounters;
+	uint32_t DefaultCounter;
+	uint32_t NumInstances;
+	uint32_t CodePage;
+
+	/* PerfTime must be 64-bit aligned */
 	UINT64_S PerfTime;
 	UINT64_S PerfFreq;
-	PERF_COUNTER_DEFINITION *counters;
-	PERF_INSTANCE_DEFINITION *instances;
-	PERF_COUNTER_BLOCK counter_data;
+
+#define PERF_OBJECT_TYPE_SZ \
+	(\
+		(12 * sizeof(uint32_t)) +  \
+		MEMBER_ALIGN64_SPACE(struct perf_object_type, PerfTime) + \
+		(2 * (2 * sizeof(uint32_t)))\
+	)
+
+	PERF_COUNTER_DEFINITION * counters;
+	PERF_INSTANCE_DEFINITION ** instances;
+
+	PERF_COUNTER_BLOCK cblock;
+
+	/* Metric values for this object's counters and instances. */
+	union counter_value * cvals;
 }
 PERF_OBJECT_TYPE;
 
-/* PerfCounter Inner Buffer structs */
 typedef struct perf_data_block
 {
-	/* hardcoded to read "P.E.R.F" */
-	uint16 Signature[4];
-	uint32 LittleEndian;
-	/* both currently hardcoded to 1 */
-	uint32 Version;
-	uint32 Revision;
-	/* bytes of PERF_OBJECT_TYPE data, does NOT include the PERF_DATA_BLOCK */
-	uint32 TotalByteLength;
-	/* size of PERF_DATA_BLOCK including the uint8 *data */
-	uint32 HeaderLength;
+	uint16_t Signature[4];	    /* hardcoded to read "P.E.R.F" */
+	uint32_t LittleEndian;
+	uint32_t Version;	    /* currently hardcoded to 1 */
+	uint32_t Revision;	    /* currently hardcoded to 1 */
+	uint32_t TotalByteLength;
+	/* size of PERF_DATA_BLOCK including the uint8_t *data */
+	uint32_t HeaderLength;
 	/* number of PERF_OBJECT_TYPE structures encoded */
-	uint32 NumObjectTypes;
-	uint32 DefaultObject;
+	uint32_t NumObjectTypes;
+	uint32_t DefaultObject;
 	SYSTEMTIME SystemTime;
-	/* This will guarantee that we're on a 64-bit boundary before we encode
-	   PerfTime, and having it there will make my offset math much easier. */
-	uint32 Padding;
-	/* Now when I'm marshalling this, I'll need to call prs_align_uint64() 
-	   before I start encodint the UINT64_S structs */
+
+	/* Perfmon expects PerfTime to be aligned on a 64-bit boundary. We must
+	 * call prs_align_uint64() when marshalling.
+	 */
+
 	/* clock rate * seconds uptime */
 	UINT64_S PerfTime;
 	/* The clock rate of the CPU */
 	UINT64_S PerfFreq; 
 	/* used for high-res timers -- for now PerfTime * 10e7 */
 	UINT64_S PerfTime100nSec;
-	uint32 SystemNameLength;
-	uint32 SystemNameOffset;
+	uint32_t SystemNameLength;
+	uint32_t SystemNameOffset;
+
+#define PERF_DATA_BLOCK_SZ \
+      	(\
+		    (10 * sizeof(uint32_t)) + \
+		    (8 * sizeof(uint16_t)) + \
+		    (4 * sizeof(uint16_t)) + \
+		    MEMBER_ALIGN64_SPACE(struct perf_data_block, PerfTime) + \
+		    (3 * (2 * (sizeof(uint32_t)))) \
+	)
+
 	/* The SystemName, in unicode, terminated */
-	uint8* data;
-	PERF_OBJECT_TYPE *objects;
+	uint8_t * sysname;
+	PERF_OBJECT_TYPE ** objects;
 } 
 PERF_DATA_BLOCK;
 
+/* FIXME: These declarations should have their own header file to avoid
+ * polluting everyone's namespace with the preceeding structures.
+ */
+
+struct reg_perflib_params
+{
+    int base_index;
+    int version;
+    int last_counter;
+    int last_help;
+};
+
+WERROR reg_perfcount_get_hkpd(prs_struct * ps,
+			     size_t	    max_buf_size,
+			     size_t *	    outbuf_len,
+			     const char *   object_ids);
+
+ssize_t reg_perfcount_get_counter_help(char ** retbuf);
+ssize_t reg_perfcount_get_counter_names(char ** retbuf);
+void	reg_perfcount_get_params(struct reg_perflib_params * p);
+
 #endif /* _RPC_PERFCOUNT_H */
Index: source/include/rpc_perfcount_defs.h
===================================================================
--- source/include/rpc_perfcount_defs.h	(revision 11815)
+++ source/include/rpc_perfcount_defs.h	(working copy)
@@ -14,6 +14,7 @@
 
 #define PERF_NO_INSTANCES             -1
 #define PERF_NO_UNIQUE_ID	      -1
+#define PERF_NO_DEFAULT_COUNTER	      -1
 
 /* These determine the data size */
 #define PERF_SIZE_DWORD               0x00000000
Index: source/include/rpc_misc.h
===================================================================
--- source/include/rpc_misc.h	(revision 11815)
+++ source/include/rpc_misc.h	(working copy)
@@ -356,4 +356,12 @@
 	uint32 high;
 } UINT64_S;
 
+static inline UINT64_S make_uint64_s(uint64_t inval)
+{
+    UINT64_S val;
+    val.high = inval & ((uint64_t)1 << 32);
+    val.low = inval & ~((uint64_t)1 << 32);
+    return(val);
+}
+
 #endif /* _RPC_MISC_H */
Index: source/include/talloc.h
===================================================================
--- source/include/talloc.h	(revision 11815)
+++ source/include/talloc.h	(working copy)
@@ -49,6 +49,8 @@
 #define talloc_array(ctx, type, count) (type *)_talloc_array(ctx, sizeof(type), count, #type)
 #define talloc_array_size(ctx, size, count) _talloc_array(ctx, size, count, __location__)
 
+#define talloc_array_elements(ctx, type) (talloc_get_size(ctx) / sizeof(type))
+
 #define talloc_realloc(ctx, p, type, count) (type *)_talloc_realloc_array(ctx, p, sizeof(type), count, #type)
 #define talloc_realloc_size(ctx, ptr, size) _talloc_realloc(ctx, ptr, size, __location__)
 
Index: source/include/rpc_reg.h
===================================================================
--- source/include/rpc_reg.h	(revision 11815)
+++ source/include/rpc_reg.h	(working copy)
@@ -91,7 +91,7 @@
  * Registry key types
  *	Most keys are going to be GENERIC -- may need a better name?
  *	HKPD and HKPT are used by reg_perfcount.c
- *		they are special keys that congtain performance data
+ *		they are special keys that contain performance data
  */
 #define REG_KEY_GENERIC		0
 #define REG_KEY_HKPD		1
Index: source/configure.in
===================================================================
--- source/configure.in	(revision 11815)
+++ source/configure.in	(working copy)
@@ -2348,22 +2348,30 @@
     AC_DEFINE(HAVE_SECURE_MKSTEMP,1,[Whether mkstemp is secure])
 fi
 
-AC_CACHE_CHECK([for sysconf(_SC_NGROUPS_MAX)],samba_cv_SYSCONF_SC_NGROUPS_MAX,[
-AC_TRY_RUN([#include <unistd.h>
-main() { exit(sysconf(_SC_NGROUPS_MAX) == -1 ? 1 : 0); }],
-samba_cv_SYSCONF_SC_NGROUPS_MAX=yes,samba_cv_SYSCONF_SC_NGROUPS_MAX=no,samba_cv_SYSCONF_SC_NGROUPS_MAX=cross)])
-if test x"$samba_cv_SYSCONF_SC_NGROUPS_MAX" = x"yes"; then
-    AC_DEFINE(SYSCONF_SC_NGROUPS_MAX,1,[Whether sysconf(_SC_NGROUPS_MAX) is available])
-fi
+dnl AX_CHECK_SYSCONF(_SC_FOO) causes SYSCONF_SC_FOO to be defined.
+AC_DEFUN(AX_CHECK_SYSCONF,
+[
+    AC_CACHE_CHECK([for sysconf($1)],
+	samba_cv_SYSCONF$1,
+	[
+	    AC_TRY_RUN([#include <unistd.h>
+		main() { exit(sysconf($1) == -1 ? 1 : 0); }],
+	    samba_cv_SYSCONF$1=yes,
+	    samba_cv_SYSCONF$1=no,
+	    samba_cv_SYSCONF$1=cross)
+	])
 
-AC_CACHE_CHECK([for sysconf(_SC_NPROC_ONLN)],samba_cv_SYSCONF_SC_NPROC_ONLN,[
-AC_TRY_RUN([#include <unistd.h>
-main() { exit(sysconf(_SC_NPROC_ONLN) == -1 ? 1 : 0); }],
-samba_cv_SYSCONF_SC_NPROC_ONLN=yes,samba_cv_SYSCONF_SC_NPROC_ONLN=no,samba_cv_SYSCONF_SC_NPROC_ONLN=cross)])
-if test x"$samba_cv_SYSCONF_SC_NPROC_ONLN" = x"yes"; then
-    AC_DEFINE(SYSCONF_SC_NPROC_ONLN,1,[Whether sysconf(_SC_NPROC_ONLN) is available])
-fi
+	if test x"$samba_cv_SYSCONF$1" = x"yes"; then
+	    AC_DEFINE(SYSCONF$1,1,
+		[Whether sysconf($1) is available])
+	fi
+])
 
+AX_CHECK_SYSCONF(_SC_NGROUPS_MAX)
+AX_CHECK_SYSCONF(_SC_NPROC_ONLN)
+AX_CHECK_SYSCONF(_SC_NPROCESSORS_ONLN)
+AX_CHECK_SYSCONF(_SC_CLK_TCK)
+
 AC_CACHE_CHECK([for root],samba_cv_HAVE_ROOT,[
 AC_TRY_RUN([main() { exit(getuid() != 0); }],
            samba_cv_HAVE_ROOT=yes,samba_cv_HAVE_ROOT=no,samba_cv_HAVE_ROOT=cross)])
Index: source/registry/reg_dynamic.c
===================================================================
--- source/registry/reg_dynamic.c	(revision 11815)
+++ source/registry/reg_dynamic.c	(working copy)
@@ -21,6 +21,7 @@
 /* Implementation of registry frontend view functions. */
 
 #include "includes.h"
+#include "rpc_perfcount.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_RPC_SRV
@@ -103,19 +104,20 @@
 
 static int perflib_params( REGVAL_CTR *regvals )
 {
-	int base_index = -1;
-	int last_counter = -1;
-	int last_help = -1;
-	int version = 0x00010001;
-	
-	base_index = reg_perfcount_get_base_index();
-	regval_ctr_addvalue(regvals, "Base Index", REG_DWORD, (char *)&base_index, sizeof(base_index));
-	last_counter = reg_perfcount_get_last_counter(base_index);
-	regval_ctr_addvalue(regvals, "Last Counter", REG_DWORD, (char *)&last_counter, sizeof(last_counter));
-	last_help = reg_perfcount_get_last_help(last_counter);
-	regval_ctr_addvalue(regvals, "Last Help", REG_DWORD, (char *)&last_help, sizeof(last_help));
-	regval_ctr_addvalue(regvals, "Version", REG_DWORD, (char *)&version, sizeof(version));
+	struct reg_perflib_params params;
 
+#define reg_add_dword(name, val) \
+	regval_ctr_addvalue(regvals, name, REG_DWORD, (char *)&val, sizeof(val))
+
+	reg_perfcount_get_params(&params);
+
+	reg_add_dword("Base Index", params.base_index);
+	reg_add_dword("Last Counter", params.last_counter);
+	reg_add_dword("Last Help", params.last_help);
+	reg_add_dword("Version", params.version);
+
+#undef reg_add_dword
+
 	return regval_ctr_numvals( regvals );
 }
 
@@ -124,19 +126,18 @@
 
 static int perflib_009_params( REGVAL_CTR *regvals )
 {
-	int base_index;
 	int buffer_size;
 	char *buffer = NULL;
 
-	base_index = reg_perfcount_get_base_index();
-	buffer_size = reg_perfcount_get_counter_names(base_index, &buffer);
-	regval_ctr_addvalue(regvals, "Counter", REG_MULTI_SZ, buffer, buffer_size);
+	buffer_size = reg_perfcount_get_counter_names(&buffer);
+	regval_ctr_addvalue(regvals, "Counters", REG_MULTI_SZ, buffer, buffer_size);
 	if(buffer_size > 0)
-		SAFE_FREE(buffer);
-	buffer_size = reg_perfcount_get_counter_help(base_index, &buffer);
+		talloc_free(buffer);
+
+	buffer_size = reg_perfcount_get_counter_help(&buffer);
 	regval_ctr_addvalue(regvals, "Help", REG_MULTI_SZ, buffer, buffer_size);
 	if(buffer_size > 0)
-		SAFE_FREE(buffer);
+		talloc_free(buffer);
 	
 	return regval_ctr_numvals( regvals );
 }
@@ -146,24 +147,22 @@
 
 static int hkpt_params( REGVAL_CTR *regvals )
 {
-	uint32 base_index;
 	uint32 buffer_size;
 	char *buffer = NULL;
 
 	/* This is ALMOST the same as perflib_009_params, but HKPT has
 	   a "Counters" entry instead of a "Counter" key. <Grrrr> */
 	   
-	base_index = reg_perfcount_get_base_index();
-	buffer_size = reg_perfcount_get_counter_names(base_index, &buffer);
+	buffer_size = reg_perfcount_get_counter_names(&buffer);
 	regval_ctr_addvalue(regvals, "Counters", REG_MULTI_SZ, buffer, buffer_size);
 	
 	if(buffer_size > 0)
-		SAFE_FREE(buffer);
+		talloc_free(buffer);
 		
-	buffer_size = reg_perfcount_get_counter_help(base_index, &buffer);
+	buffer_size = reg_perfcount_get_counter_help(&buffer);
 	regval_ctr_addvalue(regvals, "Help", REG_MULTI_SZ, buffer, buffer_size);
 	if(buffer_size > 0)
-		SAFE_FREE(buffer);
+		talloc_free(buffer);
 	
 	return regval_ctr_numvals( regvals );
 }
@@ -220,8 +219,10 @@
 	normalize_reg_path( path );
 	
 	for ( i=0; dynamic_values[i].path; i++ ) {
-		if ( strcmp( path, dynamic_values[i].path ) == 0 )
+		if ( strcmp( path, dynamic_values[i].path ) == 0 ) {
+			DEBUG(4, ("opening dynamic registry path %s\n", path));
 			return dynamic_values[i].fetch_values( val );
+		}
 	}
 	
 	return -1;
Index: source/registry/reg_perfcount.c
===================================================================
--- source/registry/reg_perfcount.c	(revision 11815)
+++ source/registry/reg_perfcount.c	(working copy)
@@ -2,8 +2,11 @@
  *  Unix SMB/CIFS implementation.
  *  Virtual Windows Registry Layer
  *
- *  Copyright (C) Marcin Krzysztof Porwit    2005,
- *  Copyright (C) Gerald (Jerry) Carter      2005.
+ *  Copyright (C) Marcin Krzysztof Porwit    2005
+ *  Copyright (C) Gerald (Jerry) Carter      2005
+ *
+ *  Copyright (C) 2005 Silicon Graphics, Inc. All rights reserved.
+ *	James Peach, <jpeach at sgi.com>
  *  
  *  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
@@ -21,1337 +24,1188 @@
  */
 
 #include "includes.h"
+#include "pcp.h"
+#include "rpc_perfcount.h"
+#include "rpc_perfcount_defs.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_RPC_SRV
 
-#define PERFCOUNT_MAX_LEN 256
+#define PERFCOUNT_TRACE 0
 
-#define PERFCOUNTDIR	"perfmon"
-#define NAMES_DB	"names.tdb"
-#define DATA_DB		"data.tdb"
+struct perf_index
+{
+    const char *	help;
+    const char *	name;
+    struct perf_object *perf;
+};
 
+static struct perf_object **	p_object_list;
+static struct perf_index *	p_object_index;
+
+static char *	c_name_buf;
+ssize_t		c_name_sz;
+
+static char *	c_help_buf;
+ssize_t		c_help_sz;
+
+/* These macros let us shift the object indices up by a fixed about to avoid
+ * using zero-based indices (if necessary).
+ */
+#define OBJECT_INDEX_MIN    0
+#define OBJECT_INDEX_MAX    (talloc_array_elements(p_object_index, \
+						    struct perf_index) + \
+			    OBJECT_INDEX_MIN)
+
 /*********************************************************************
 *********************************************************************/
 
-static char* counters_directory( const char *dbname )
+typedef const char * (*index_item_string)(const struct perf_index *);
+
+static const char * index_item_name(const struct perf_index * pi)
+{ return pi->name; }
+
+static const char * index_item_help(const struct perf_index * pi)
+{ return pi->help; }
+
+/* Convert the given index and string to unicode strings and append to
+ * the given buffer. The buffer contains a sequence of unicode strings
+ * separated by NULLs.
+ */
+static BOOL
+append_unicode_string(uint16_t ** buf, size_t * buflen,
+			int idx, const char * str)
 {
-	static pstring fname;
-	fstring path;
-	
-	if ( !dbname )
-		return NULL;
-	
-	fstr_sprintf( path, "%s/%s", PERFCOUNTDIR, dbname );
-	
-	pstrcpy( fname, lock_path( path ) );
-	
-	return fname;
-}
+    UNISTR2 uindex;
+    UNISTR2 ustr;
 
-/*********************************************************************
-*********************************************************************/
+    char	ibuf[16];
+    size_t	nbuflen;
+    uint16_t *	nbuf;
 
-void perfcount_init_keys( void )
+    DEBUG(100, ("appending string \"%s\" at index %d\n",
+		str, idx));
+
+    /* NOTE: Lengths here are in 16-bit quantities. */
+
+    snprintf(ibuf, sizeof(ibuf), "%i", idx);
+    init_unistr2(&uindex, ibuf, UNI_STR_TERMINATE);
+    init_unistr2(&ustr, str, UNI_STR_TERMINATE);
+
+    /* uni_str_len includes the NULL. */
+    nbuflen = *buflen + uindex.uni_str_len + ustr.uni_str_len;
+    if ((nbuf = talloc_realloc(get_talloc_ctx(), *buf,
+				uint16_t, nbuflen)) == NULL) {
+	return(False);
+    }
+
+    memcpy(nbuf + *buflen, uindex.buffer,
+	    uindex.uni_str_len * sizeof(uint16_t));
+    memcpy(nbuf + *buflen + uindex.uni_str_len,
+	    ustr.buffer, ustr.uni_str_len * sizeof(uint16_t));
+
+    talloc_free(uindex.buffer);
+    talloc_free(ustr.buffer);
+
+    *buf = nbuf;
+    *buflen = nbuflen;
+    return(True);
+}
+
+static ssize_t
+get_item_strings(char ** retbuf, index_item_string str)
 {
-	char *p = lock_path(PERFCOUNTDIR);
+    uint16_t *	stringbuf = NULL;
+    uint16_t *	tmp = NULL;
+    size_t	buflen = 0;
 
-	/* no registry keys; just create the perfmon directory */
-	
-	if ( !directory_exist( p, NULL ) )
-		mkdir( p, 0755 );
-	
-	return;
+    int i;
+
+    *retbuf = NULL;
+
+    for (i = 0;
+	 i < talloc_array_elements(p_object_index, struct perf_index);
+	 ++i) {
+
+	if (str(&p_object_index[i]) == NULL) {
+	    continue;
+	}
+
+	if (!append_unicode_string(&stringbuf, &buflen, OBJECT_INDEX_MIN + i,
+				    str(&p_object_index[i]))) {
+	    talloc_free(stringbuf);
+	    return(-1);
+	}
+    }
+
+    /* Allocate space for a double null-terminator. */
+    if ((tmp = talloc_realloc(get_talloc_ctx(), stringbuf,
+				    uint16_t, buflen + 2)) == NULL) {
+	return(-1);
+    }
+
+    stringbuf = tmp;
+    memset(stringbuf + buflen, 0, 2 * sizeof(uint16_t));
+    buflen += 2;
+
+    *retbuf = (char *)stringbuf;
+    return(buflen * sizeof(uint16_t));
 }
 
 /*********************************************************************
 *********************************************************************/
 
-uint32 reg_perfcount_get_base_index(void)
+/* Map PCP metric data types to perfmon data types. */
+static int
+perfmon_metric_size(const pmDesc * desc)
 {
-	const char *fname = counters_directory( NAMES_DB );
-	TDB_CONTEXT *names;
-	TDB_DATA kbuf, dbuf;
-	char key[] = "1";
-	uint32 retval = 0;
-	char buf[PERFCOUNT_MAX_LEN];
+    switch (desc->type)
+    {
+	case PM_TYPE_32:
+	case PM_TYPE_U32:
+	case PM_TYPE_FLOAT:
+	    return(sizeof(uint32_t));
+	case PM_TYPE_64:
+	case PM_TYPE_U64:
+	case PM_TYPE_DOUBLE:
+	    return(sizeof(uint64_t));
+	case PM_TYPE_STRING:
+	    return(-1);
+	default:
+	    /* PM_TYPE_AGGREGATE */
+	    /* PM_TYPE_AGGREGATE_STATIC */
+	    /* PM_TYPE_UNKNOWN */
+	    return(0);
+    }
+}
 
-	names = tdb_open_log(fname, 0, TDB_DEFAULT, O_RDONLY, 0444);
+/* Map a PCP metric semantics type to a perfmon counter semantics type. */
+static int
+perfmon_metric_semantics(const pmDesc * desc)
+{
+    int ptype = 0;
 
-	if ( !names ) {
-		DEBUG(1, ("reg_perfcount_get_base_index: unable to open [%s].\n", fname));
-		return 0;
-	}    
-	/* needs to read the value of key "1" from the counter_names.tdb file, as that is
-	   where the total number of counters is stored. We're assuming no holes in the
-	   enumeration.
-	   The format for the counter_names.tdb file is:
-	   key        value
-	   1          num_counters
-	   2          perf_counter1
-	   3          perf_counter1_help
-	   4          perf_counter2
-	   5          perf_counter2_help
-	   even_num   perf_counter<even_num>
-	   even_num+1 perf_counter<even_num>_help
-	   and so on.
-	   So last_counter becomes num_counters*2, and last_help will be last_counter+1 */
-	kbuf.dptr = key;
-	kbuf.dsize = strlen(key);
-	dbuf = tdb_fetch(names, kbuf);
-	if(dbuf.dptr == NULL)
-	{
-		DEBUG(1, ("reg_perfcount_get_base_index: failed to find key \'1\' in [%s].\n", fname));
-		tdb_close(names);
-		return 0;
+    if (desc->sem == PM_SEM_COUNTER) {
+	ptype |= (PERF_TYPE_COUNTER | PERF_NUMBER_DECIMAL);
+
+	if (desc->units.dimTime < 0) {
+	    ptype |= (PERF_COUNTER_RATE | PERF_OBJECT_TIMER);
 	}
-	else
-	{
-		tdb_close(names);
-		memset(buf, 0, PERFCOUNT_MAX_LEN);
-		memcpy(buf, dbuf.dptr, dbuf.dsize);
-		retval = (uint32)atoi(buf);
-		SAFE_FREE(dbuf.dptr);
-		return retval;
-	}
-	return 0;
+    }
+
+    if (desc->type == PM_TYPE_STRING) {
+	ptype |= (PERF_TYPE_TEXT | PERF_TEXT_ASCII);
+    } else {
+	ptype |= (PERF_TYPE_NUMBER | PERF_COUNTER_VALUE);
+    }
+
+    switch (desc->type) {
+	case PM_TYPE_32:
+	case PM_TYPE_U32:
+	case PM_TYPE_FLOAT:
+	    ptype |= (PERF_SIZE_DWORD);
+	    break;
+	case PM_TYPE_64:
+	case PM_TYPE_U64:
+	case PM_TYPE_DOUBLE:
+	    ptype |= (PERF_SIZE_LARGE);
+	    break;
+	case PM_TYPE_STRING:
+	    ptype |= (PERF_SIZE_VARIABLE_LEN);
+	    break;
+	default:
+	    /* PM_TYPE_AGGREGATE */
+	    /* PM_TYPE_AGGREGATE_STATIC */
+	    /* PM_TYPE_UNKNOWN */
+	    break;
+    }
+
+    return(ptype);
 }
 
 /*********************************************************************
 *********************************************************************/
 
-uint32 reg_perfcount_get_last_counter(uint32 base_index)
+static BOOL
+perfcount_fetch_counter_data(PERF_DATA_BLOCK * block)
 {
-	uint32 retval;
+    pcp_clear_profile();
 
-	if(base_index == 0)
-		retval = 0;
-	else
-		retval = base_index * 2;
+    /* FIXME */
 
-	return retval;
+    return(False);
 }
 
 /*********************************************************************
 *********************************************************************/
 
-uint32 reg_perfcount_get_last_help(uint32 last_counter)
+static BOOL
+perfcount_define_counter_def(const struct perf_metric * pm,
+			     PERF_COUNTER_DEFINITION *  counter)
 {
-	uint32 retval;
+    DEBUG(PERFCOUNT_TRACE,
+	    ("adding PERF_COUNTER_DEFINITION for %s, metric %s\n",
+		pm->name.str, pm->minfo.name));
 
-	if(last_counter == 0)
-		retval = 0;
-	else
-		retval = last_counter + 1;
+    counter->CounterNameTitleIndex = pm->name.index;
+    counter->CounterHelpTitleIndex = pm->help.index;
+    counter->DetailLevel = PERF_DETAIL_NOVICE;
+    counter->ByteLength = PERF_COUNTER_DEFINITION_SZ;
 
-	return retval;
+    counter->DefaultScale = 0; /* No scaling by default. */
+    counter->CounterType = perfmon_metric_semantics(&pm->minfo.desc);
+    counter->CounterSize = perfmon_metric_size(&pm->minfo.desc);
+
+    SMB_ASSERT(IS_ALIGN64(counter->ByteLength));
+    return(True);
 }
 
+static PERF_INSTANCE_DEFINITION *
+perfcount_define_instance(int inum, const char * iname)
+{
+    PERF_INSTANCE_DEFINITION * inst;
 
-/*********************************************************************
-*********************************************************************/
+    if ((inst = talloc_zero(NULL, PERF_INSTANCE_DEFINITION)) == NULL) {
+	return(NULL);
+    }
 
-static uint32 _reg_perfcount_multi_sz_from_tdb(TDB_CONTEXT *tdb, 
-					       int keyval,
-					       char **retbuf,
-					       uint32 buffer_size)
+    DEBUG(PERFCOUNT_TRACE,
+	("adding PERF_INSTANCE_DEFINITION for %s (%d)\n", iname, inum));
+
+    /* We don't implement any concept of instances having parent objects. The
+     * Windows metrics always leave these members unset as well.
+     */
+    inst->ParentObjectTitleIndex = 0;
+    inst->ParentObjectTitlePointer = -1;
+
+    inst->UniqueID = inum;
+
+    /* Attach the instance name at the end of the instance definition. */
+    inst->NameLength = (strlen(iname) * 2) + 2;
+
+    inst->name = talloc_zero_array(inst, uint8_t, inst->NameLength);
+    if (inst->name == NULL) {
+	talloc_free(inst);
+	return(NULL);
+    }
+
+    rpcstr_push(inst->name, iname, inst->NameLength, STR_TERMINATE);
+    return(inst);
+}
+
+static PERF_OBJECT_TYPE *
+perfcount_define_object(struct perf_object * po)
 {
-	TDB_DATA kbuf, dbuf;
-	char temp[256];
-	char *buf1 = *retbuf, *buf2 = NULL;
-	uint32 working_size = 0;
-	UNISTR2 name_index, name;
+    int *	inums = NULL;
+    char **	inames = NULL;
 
-	memset(temp, 0, sizeof(temp));
-	snprintf(temp, sizeof(temp), "%d", keyval);
-	kbuf.dptr = temp;
-	kbuf.dsize = strlen(temp);
-	dbuf = tdb_fetch(tdb, kbuf);
-	if(dbuf.dptr == NULL)
-	{
-		/* If a key isn't there, just bypass it -- this really shouldn't 
-		   happen unless someone's mucking around with the tdb */
-		DEBUG(3, ("_reg_perfcount_multi_sz_from_tdb: failed to find key [%s] in [%s].\n",
-			  temp, tdb->name));
-		return buffer_size;
+    int i;
+
+    PERF_OBJECT_TYPE * o;
+
+    if ((o = talloc_zero(NULL, PERF_OBJECT_TYPE)) == NULL) {
+	return(NULL);
+    }
+
+    DEBUG(PERFCOUNT_TRACE, ("adding PERF_OBJECT_TYPE for %s\n", po->name.str));
+
+    o->ObjectNameTitleIndex = po->name.index;
+    o->ObjectHelpTitleIndex = po->help.index;
+    o->NumCounters = po->mcount;
+    o->DefaultCounter = PERF_NO_DEFAULT_COUNTER;
+
+    /* Make the default object counter time scale per-second. */
+    o->PerfTime = make_uint64_s((uint64_t)time(NULL));
+    o->PerfFreq = make_uint64_s(1);
+
+    o->NumInstances = (po->indom == PM_INDOM_NULL) ? PERF_NO_INSTANCES : 0;
+    o->counters = NULL;
+    o->instances = NULL;
+
+    /* PCP has no equivalent to DetailLevel. */
+    o->DetailLevel = PERF_DETAIL_NOVICE;
+
+    /* Attach the counter definitions. */
+    o->NumCounters = po->mcount;
+    for (i = 0; i < po->mcount; ++i) {
+	if (!perfcount_define_counter_def(&po->metrics[i], &o->counters[i])) {
+	    goto fail;
 	}
-	/* First encode the name_index */
-	working_size = (kbuf.dsize + 1)*sizeof(uint16);
-	buf2 = SMB_REALLOC(buf1, buffer_size + working_size);
-	if(!buf2)
-	{
-		SAFE_FREE(buf1);
-		buffer_size = 0;
-		return buffer_size;
+    }
+
+    if (po->indom != PM_INDOM_NULL) {
+	/* Attach the instance definitions, if there are any. */
+
+	o->NumInstances = pcp_fetch_instance_domain(po->indom, &inums, &inames);
+	if (o->NumInstances < 1) {
+	    goto fail;
 	}
-	buf1 = buf2;
-	init_unistr2(&name_index, kbuf.dptr, UNI_STR_TERMINATE);
-	memcpy(buf1+buffer_size, (char *)name_index.buffer, working_size);
-	buffer_size += working_size;
-	/* Now encode the actual name */
-	working_size = (dbuf.dsize + 1)*sizeof(uint16);
-	buf2 = SMB_REALLOC(buf1, buffer_size + working_size);
-	if(!buf2)
+
+	/* Allocate enough counter values to store all the metric values
+	 * for all the instances.
+	 */
+	o->cvals = talloc_zero_array(o, union counter_value,
+				    o->NumCounters * o->NumInstances);
+	if (o->cvals == NULL) {
+	    goto fail;
+	}
+
+	o->instances = talloc_zero_array(o, PERF_INSTANCE_DEFINITION * ,
+					    o->NumInstances);
+	if (o->instances == NULL) {
+	    goto fail;
+	}
+
+	/* Keep one PERF_INSTANCE_DEFINITION per instance. Each of these will
+	 * have a PERF_COUNTER_BLOCK for each counter value.
+	 */
+	for (i = 0; i < o->NumInstances; i++)
 	{
-		SAFE_FREE(buf1);
-		buffer_size = 0;
-		return buffer_size;
+	    o->instances[i] = perfcount_define_instance(inums[i],inames[i]);
+	    if (o->instances[i] == NULL) {
+		goto fail;
+	    }
+
+	    talloc_steal(o, o->instances[i]);
+
+	    /* Each instance gets a block of NumCounters values. */
+	    o->instances[i]->cvals =
+			    o->cvals + (o->NumCounters * i);
 	}
-	buf1 = buf2;
-	memset(temp, 0, sizeof(temp));
-	memcpy(temp, dbuf.dptr, dbuf.dsize);
-	SAFE_FREE(dbuf.dptr);
-	init_unistr2(&name, temp, UNI_STR_TERMINATE);
-	memcpy(buf1+buffer_size, (char *)name.buffer, working_size);
-	buffer_size += working_size;
 
-	*retbuf = buf1;
+    } else {
+	/* No instances, so allocate space for the counter data. */
+	SMB_ASSERT(po->indom == PM_INDOM_NULL);
 
-	return buffer_size;
+	o->cvals = talloc_zero_array(o, union counter_value,
+					    o->NumInstances);
+	if (o->cvals == NULL) {
+	    goto fail;
+	}
+
+	for (i = 0; i < o->NumCounters; ++i) {
+	    o->counters[i].cvals = o->cvals + i;
+	}
+    }
+
+    SAFE_FREE(inums);
+    SAFE_FREE(inames);
+    return(o);
+
+fail:
+    talloc_free(0);
+    SAFE_FREE(inums);
+    SAFE_FREE(inames);
+    return(NULL);
 }
 
+
 /*********************************************************************
 *********************************************************************/
 
-uint32 reg_perfcount_get_counter_help(uint32 base_index, char **retbuf)
+static PERF_DATA_BLOCK *
+perfcount_define_data_block(prs_struct * ps)
 {
-	char *buf1 = NULL, *buf2 = NULL;
-	uint32 buffer_size = 0;
-	TDB_CONTEXT *names;
-	const char *fname = counters_directory( NAMES_DB );
-	int i;
+    PERF_DATA_BLOCK * block;
+    time_t tm;
 
-	if(base_index == 0)
-		return 0;
+    if ((block = talloc_zero(NULL, PERF_DATA_BLOCK)) == NULL) {
+	return(NULL);
+    }
 
-	names = tdb_open_log(fname, 0, TDB_DEFAULT, O_RDONLY, 0444);
+    rpcstr_push(block->Signature, "PERF", sizeof(block->Signature), 0);
+    block->LittleEndian = (ps->bigendian_data == RPC_BIG_ENDIAN) ? 0 : 1;
+    block->Version = (SAMBA_VERSION_MAJOR) * 10 + SAMBA_VERSION_MINOR;
+    block->Revision = SAMBA_VERSION_RELEASE;
+    block->TotalByteLength = 0;
+    block->NumObjectTypes = 0;
+    block->DefaultObject = -1;
+    block->objects = NULL;
 
-	if(names == NULL)
-	{
-		DEBUG(1, ("reg_perfcount_get_counter_help: unable to open [%s].\n", fname));
-		return 0;
-	}    
+    tm = time(NULL);
+    make_systemtime(&(block->SystemTime), gmtime(&tm));
 
-	for(i = 1; i <= base_index; i++)
-	{
-		buffer_size = _reg_perfcount_multi_sz_from_tdb(names, (i*2)+1, retbuf, buffer_size);
-	}
-	tdb_close(names);
+    /* FIXME: define this such that rate counters are per-second. */
+    block->PerfFreq = make_uint64_s(1);
+    block->PerfTime = make_uint64_s(1);
+    block->PerfTime100nSec = make_uint64_s(1);
 
-	/* Now terminate the MULTI_SZ with a double unicode NULL */
-	buf1 = *retbuf;
-	buf2 = SMB_REALLOC(buf1, buffer_size + 2);
-	if(!buf2)
-	{
-		SAFE_FREE(buf1);
-		buffer_size = 0;
-	}
-	else
-	{
-		buf1 = buf2;
-		buf1[buffer_size++] = '\0';
-		buf1[buffer_size++] = '\0';
-	}
+    block->SystemNameLength = (strlen(global_myname()) * 2) + 2;
 
-	*retbuf = buf1;
+    block->sysname = talloc_zero_array(block, uint8_t, block->SystemNameLength);
+    if (block->sysname == NULL) {
+	talloc_free(block);
+	return(NULL);
+    }
 
-	return buffer_size;
+    return(block);
 }
 
 /*********************************************************************
 *********************************************************************/
 
-uint32 reg_perfcount_get_counter_names(uint32 base_index, char **retbuf)
+static PERF_DATA_BLOCK *
+perfcount_fetch_objects(prs_struct *ps, const char * object_ids)
 {
-	char *buf1 = NULL, *buf2 = NULL;
-	uint32 buffer_size = 0;
-	TDB_CONTEXT *names;
-	const char *fname = counters_directory( NAMES_DB );
-	int i;
+    PERF_DATA_BLOCK * block;
 
-	if(base_index == 0)
-		return 0;
+    if ((block = perfcount_define_data_block(ps)) == NULL) {
+	return(NULL);
+    }
 
-	names = tdb_open_log(fname, 0, TDB_DEFAULT, O_RDONLY, 0444);
+    if (object_ids == NULL)
+    {
+	struct perf_object ** po;
+	int i;
 
-	if(names == NULL)
-	{
-		DEBUG(1, ("reg_perfcount_get_counter_names: unable to open [%s].\n", fname));
-		return 0;
-	}    
+	/* we're getting a request for "Global" here */
+	DEBUG(PERFCOUNT_TRACE, ("all perfmon objects requested\n"));
 
-	buffer_size = _reg_perfcount_multi_sz_from_tdb(names, 1, retbuf, buffer_size);
+	for (po = p_object_list; *po; ++po) {
+	    block->NumObjectTypes++;
+	}
 
-	for(i = 1; i <= base_index; i++)
-	{
-		buffer_size = _reg_perfcount_multi_sz_from_tdb(names, i*2, retbuf, buffer_size);
+	block->objects = talloc_zero_array(block, PERF_OBJECT_TYPE *,
+					    block->NumObjectTypes);
+	if (block->objects == NULL) {
+	    talloc_free(block);
+	    return(NULL);
 	}
-	tdb_close(names);
 
-	/* Now terminate the MULTI_SZ with a double unicode NULL */
-	buf1 = *retbuf;
-	buf2 = SMB_REALLOC(buf1, buffer_size + 2);
-	if(!buf2)
-	{
-		SAFE_FREE(buf1);
-		buffer_size = 0;
+	for (i = 0, po = p_object_list; *po; ++po, ++i) {
+	    if ((block->objects[i] = perfcount_define_object(*po))) {
+		talloc_steal(block, block->objects[i]);
+	    } else {
+		/* block->objects[i] == NULL */
+		talloc_free(block);
+		return(NULL);
+	    }
 	}
-	else
-	{
-		buf1 = buf2;
-		buf1[buffer_size++] = '\0';
-		buf1[buffer_size++] = '\0';
-	}
 
-	*retbuf=buf1;
+	return(block);
+    } else {
+	/* request for a specific set of PERF_OBJECT_TYPES */
+	char tok[16];
 
-	return buffer_size;
-}
+	DEBUG(PERFCOUNT_TRACE, ("perfmon objects %s requested\n", object_ids));
 
-/*********************************************************************
-*********************************************************************/
+	while (next_token_nr(&object_ids, tok, " \t", sizeof(tok))) {
+	    int	idx;
+	    struct perf_object * po;
 
-static void _reg_perfcount_make_key(TDB_DATA *key,
-				    char *buf,
-				    int buflen,
-				    int key_part1,
-				    const char *key_part2)
-{
-	memset(buf, 0, buflen);
-	if(key_part2 != NULL)
-		snprintf(buf, buflen,"%d%s", key_part1, key_part2);
-	else 
-		snprintf(buf, buflen, "%d", key_part1);
+	    idx = atoi(tok);
+	    if (idx < 0) {
+		DEBUG(0, ("invalid perfmon object ID: %s\n", tok));
+		talloc_free(block);
+		return(NULL);
+	    }
 
-	key->dptr = buf;
-	key->dsize = strlen(buf);
+	    if (idx < OBJECT_INDEX_MIN || idx >= OBJECT_INDEX_MAX) {
+		DEBUG(0, ("no such perfmon object ID: %d\n", idx));
+		talloc_free(block);
+		return(NULL);
+	    }
 
-	return;
-}
+	    if ((po = p_object_index[idx - OBJECT_INDEX_MIN].perf) == NULL) {
+		DEBUG(0, ("missing perfmon object for ID %d\n", idx));
+		talloc_free(block);
+		return(NULL);
+	    }
 
-/*********************************************************************
-*********************************************************************/
+	    block->NumObjectTypes++;
+	    block->objects = talloc_realloc(block, block->objects,
+				PERF_OBJECT_TYPE *, block->NumObjectTypes);
+	    if (block->objects == NULL) {
+		/* This can't leak because talloc trace the old reference
+		 * for us.
+		 */
+		talloc_free(block);
+		return(NULL);
+	    }
 
-static BOOL _reg_perfcount_isparent(TDB_DATA data)
-{
-	if(data.dsize > 0)
-	{
-		if(data.dptr[0] == 'p')
-			return True;
-		else
-			return False;
+	    if ((block->objects[block->NumObjectTypes - 1] =
+					    perfcount_define_object(po))) {
+		talloc_steal(block, block->objects[block->NumObjectTypes - 1]);
+	    } else {
+		/* block->objects[block->NumObjectTypes - 1] == NULL */
+		talloc_free(block);
+		return(NULL);
+	    }
 	}
-	return False;
+
+	return (block);
+    }
 }
 
 /*********************************************************************
 *********************************************************************/
 
-static BOOL _reg_perfcount_ischild(TDB_DATA data)
+static ssize_t
+perfcount_size_counter_block(PERF_COUNTER_DEFINITION *	cdef,
+			     PERF_COUNTER_BLOCK *	cblock,
+			     unsigned			cnum)
 {
-	if(data.dsize > 0)
-	{
-		if(data.dptr[0] == 'c')
-			return True;
-		else
-			return False;
+    int c;
+
+    /* ByteLength: the size of the PERF_COUNTER_BLOCK structure plus the sizes
+     * of the data for each counter. We also account for any padding necessary
+     * to force alignment.
+     */
+    cblock->ByteLength = PERF_COUNTER_BLOCK_SZ;
+
+    for (c = 0; c < cnum; ++c) {
+
+	if (cdef->CounterType & PERF_SIZE_LARGE) {
+	    /* Make sure a LARGE_INTEGER is 64-bit aligned. */
+	    cdef->CounterOffset = ALIGN64(cblock->ByteLength);
+	    cblock->ByteLength += ALIGN64(cblock->ByteLength);
+	} else if (cdef->CounterType & PERF_SIZE_DWORD) {
+	    /* DWORDS should be 32-bit aligned. */
+	    cdef->CounterOffset = ALIGN32(cblock->ByteLength);
+	    cblock->ByteLength += ALIGN32(cblock->ByteLength);
+	} else {
+	    SMB_ASSERT(cdef->CounterType & PERF_SIZE_VARIABLE_LEN);
+	    cdef->CounterOffset = cblock->ByteLength;
 	}
-	return False;
+
+	cblock->ByteLength += cdef->CounterSize;
+    }
+
+    /* Make sure the next structure will be 64-bit aligned. */
+    cblock->ByteLength = ALIGN64(cblock->ByteLength);
+    return(cblock->ByteLength);
 }
 
-/*********************************************************************
-*********************************************************************/
+static ssize_t
+perfcount_size_instance_def(PERF_INSTANCE_DEFINITION * i)
+{
+    /* ByteLength: the number of bytes in the PERF_INSTANCE_DEFINITION
+     * structure plus the size of the instance name plus padding to the next
+     * 64-bit boundary.
+     */
+    i->NameOffset = i->ByteLength = PERF_INSTANCE_DEFINITION_SZ;
+    i->ByteLength += i->NameLength;
+    i->ByteLength = ALIGN64(i->ByteLength);
 
-static uint32 _reg_perfcount_get_numinst(int objInd, TDB_CONTEXT *names)
+    return(i->ByteLength);
+}
+
+static ssize_t
+perfcount_size_object_type(PERF_OBJECT_TYPE * o)
 {
-	TDB_DATA key, data;
-	char buf[PERFCOUNT_MAX_LEN];
+    /* HeaderLength: The number of bytes in the PERF_OBJECT_TYPE plus any
+     * necessary padding.
+     */
+    o->HeaderLength = ALIGN64(PERF_OBJECT_TYPE_SZ);
 
-	_reg_perfcount_make_key(&key, buf, PERFCOUNT_MAX_LEN, objInd, "inst");
-	data = tdb_fetch(names, key);
+    /* DefinitionLength: The number of bytes in the PERF_OBJECT_TYPE plus any
+     * necessary padding, plus the size of all the PERF_COUNTER_DEFINITION
+     * structures. If the object has instances, they are not accounted for in
+     * this length, otherwise (char *)PERF_OBJECT_TYPE + DefinitionLength
+     * should take you to the PERF_COUNTER_BLOCK struture.
+     */
+    o->DefinitionLength = o->HeaderLength
+			    + (o->NumCounters * PERF_COUNTER_DEFINITION_SZ);
 
-	if(data.dptr == NULL)
-		return (uint32)PERF_NO_INSTANCES;
-    
-	memset(buf, 0, PERFCOUNT_MAX_LEN);
-	memcpy(buf, data.dptr, data.dsize);
-	return (uint32)atoi(buf);
-}
+    SMB_ASSERT(IS_ALIGN64(PERF_COUNTER_DEFINITION_SZ));
+    SMB_ASSERT(o->NumInstances != 0);
 
-/*********************************************************************
-*********************************************************************/
+    /* TotalByteLength: The number of bytes from the start of this object to
+     * the start of the next one. This includes all the counter defintions,
+     * instance definitions and counter data.
+     */
+    o->TotalByteLength = o->DefinitionLength;
 
-static BOOL _reg_perfcount_add_object(PERF_DATA_BLOCK *block,
-				      prs_struct *ps,
-				      int num,
-				      TDB_DATA data,
-				      TDB_CONTEXT *names)
-{
+    if (o->NumInstances != PERF_NO_INSTANCES) {
 	int i;
-	BOOL success = False;
-	PERF_OBJECT_TYPE *obj;
 
-	block->objects = (PERF_OBJECT_TYPE *)TALLOC_REALLOC_ARRAY(ps->mem_ctx,
-								  block->objects,
-								  PERF_OBJECT_TYPE,
-								  block->NumObjectTypes+1);
-	if(block->objects == NULL)
-		return False;
-	obj = &(block->objects[block->NumObjectTypes]);
-	memset((void *)&(block->objects[block->NumObjectTypes]), 0, sizeof(PERF_OBJECT_TYPE));
-	block->objects[block->NumObjectTypes].ObjectNameTitleIndex = num;
-	block->objects[block->NumObjectTypes].ObjectNameTitlePointer = 0;
-	block->objects[block->NumObjectTypes].ObjectHelpTitleIndex = num+1;
-	block->objects[block->NumObjectTypes].ObjectHelpTitlePointer = 0;
-	block->objects[block->NumObjectTypes].NumCounters = 0;
-	block->objects[block->NumObjectTypes].DefaultCounter = 0;
-	block->objects[block->NumObjectTypes].NumInstances = _reg_perfcount_get_numinst(num, names);
-	block->objects[block->NumObjectTypes].counters = NULL;
-	block->objects[block->NumObjectTypes].instances = NULL;
-	block->objects[block->NumObjectTypes].counter_data.ByteLength = sizeof(uint32);
-	block->objects[block->NumObjectTypes].counter_data.data = NULL;
-	block->objects[block->NumObjectTypes].DetailLevel = PERF_DETAIL_NOVICE;
-	block->NumObjectTypes+=1;
+	for (i = 0; i < o->NumInstances; ++i) {
+	    o->TotalByteLength += perfcount_size_instance_def(o->instances[i]);
 
-	for(i = 0; i < (int)obj->NumInstances; i++)
-	{
-		success = _reg_perfcount_add_instance(obj, ps, i, names);
+	    /* FIXME: This updates the counter definition offsets multiple
+	     * times which is unfortunate, but we need to update the counter
+	     * block for all instances.
+	     */
+	    o->TotalByteLength += perfcount_size_counter_block(o->counters,
+					     &o->instances[i]->cblock,
+					     o->NumCounters);
 	}
+    } else {
+	o->TotalByteLength += perfcount_size_counter_block(o->counters,
+					     &o->cblock,
+					     o->NumCounters);
+    }
 
-	return True;
+    /* Make sure the next structure will be 64-bit aligned. */
+    o->TotalByteLength = ALIGN64(o->TotalByteLength);
+    return(o->TotalByteLength);
 }
 
-/*********************************************************************
-*********************************************************************/
-
-BOOL _reg_perfcount_get_counter_data(TDB_DATA key, TDB_DATA *data)
+/* Calculate the marshaled size of the block in bytes. Update byte offset
+ * structure members as necessary.
+ */
+static ssize_t
+perfcount_size_data_block(PERF_DATA_BLOCK * block)
 {
-	TDB_CONTEXT *counters;
-	const char *fname = counters_directory( DATA_DB );
-    
-	counters = tdb_open_log(fname, 0, TDB_DEFAULT, O_RDONLY, 0444);
+    int o;
 
-	if(counters == NULL)
-	{
-		DEBUG(1, ("reg_perfcount_get_counter_data: unable to open [%s].\n", fname));
-		return False;
-	}    
+    block->HeaderLength = block->SystemNameOffset = PERF_DATA_BLOCK_SZ;
+    block->HeaderLength += block->SystemNameLength;
 
-	*data = tdb_fetch(counters, key);
-    
-	tdb_close(counters);
+    block->HeaderLength = ALIGN64(block->HeaderLength);
+    block->TotalByteLength = block->HeaderLength;
 
-	return True;
+    for(o = 0; o < block->NumObjectTypes; ++o) {
+	block->TotalByteLength +=
+		perfcount_size_object_type(block->objects[o]);
+    }
+
+    SMB_ASSERT(IS_ALIGN64(block->TotalByteLength));
+    return(block->TotalByteLength);
 }
 
 /*********************************************************************
+ * MARSHALLING RULES:
+ *
+ * 1. 64-bit fields inside data structures must be aligned on 8-byte
+ * boundaries.
+ * 2. All structures are aligned to start on 8-byte boundaries.
+ *
 *********************************************************************/
 
-static uint32 _reg_perfcount_get_size_field(uint32 CounterType)
+/* Pad the stream out to the boundary given by start+size. */
+static BOOL
+marshall_padding(prs_struct * ps, uint32_t start, uint32_t size)
 {
-	uint32 retval;
+    uint32_t remain;
 
-	retval = CounterType;
+    /* Check for offset wrap. */
+    SMB_ASSERT((start + size) >= start);
 
-	/* First mask out reserved lower 8 bits */
-	retval = retval & 0xFFFFFF00;
-	retval = retval << 22;
-	retval = retval >> 22;
+    remain = (start + size) - size;
+    if (remain) {
+	return prs_grow(ps, remain);
+    }
 
-	return retval;
+    return True;
 }
 
-/*********************************************************************
-*********************************************************************/
-
-static uint32 _reg_perfcount_compute_scale(SMB_BIG_INT data)
+static BOOL
+marshall_counter_block(prs_struct *		    ps, 
+		       PERF_COUNTER_BLOCK *	    cblock, 
+		       PERF_COUNTER_DEFINITION *    cdefs,
+		       union counter_value *	    cvals,
+		       int			    cnum,
+		       int depth)
 {
-	int scale = 0;
-	if(data == 0)
-		return scale;
-	while(data > 100)
-	{
-		data /= 10;
-		scale--;
-	}
-	while(data < 10)
-	{
-		data *= 10;
-		scale++;
-	}
+    int		i;
+    uint32_t	start;
 
-	return (uint32)scale;
-}
+    prs_debug(ps, depth, "", "marshall_counter_block");
+    depth++;
 
-/*********************************************************************
-*********************************************************************/
+    SMB_ASSERT(IS_ALIGN64(ps->data_offset));
+    start = ps->data_offset;
 
-static BOOL _reg_perfcount_get_counter_info(PERF_DATA_BLOCK *block,
-					    prs_struct *ps,
-					    int CounterIndex,
-					    PERF_OBJECT_TYPE *obj,
-					    TDB_CONTEXT *names)
-{
-	TDB_DATA key, data;
-	char buf[PERFCOUNT_MAX_LEN];
-	size_t dsize, padding;
-	long int data32, dbuf[2];
-	SMB_BIG_INT data64;
-	uint32 counter_size;
+    if(!prs_uint32("ByteLength", ps, depth, &cblock->ByteLength)) {
+	return False;
+    }
 
-	obj->counters[obj->NumCounters].DefaultScale = 0;
-	dbuf[0] = dbuf[1] = 0;
-	padding = 0;
+    for (i = 0; i < cnum; ++i) {
 
-	_reg_perfcount_make_key(&key, buf, PERFCOUNT_MAX_LEN, CounterIndex, "type");
-	data = tdb_fetch(names, key);
-	if(data.dptr == NULL)
-	{
-		DEBUG(3, ("_reg_perfcount_get_counter_info: No type data for counter [%d].\n", CounterIndex));
+	if (cdefs[i].CounterType & PERF_SIZE_LARGE) {
+	    UINT64_S val64;
+
+	    SMB_ASSERT(cdefs[i].CounterSize == 8);
+	    val64 = make_uint64_s(cvals[i].large_val);
+
+	    if(!prs_align_uint64(ps))
 		return False;
-	}
-	memset(buf, 0, PERFCOUNT_MAX_LEN);
-	memcpy(buf, data.dptr, data.dsize);
-	obj->counters[obj->NumCounters].CounterType = atoi(buf);
-	DEBUG(10, ("_reg_perfcount_get_counter_info: Got type [%d] for counter [%d].\n",
-		   obj->counters[obj->NumCounters].CounterType, CounterIndex));
-	free(data.dptr);
+	    if(!prs_uint64("CounterData64", ps, depth, &val64))
+		return False;
 
-	/* Fetch the actual data */
-	_reg_perfcount_make_key(&key, buf, PERFCOUNT_MAX_LEN, CounterIndex, "");
-	_reg_perfcount_get_counter_data(key, &data);
-	if(data.dptr == NULL)
-	{
-		DEBUG(3, ("_reg_perfcount_get_counter_info: No counter data for counter [%d].\n", CounterIndex));
+	} else if (cdefs[i].CounterType & PERF_SIZE_DWORD) {
+	    SMB_ASSERT(cdefs[i].CounterSize == 4);
+
+	    if(!prs_align_uint32(ps))
 		return False;
-	}
-    
-	counter_size = _reg_perfcount_get_size_field(obj->counters[obj->NumCounters].CounterType);
+	    if(!prs_uint32("CounterData32", ps, depth, &cvals[i].dword_val))
+		return False;
 
-	if(counter_size == PERF_SIZE_DWORD)
-	{
-		dsize = sizeof(data32);
-		memset(buf, 0, PERFCOUNT_MAX_LEN);
-		memcpy(buf, data.dptr, data.dsize);
-		data32 = strtol(buf, NULL, 0);
-		if((obj->counters[obj->NumCounters].CounterType & 0x00000F00) == PERF_TYPE_NUMBER)
-			obj->counters[obj->NumCounters].DefaultScale = _reg_perfcount_compute_scale((SMB_BIG_INT)data32);
-		else
-			obj->counters[obj->NumCounters].DefaultScale = 0;
-		dbuf[0] = data32;
-		padding = (dsize - (obj->counter_data.ByteLength%dsize)) % dsize;
-	}
-	else if(counter_size == PERF_SIZE_LARGE)
-	{
-		dsize = sizeof(data64);
-		memset(buf, 0, PERFCOUNT_MAX_LEN);
-		memcpy(buf, data.dptr, data.dsize);
-		data64 = atof(buf);
-		if((obj->counters[obj->NumCounters].CounterType & 0x00000F00) == PERF_TYPE_NUMBER)
-			obj->counters[obj->NumCounters].DefaultScale = _reg_perfcount_compute_scale(data64);
-		else
-			obj->counters[obj->NumCounters].DefaultScale = 0;
-		memcpy((void *)dbuf, (const void *)&data64, dsize);
-		padding = (dsize - (obj->counter_data.ByteLength%dsize)) % dsize;
-	}
-	else /* PERF_SIZE_VARIABLE_LEN */
-	{
-		dsize = data.dsize;
-		memset(buf, 0, PERFCOUNT_MAX_LEN);
-		memcpy(buf, data.dptr, data.dsize);
-	}
-	free(data.dptr);
+	} else {
+	    SMB_ASSERT(cdefs[i].CounterType & PERF_SIZE_VARIABLE_LEN);
 
-	obj->counter_data.ByteLength += dsize + padding;
-	obj->counter_data.data = TALLOC_REALLOC_ARRAY(ps->mem_ctx,
-						      obj->counter_data.data,
-						      uint8,
-						      obj->counter_data.ByteLength - sizeof(uint32));
-	if(obj->counter_data.data == NULL)
+	    if(!prs_uint8s(False, "CounterDataVarLen", ps, depth,
+			cvals[i].varlen_val, cdefs[i].CounterSize)) {
 		return False;
-	if(dbuf[0] != 0 || dbuf[1] != 0)
-	{
-		memcpy((void *)(obj->counter_data.data + 
-				(obj->counter_data.ByteLength - (sizeof(uint32) + dsize))), 
-		       (const void *)dbuf, dsize);
+	    }
 	}
-	else
-	{
-		/* Handling PERF_SIZE_VARIABLE_LEN */
-		memcpy((void *)(obj->counter_data.data +
-				(obj->counter_data.ByteLength - (sizeof(uint32) + dsize))),
-		       (const void *)buf, dsize);
-	}
-	obj->counters[obj->NumCounters].CounterOffset = obj->counter_data.ByteLength - dsize;
-	if(obj->counters[obj->NumCounters].CounterOffset % dsize != 0)
-	{
-		DEBUG(3,("Improperly aligned counter [%d]\n", obj->NumCounters));
-	}
-	obj->counters[obj->NumCounters].CounterSize = dsize;
 
-	return True;
-}
+    }
 
-/*********************************************************************
-*********************************************************************/
+    if (!marshall_padding(ps, start, cblock->ByteLength))
+	return False;
 
-PERF_OBJECT_TYPE *_reg_perfcount_find_obj(PERF_DATA_BLOCK *block, int objind)
+    SMB_ASSERT(IS_ALIGN64(ps->data_offset));
+    return True;
+}
+
+static BOOL
+marshall_instance_defs(prs_struct * ps, PERF_OBJECT_TYPE * object, int depth)
 {
-	int i;
+    PERF_INSTANCE_DEFINITION  * instance;
+    int inst;
 
-	PERF_OBJECT_TYPE *obj = NULL;
+    prs_debug(ps, depth, "", "marshall_instance_defs");
+    depth++;
 
-	for(i = 0; i < block->NumObjectTypes; i++)
-	{
-		if(block->objects[i].ObjectNameTitleIndex == objind)
-		{
-			obj = &(block->objects[i]);
-		}
-	}
+    for(inst = 0; inst < object->NumInstances; inst++) {
+	uint32_t start;
 
-	return obj;
-}
+	instance = object->instances[inst];
 
-/*********************************************************************
-*********************************************************************/
+	SMB_ASSERT(IS_ALIGN64(ps->data_offset));
+	start = ps->data_offset;
 
-static BOOL _reg_perfcount_add_counter(PERF_DATA_BLOCK *block,
-				       prs_struct *ps,
-				       int num,
-				       TDB_DATA data,
-				       TDB_CONTEXT *names)
-{
-	char *begin, *end, *start, *stop;
-	int parent;
-	PERF_OBJECT_TYPE *obj;
-	BOOL success = False;
-	char buf[PERFCOUNT_MAX_LEN];
-    
-	obj = NULL;
-	memset(buf, 0, PERFCOUNT_MAX_LEN);
-	memcpy(buf, data.dptr, data.dsize);
-	begin = index(buf, '[');
-	end = index(buf, ']');
-	if(begin == NULL || end == NULL)
-		return False;
-	start = begin+1;
+	if(!prs_uint32("ByteLength", ps, depth, &instance->ByteLength))
+	    return False;
+	if(!prs_uint32("ParentObjectTitleIndex", ps, depth, &instance->ParentObjectTitleIndex))
+	    return False;
+	if(!prs_uint32("ParentObjectTitlePointer", ps, depth, &instance->ParentObjectTitlePointer))
+	    return False;
+	if(!prs_uint32("UniqueID", ps, depth, &instance->UniqueID))
+	    return False;
+	if(!prs_uint32("NameOffset", ps, depth, &instance->NameOffset))
+	    return False;
+	if(!prs_uint32("NameLength", ps, depth, &instance->NameLength))
+	    return False;
+	if(!prs_uint8s(False, "InstanceName", ps, depth, instance->name,
+		       instance->NameLength))
+	    return False;
 
-	while(start < end)
-	{
-		stop = index(start, ',');
-		if(stop == NULL)
-			stop = end;
-		*stop = '\0';
-		parent = atoi(start);
+	if (!marshall_padding(ps, start, instance->ByteLength))
+	    return False;
 
-		obj = _reg_perfcount_find_obj(block, parent);
-		if(obj == NULL)
-		{
-			/* At this point we require that the parent object exist.
-			   This can probably be handled better at some later time */
-			DEBUG(3, ("_reg_perfcount_add_counter: Could not find parent object [%d] for counter [%d].\n",
-				  parent, num));
-			return False;
-		}
-		obj->counters = (PERF_COUNTER_DEFINITION *)TALLOC_REALLOC_ARRAY(ps->mem_ctx,
-										obj->counters,
-										PERF_COUNTER_DEFINITION,
-										obj->NumCounters+1);
-		if(obj->counters == NULL)
-			return False;
-		memset((void *)&(obj->counters[obj->NumCounters]), 0, sizeof(PERF_COUNTER_DEFINITION));
-		obj->counters[obj->NumCounters].CounterNameTitleIndex=num;
-		obj->counters[obj->NumCounters].CounterHelpTitleIndex=num+1;
-		obj->counters[obj->NumCounters].DetailLevel = PERF_DETAIL_NOVICE;
-		obj->counters[obj->NumCounters].ByteLength = sizeof(PERF_COUNTER_DEFINITION);
-		success = _reg_perfcount_get_counter_info(block, ps, num, obj, names);
-		obj->NumCounters += 1;
-		start = stop + 1;
+	if(!marshall_counter_block(ps, &instance->cblock, object->counters,
+		    instance->cvals, object->NumCounters, depth)) {
+	    return False;
 	}
-    	
-	/* Handle case of Objects/Counters without any counter data, which would suggest
-	   that the required instances are not there yet, so change NumInstances from
-	   PERF_NO_INSTANCES to 0 */
+    }
 
-	return True;
+    SMB_ASSERT(IS_ALIGN64(ps->data_offset));
+    return True;
 }
 
-/*********************************************************************
-*********************************************************************/
-
-BOOL _reg_perfcount_get_instance_info(PERF_INSTANCE_DEFINITION *inst,
-				      prs_struct *ps,
-				      int instId,
-				      PERF_OBJECT_TYPE *obj,
-				      TDB_CONTEXT *names)
+static BOOL
+marshall_counter_defs(prs_struct *		ps,
+		      PERF_COUNTER_DEFINITION * counters,
+		      unsigned			cnum,
+		      int			depth)
 {
-	TDB_DATA key, data;
-	char buf[PERFCOUNT_MAX_LEN], temp[PERFCOUNT_MAX_LEN];
-	wpstring name;
-	int pad;
+    int cnt;
 
-	/* First grab the instance data from the data file */
-	memset(temp, 0, PERFCOUNT_MAX_LEN);
-	snprintf(temp, PERFCOUNT_MAX_LEN, "i%d", instId);
-	_reg_perfcount_make_key(&key, buf, PERFCOUNT_MAX_LEN, obj->ObjectNameTitleIndex, temp);
-	_reg_perfcount_get_counter_data(key, &data);
-	if(data.dptr == NULL)
-	{
-		DEBUG(3, ("_reg_perfcount_get_instance_info: No instance data for instance [%s].\n",
-			  buf));
-		return False;
-	}
-	inst->counter_data.ByteLength = data.dsize + sizeof(inst->counter_data.ByteLength);
-	inst->counter_data.data = TALLOC_REALLOC_ARRAY(ps->mem_ctx,
-						       inst->counter_data.data,
-						       uint8,
-						       data.dsize);
-	if(inst->counter_data.data == NULL)
-		return False;
-	memset(inst->counter_data.data, 0, data.dsize);
-	memcpy(inst->counter_data.data, data.dptr, data.dsize);
-	free(data.dptr);
+    prs_debug(ps, depth, "", "marshall_counter_defs");
+    depth++;
 
-	/* Fetch instance name */
-	memset(temp, 0, PERFCOUNT_MAX_LEN);
-	snprintf(temp, PERFCOUNT_MAX_LEN, "i%dname", instId);
-	_reg_perfcount_make_key(&key, buf, PERFCOUNT_MAX_LEN, obj->ObjectNameTitleIndex, temp);
-	data = tdb_fetch(names, key);
-	if(data.dptr == NULL)
-	{
-		/* Not actually an error, but possibly unintended? -- just logging FYI */
-		DEBUG(3, ("_reg_perfcount_get_instance_info: No instance name for instance [%s].\n",
-			  buf));
-		inst->NameLength = 0;
-	}
-	else
-	{
-		memset(buf, 0, PERFCOUNT_MAX_LEN);
-		memcpy(buf, data.dptr, data.dsize);
-		rpcstr_push((void *)name, buf, sizeof(name), STR_TERMINATE);
-		inst->NameLength = (strlen_w(name) * 2) + 2;
-		inst->data = TALLOC_REALLOC_ARRAY(ps->mem_ctx,
-						  inst->data,
-						  uint8,
-						  inst->NameLength);
-		memcpy(inst->data, name, inst->NameLength);
-		free(data.dptr);
-	}
+    for(cnt = 0; cnt < cnum; cnt++)
+    {
+	uint32_t start;
+	PERF_COUNTER_DEFINITION * counter;
 
-	inst->ParentObjectTitleIndex = 0;
-	inst->ParentObjectTitlePointer = 0;
-	inst->UniqueID = PERF_NO_UNIQUE_ID;
-	inst->NameOffset = 6 * sizeof(uint32);
-    
-	inst->ByteLength = inst->NameOffset + inst->NameLength;
-	/* Need to be aligned on a 64-bit boundary here for counter_data */
-	if((pad = (inst->ByteLength % 8)))
-	{
-		pad = 8 - pad;
-		inst->data = TALLOC_REALLOC_ARRAY(ps->mem_ctx,
-						  inst->data,
-						  uint8,
-						  inst->NameLength + pad);
-		memset(inst->data + inst->NameLength, 0, pad);
-		inst->ByteLength += pad;
-	}
+	counter = &counters[cnt];
 
-	return True;
-}
+	SMB_ASSERT(IS_ALIGN64(ps->data_offset));
+	start = ps->data_offset;
 
-/*********************************************************************
-*********************************************************************/
+	if(!prs_uint32("ByteLength", ps, depth, &counter->ByteLength))
+	    return False;
+	if(!prs_uint32("CounterNameTitleIndex", ps, depth, &counter->CounterNameTitleIndex))
+	    return False;
+	if(!prs_uint32("CounterNameTitlePointer", ps, depth, &counter->CounterNameTitlePointer))
+	    return False;
+	if(!prs_uint32("CounterHelpTitleIndex", ps, depth, &counter->CounterHelpTitleIndex))
+	    return False;
+	if(!prs_uint32("CounterHelpTitlePointer", ps, depth, &counter->CounterHelpTitlePointer))
+	    return False;
+	if(!prs_uint32("DefaultScale", ps, depth, &counter->DefaultScale))
+	    return False;
+	if(!prs_uint32("DetailLevel", ps, depth, &counter->DetailLevel))
+	    return False;
+	if(!prs_uint32("CounterType", ps, depth, &counter->CounterType))
+	    return False;
+	if(!prs_uint32("CounterSize", ps, depth, &counter->CounterSize))
+	    return False;
+	if(!prs_uint32("CounterOffset", ps, depth, &counter->CounterOffset))
+	    return False;
 
-BOOL _reg_perfcount_add_instance(PERF_OBJECT_TYPE *obj,
-				 prs_struct *ps,
-				 int instInd,
-				 TDB_CONTEXT *names)
-{
-	BOOL success;
-	PERF_INSTANCE_DEFINITION *inst;
+	if (!marshall_padding(ps, start, counter->ByteLength))
+	    return False;
+    }
 
-	success = False;
-
-	if(obj->instances == NULL)
-	{
-		obj->instances = TALLOC_REALLOC_ARRAY(ps->mem_ctx, 
-						      obj->instances,
-						      PERF_INSTANCE_DEFINITION,
-						      obj->NumInstances);
-	}
-	if(obj->instances == NULL)
-		return False;
-    
-	memset(&(obj->instances[instInd]), 0, sizeof(PERF_INSTANCE_DEFINITION));
-	inst = &(obj->instances[instInd]);
-	success = _reg_perfcount_get_instance_info(inst, ps, instInd, obj, names);
-    
-	return True;
+    SMB_ASSERT(IS_ALIGN64(ps->data_offset));
+    return True;
 }
 
-/*********************************************************************
-*********************************************************************/
-
-static int _reg_perfcount_assemble_global(PERF_DATA_BLOCK *block,
-					  prs_struct *ps,
-					  int base_index,
-					  TDB_CONTEXT *names)
+static BOOL
+marshall_object_types(prs_struct *	    ps,
+		      PERF_OBJECT_TYPE **   otypes,
+		      unsigned		    onum,
+		      int		    depth)
 {
-	BOOL success;
-	int i, j, retval = 0;
-	char keybuf[PERFCOUNT_MAX_LEN];
-	TDB_DATA key, data;
+    int obj;
 
-	for(i = 1; i <= base_index; i++)
-	{
-		j = i*2;
-		_reg_perfcount_make_key(&key, keybuf, PERFCOUNT_MAX_LEN, j, "rel");
-		data = tdb_fetch(names, key);
-		if(data.dptr != NULL)
-		{
-			if(_reg_perfcount_isparent(data))
-				success = _reg_perfcount_add_object(block, ps, j, data, names);
-			else if(_reg_perfcount_ischild(data))
-				success = _reg_perfcount_add_counter(block, ps, j, data, names);
-			else
-			{
-				DEBUG(3, ("Bogus relationship [%s] for counter [%d].\n", data.dptr, j));
-				success = False;
-			}
-			if(success == False)
-			{
-				DEBUG(3, ("_reg_perfcount_assemble_global: Failed to add new relationship for counter [%d].\n", j));
-				retval = -1;
-			}
-			free(data.dptr);
-		}
-		else
-			DEBUG(3, ("NULL relationship for counter [%d] using key [%s].\n", j, keybuf));
-	}	
-	return retval;
-}
+    prs_debug(ps, depth, "", "marshall_object_types");
+    depth++;
 
-/*********************************************************************
-*********************************************************************/
+    for (obj = 0; obj < onum; obj++) {
+	uint32_t start;
+	PERF_OBJECT_TYPE * object;
 
-static BOOL _reg_perfcount_get_64(SMB_BIG_UINT *retval,
-				  TDB_CONTEXT *tdb,
-				  int key_part1,
-				  const char *key_part2)
-{
-	TDB_DATA key, data;
-	char buf[PERFCOUNT_MAX_LEN];
+	object = otypes[obj];
 
-	_reg_perfcount_make_key(&key, buf, PERFCOUNT_MAX_LEN, key_part1, key_part2);
+	SMB_ASSERT(IS_ALIGN64(ps->data_offset));
+	start = ps->data_offset;
 
-	data = tdb_fetch(tdb, key);
-	if(data.dptr == NULL)
-	{
-		DEBUG(3,("_reg_perfcount_get_64: No data found for key [%s].\n", key.dptr));
-		return False;
-	}
+	if(!prs_uint32("TotalByteLength", ps, depth, &object->TotalByteLength))
+	    return False;
+	if(!prs_uint32("DefinitionLength", ps, depth, &object->DefinitionLength))
+	    return False;
+	if(!prs_uint32("HeaderLength", ps, depth, &object->HeaderLength))
+	    return False;
+	if(!prs_uint32("ObjectNameTitleIndex", ps, depth, &object->ObjectNameTitleIndex))
+	    return False;
+	if(!prs_uint32("ObjectNameTitlePointer", ps, depth, &object->ObjectNameTitlePointer))
+	    return False;
+	if(!prs_uint32("ObjectHelpTitleIndex", ps, depth, &object->ObjectHelpTitleIndex))
+	    return False;
+	if(!prs_uint32("ObjectHelpTitlePointer", ps, depth, &object->ObjectHelpTitlePointer))
+	    return False;
+	if(!prs_uint32("DetailLevel", ps, depth, &object->DetailLevel))
+	    return False;
+	if(!prs_uint32("NumCounters", ps, depth, &object->NumCounters))
+	    return False;
+	if(!prs_uint32("DefaultCounter", ps, depth, &object->DefaultCounter))
+	    return False;
+	if(!prs_uint32("NumInstances", ps, depth, &object->NumInstances))
+	    return False;
+	if(!prs_uint32("CodePage", ps, depth, &object->CodePage))
+	    return False;
 
-	memset(buf, 0, PERFCOUNT_MAX_LEN);
-	memcpy(buf, data.dptr, data.dsize);
-	free(data.dptr);
+	if(!prs_align_uint64(ps))
+	    return False;
 
-	*retval = atof(buf);
+	SMB_ASSERT(IS_ALIGN64(ps->data_offset));
+	if(!prs_uint64("PerfTime", ps, depth, &object->PerfTime))
+	    return False;
+	if(!prs_uint64("PerfFreq", ps, depth, &object->PerfFreq))
+	    return False;
 
-	return True;
-}
+	/* If instances, encode instace plus counter data for each instance */
+	if (!marshall_counter_defs(ps, object->counters,
+				   object->NumCounters, depth)) {
+	    return False;
+	}
 
-/*********************************************************************
-*********************************************************************/
+	SMB_ASSERT(IS_ALIGN64(ps->data_offset));
 
-static BOOL _reg_perfcount_init_data_block_perf(PERF_DATA_BLOCK *block,
-						TDB_CONTEXT *names)
-{
-	SMB_BIG_UINT PerfFreq, PerfTime, PerfTime100nSec;
-	TDB_CONTEXT *counters;
-	BOOL status = False;
-	const char *fname = counters_directory( DATA_DB );
-    
-	counters = tdb_open_log(fname, 0, TDB_DEFAULT, O_RDONLY, 0444);
-    
-	if(counters == NULL)
+	if (object->NumInstances == PERF_NO_INSTANCES)
 	{
-		DEBUG(1, ("reg_perfcount_init_data_block_perf: unable to open [%s].\n", fname));
+	    if (!marshall_padding(ps, start, object->DefinitionLength))
 		return False;
-	}    
-    
-	status = _reg_perfcount_get_64(&PerfFreq, names, 0, "PerfFreq");
-	if(status == False)
-	{
-		tdb_close(counters);
-		return status;
-	}
-	memcpy((void *)&(block->PerfFreq), (const void *)&PerfFreq, sizeof(PerfFreq));
 
-	status = _reg_perfcount_get_64(&PerfTime, counters, 0, "PerfTime");
-	if(status == False)
-	{
-		tdb_close(counters);
-		return status;
+	    if (!marshall_counter_block(ps, &object->cblock, object->counters,
+			object->cvals, object->NumCounters, depth)) {
+		return False;
+	    }
 	}
-	memcpy((void *)&(block->PerfTime), (const void *)&PerfTime, sizeof(PerfTime));
-
-	status = _reg_perfcount_get_64(&PerfTime100nSec, counters, 0, "PerfTime100nSec");
-	if(status == False)
+	else
 	{
-		tdb_close(counters);
-		return status;
+	    if (!marshall_instance_defs(ps, object, depth)) {
+		return False;
+	    }
 	}
-	memcpy((void *)&(block->PerfTime100nSec), (const void *)&PerfTime100nSec, sizeof(PerfTime100nSec));
 
-	tdb_close(counters);
-	return True;
+	if (!marshall_padding(ps, start, object->TotalByteLength))
+	    return False;
+    }
+
+    SMB_ASSERT(IS_ALIGN64(ps->data_offset));
+    return True;
 }
 
-/*********************************************************************
-*********************************************************************/
-
-static void _reg_perfcount_init_data_block(PERF_DATA_BLOCK *block, prs_struct *ps, TDB_CONTEXT *names)
+static BOOL
+marshall_data_block(prs_struct * ps, PERF_DATA_BLOCK * block, int depth)
 {
-	wpstring temp;
-	time_t tm;
- 
-	memset(temp, 0, sizeof(temp));
-	rpcstr_push((void *)temp, "PERF", sizeof(temp), STR_TERMINATE);
-	memcpy(block->Signature, temp, strlen_w(temp) *2);
+    prs_debug(ps, depth, "", "marshall_data_block");
+    depth++;
 
-	if(ps->bigendian_data == RPC_BIG_ENDIAN)
-		block->LittleEndian = 0;
-	else
-		block->LittleEndian = 1;
-	block->Version = 1;
-	block->Revision = 1;
-	block->TotalByteLength = 0;
-	block->NumObjectTypes = 0;
-	block->DefaultObject = -1;
-	block->objects = NULL;
-	tm = time(NULL);
-	make_systemtime(&(block->SystemTime), gmtime(&tm));
-	_reg_perfcount_init_data_block_perf(block, names);
-	memset(temp, 0, sizeof(temp));
-	rpcstr_push((void *)temp, global_myname(), sizeof(temp), STR_TERMINATE);
-	block->SystemNameLength = (strlen_w(temp) * 2) + 2;
-	block->data = TALLOC_ZERO_ARRAY(ps->mem_ctx, uint8, block->SystemNameLength + (8 - (block->SystemNameLength % 8)));
-	memcpy(block->data, temp, block->SystemNameLength);
-	block->SystemNameOffset = sizeof(PERF_DATA_BLOCK) - sizeof(block->objects) - sizeof(block->data); 
-	block->HeaderLength = block->SystemNameOffset + block->SystemNameLength;
-	/* Make sure to adjust for 64-bit alignment for when we finish writing the system name,
-	   so that the PERF_OBJECT_TYPE struct comes out 64-bit aligned */
-	block->HeaderLength += 8 - (block->HeaderLength % 8);
+    SMB_ASSERT(ps->data_offset == 0);
 
-	return;
+    if (!prs_uint16s(False, "Signature", ps, depth, &block->Signature,
+		sizeof(block->Signature) / sizeof(uint16_t))) {
+	return False;
+    }
+
+    if(!prs_uint32("Little Endian", ps, depth, &block->LittleEndian))
+	return False;
+    if(!prs_uint32("Version", ps, depth, &block->Version))
+	return False;
+    if(!prs_uint32("Revision", ps, depth, &block->Revision))
+	return False;
+    if(!prs_uint32("TotalByteLength", ps, depth, &block->TotalByteLength))
+	return False;
+    if(!prs_uint32("HeaderLength", ps, depth, &block->HeaderLength))
+	return False;
+    if(!prs_uint32("NumObjectTypes", ps, depth, &block->NumObjectTypes))
+	return False;
+    if(!prs_uint32("DefaultObject", ps, depth, &block->DefaultObject))
+	return False;
+    if(!spoolss_io_system_time("SystemTime", ps, depth, &block->SystemTime))
+	return False;
+
+    if(!prs_align_uint64(ps))
+	return False;
+    SMB_ASSERT(IS_ALIGN64(ps->data_offset));
+
+    if(!prs_uint64("PerfTime", ps, depth, &block->PerfTime))
+	return False;
+    if(!prs_uint64("PerfFreq", ps, depth, &block->PerfFreq))
+	return False;
+    if(!prs_uint64("PerfTime100nSec", ps, depth, &block->PerfTime100nSec))
+	return False;
+    if(!prs_uint32("SystemNameLength", ps, depth, &block->SystemNameLength))
+	return False;
+    if(!prs_uint32("SystemNameOffset", ps, depth, &block->SystemNameOffset))
+	return False;
+
+    /* hack to make sure we're 64-bit aligned at the end of this whole mess */
+    if(!prs_uint8s(False, "SystemName", ps, depth, block->sysname, 
+		   block->HeaderLength - block->SystemNameOffset)) {
+	return False;
+    }
+
+    if (!marshall_padding(ps, 0, block->HeaderLength))
+	return False;
+
+    SMB_ASSERT(IS_ALIGN64(ps->data_offset));
+    return True;
 }
 
 /*********************************************************************
 *********************************************************************/
 
-static uint32 _reg_perfcount_perf_data_block_fixup(PERF_DATA_BLOCK *block, prs_struct *ps)
+static BOOL
+marshall_hkpd(prs_struct *ps, PERF_DATA_BLOCK * block)
 {
-	int obj, cnt, inst, pad, i;
-	PERF_OBJECT_TYPE *object;
-	PERF_INSTANCE_DEFINITION *instance;
-	PERF_COUNTER_DEFINITION *counter;
-	PERF_COUNTER_BLOCK *counter_data;
-	char *temp = NULL, *src_addr, *dst_addr;
+    int depth = 0;
 
-	block->TotalByteLength = 0;
-	object = block->objects;
-	for(obj = 0; obj < block->NumObjectTypes; obj++)
-	{
-		object[obj].TotalByteLength = 0;
-		object[obj].DefinitionLength = 0;
-		instance = object[obj].instances;
-		counter = object[obj].counters;
-		for(cnt = 0; cnt < object[obj].NumCounters; cnt++)
-		{
-			object[obj].TotalByteLength += counter[cnt].ByteLength;
-			object[obj].DefinitionLength += counter[cnt].ByteLength;
-		}
-		if(object[obj].NumInstances != PERF_NO_INSTANCES)
-		{
-			for(inst = 0; inst < object[obj].NumInstances; inst++)
-			{
-				instance = &(object[obj].instances[inst]);
-				object[obj].TotalByteLength += instance->ByteLength;
-				counter_data = &(instance->counter_data);
-				counter = &(object[obj].counters[object[obj].NumCounters - 1]);
-				counter_data->ByteLength = counter->CounterOffset + counter->CounterSize + sizeof(counter_data->ByteLength);
-				temp = TALLOC_REALLOC_ARRAY(ps->mem_ctx, 
-							    temp, 
-							    char, 
-							    counter_data->ByteLength- sizeof(counter_data->ByteLength));
-				memset(temp, 0, counter_data->ByteLength - sizeof(counter_data->ByteLength));
-				src_addr = (char *)counter_data->data;
-				for(i = 0; i < object[obj].NumCounters; i++)
-				{
-					counter = &(object[obj].counters[i]);
-					dst_addr = temp + counter->CounterOffset - sizeof(counter_data->ByteLength);
-					memcpy(dst_addr, src_addr, counter->CounterSize);
-				        src_addr += counter->CounterSize;
-				}
-				/* Make sure to be 64-bit aligned */
-				if((pad = (counter_data->ByteLength % 8)))
-				{
-					pad = 8 - pad;
-				}
-				counter_data->data = TALLOC_REALLOC_ARRAY(ps->mem_ctx,
-									 counter_data->data,
-									 uint8,
-									 counter_data->ByteLength - sizeof(counter_data->ByteLength) + pad);
-				memset(counter_data->data, 0, counter_data->ByteLength - sizeof(counter_data->ByteLength) + pad);
-				memcpy(counter_data->data, temp, counter_data->ByteLength - sizeof(counter_data->ByteLength));
-				counter_data->ByteLength += pad;
-				object[obj].TotalByteLength += counter_data->ByteLength;
-			}
-		}
-		else
-		{
-			/* Need to be 64-bit aligned at the end of the counter_data block, so pad counter_data to a 64-bit boundary,
-			   so that the next PERF_OBJECT_TYPE can start on a 64-bit alignment */
-			if((pad = (object[obj].counter_data.ByteLength % 8)))
-			{
-				pad = 8 - pad;
-				object[obj].counter_data.data = TALLOC_REALLOC_ARRAY(ps->mem_ctx, 
-										     object[obj].counter_data.data,
-										     uint8, 
-										     object[obj].counter_data.ByteLength + pad);
-				memset((void *)(object[obj].counter_data.data + object[obj].counter_data.ByteLength), 0, pad);
-				object[obj].counter_data.ByteLength += pad;
-			}
-			object[obj].TotalByteLength += object[obj].counter_data.ByteLength;
-		}
-		object[obj].HeaderLength = sizeof(*object) - (sizeof(counter) + sizeof(instance) + sizeof(PERF_COUNTER_BLOCK));
-		object[obj].TotalByteLength += object[obj].HeaderLength;
-		object[obj].DefinitionLength += object[obj].HeaderLength;
-		
-		block->TotalByteLength += object[obj].TotalByteLength;
-	}
+    if (marshall_data_block(ps, block, depth)) {
+	return marshall_object_types(ps, block->objects,
+				    block->NumObjectTypes, depth);
+    }
 
-	return block->TotalByteLength;
+    return False;
 }
 
 /*********************************************************************
 *********************************************************************/
 
-uint32 reg_perfcount_get_perf_data_block(uint32 base_index, 
-					 prs_struct *ps, 
-					 PERF_DATA_BLOCK *block,
-					 char *object_ids)
+void perfcount_init_keys (void)
 {
-	uint32 buffer_size = 0, last_counter;
-	const char *fname = counters_directory( NAMES_DB );
-	TDB_CONTEXT *names;
-	int retval;
-	
-	names = tdb_open_log(fname, 0, TDB_DEFAULT, O_RDONLY, 0444);
+    SMB_ASSERT(p_object_list == NULL);
+    SMB_ASSERT(p_object_index == NULL);
 
-	if(names == NULL)
-	{
-		DEBUG(1, ("reg_perfcount_get_perf_data_block: unable to open [%s].\n", fname));
-		return 0;
-	}
+    p_object_list = init_perf_object_namespace();
 
-	_reg_perfcount_init_data_block(block, ps, names);
+    if (p_object_list) {
+	/* We have a set of performance objects and their corresponding
+	 * counters. We need to index these so that we can provide indices to
+	 * the client for both help text and object access.
+	 *
+	 * The name index is used as both the index for the name string and for
+	 * the corresponding performance object. The help string has a
+	 * separate, independent index.
+	 */
 
-	last_counter = reg_perfcount_get_last_counter(base_index);
-    
-	if(object_ids == NULL)
-	{
-		/* we're getting a request for "Global" here */
-		retval = _reg_perfcount_assemble_global(block, ps, base_index, names);
+	struct perf_object **	po;
+	unsigned		icount = 0;
+
+	for (po = p_object_list; *po; ++po) {
+	    /* Reserve space for a "help" and a "name" index for the object and
+	     * for each of its counters. The object index is the same as the
+	     * name index.
+	     */
+	    icount += 2;
+	    icount += ((*po)->mcount * 2);
 	}
-	else
-	{
-		/* we're getting a request for a specific set of PERF_OBJECT_TYPES */
-		retval = _reg_perfcount_assemble_global(block, ps, base_index, names);
-	}
-	buffer_size = _reg_perfcount_perf_data_block_fixup(block, ps);
 
-	tdb_close(names);
+	icount *= 2;
+	DEBUG(PERFCOUNT_TRACE, ("%u perfcount indices needed\n", icount));
 
-	return buffer_size + block->HeaderLength;
-}
+	p_object_index = talloc_zero_array(NULL, struct perf_index, icount);
+	if (p_object_index == NULL) {
+	    talloc_free(p_object_list);
+	    return;
+	}
 
-/*********************************************************************
-*********************************************************************/
+	DEBUG(PERFCOUNT_TRACE, ("%u indices allocated in %u bytes\n",
+		talloc_array_elements(p_object_index, struct perf_index),
+		talloc_get_size(p_object_index)));
 
-static BOOL _reg_perfcount_marshall_perf_data_block(prs_struct *ps, PERF_DATA_BLOCK block, int depth)
-{
-	int i;
-	prs_debug(ps, depth, "", "_reg_perfcount_marshall_perf_data_block");
-	depth++;
+	SMB_ASSERT(icount == 
+		talloc_array_elements(p_object_index, struct perf_index));
 
-	if(!prs_align(ps))
-		return False;
-	for(i = 0; i < 4; i++)
-	{
-		if(!prs_uint16("Signature", ps, depth, &block.Signature[i]))
-			return False;
+	/* The first index contains a the total number of indexes. This is the
+	 * number of objects + the number of counters.
+	 */
+	p_object_index[0].name =
+			    talloc_asprintf(p_object_index, "%d", icount);
+	if (p_object_index[0].name == NULL) {
+	    talloc_free(p_object_list);
+	    return;
 	}
-	if(!prs_uint32("Little Endian", ps, depth, &block.LittleEndian))
-		return False;
-	if(!prs_uint32("Version", ps, depth, &block.Version))
-		return False;
-	if(!prs_uint32("Revision", ps, depth, &block.Revision))
-		return False;
-	if(!prs_uint32("TotalByteLength", ps, depth, &block.TotalByteLength))
-		return False;
-	if(!prs_uint32("HeaderLength", ps, depth, &block.HeaderLength))
-		return False;
-	if(!prs_uint32("NumObjectTypes", ps, depth, &block.NumObjectTypes))
-		return False;
-	if(!prs_uint32("DefaultObject", ps, depth, &block.DefaultObject))
-		return False;
-	if(!spoolss_io_system_time("SystemTime", ps, depth, &block.SystemTime))
-		return False;
-	if(!prs_uint32("Padding", ps, depth, &block.Padding))
-		return False;
-	if(!prs_align_uint64(ps))
-		return False;
-	if(!prs_uint64("PerfTime", ps, depth, &block.PerfTime))
-		return False;
-	if(!prs_uint64("PerfFreq", ps, depth, &block.PerfFreq))
-		return False;
-	if(!prs_uint64("PerfTime100nSec", ps, depth, &block.PerfTime100nSec))
-		return False;
-	if(!prs_uint32("SystemNameLength", ps, depth, &block.SystemNameLength))
-		return False;
-	if(!prs_uint32("SystemNameOffset", ps, depth, &block.SystemNameOffset))
-		return False;
-	/* hack to make sure we're 64-bit aligned at the end of this whole mess */
-	if(!prs_uint8s(False, "SystemName", ps, depth, block.data, 
-		       block.HeaderLength - block.SystemNameOffset)) 
-		return False;
 
-	return True;
-}
+	for (po = p_object_list, icount = 1; *po; ++po) {
+	    int m;
 
-/*********************************************************************
-*********************************************************************/
+	    (*po)->name.index = OBJECT_INDEX_MIN + icount;
+	    p_object_index[icount].name = (*po)->name.str;
+	    p_object_index[icount].perf = (*po);
+	    ++icount;
 
-static BOOL _reg_perfcount_marshall_perf_counters(prs_struct *ps,
-						  PERF_OBJECT_TYPE object,
-						  int depth)
-{
-	int cnt;
-	PERF_COUNTER_DEFINITION counter;
+	    (*po)->help.index = icount;
+	    p_object_index[icount].help = (*po)->help.str;
+	    ++icount;
 
-	prs_debug(ps, depth, "", "_reg_perfcount_marshall_perf_counters");
-	depth++;
-    
-	for(cnt = 0; cnt < object.NumCounters; cnt++)
-	{
-		counter = object.counters[cnt];
+	    for (m = 0; m < (*po)->mcount; ++m) {
+		(*po)->metrics[m].name.index = OBJECT_INDEX_MIN + icount;
+		p_object_index[icount].name = (*po)->metrics[m].name.str;
+		++icount;
 
-		if(!prs_align(ps))
-			return False;
-		if(!prs_uint32("ByteLength", ps, depth, &counter.ByteLength))
-			return False;
-		if(!prs_uint32("CounterNameTitleIndex", ps, depth, &counter.CounterNameTitleIndex))
-			return False;
-		if(!prs_uint32("CounterNameTitlePointer", ps, depth, &counter.CounterNameTitlePointer))
-			return False;
-		if(!prs_uint32("CounterHelpTitleIndex", ps, depth, &counter.CounterHelpTitleIndex))
-			return False;
-		if(!prs_uint32("CounterHelpTitlePointer", ps, depth, &counter.CounterHelpTitlePointer))
-			return False;
-		if(!prs_uint32("DefaultScale", ps, depth, &counter.DefaultScale))
-			return False;
-		if(!prs_uint32("DetailLevel", ps, depth, &counter.DetailLevel))
-			return False;
-		if(!prs_uint32("CounterType", ps, depth, &counter.CounterType))
-			return False;
-		if(!prs_uint32("CounterSize", ps, depth, &counter.CounterSize))
-			return False;
-		if(!prs_uint32("CounterOffset", ps, depth, &counter.CounterOffset))
-			return False;
+		(*po)->metrics[m].help.index = OBJECT_INDEX_MIN + icount;
+		p_object_index[icount].help = (*po)->metrics[m].help.str;
+		++icount;
+	    }	
+
+	    ++icount;
 	}
 
-	return True;
-}
+	SMB_ASSERT(icount <= 
+		talloc_array_elements(p_object_index, struct perf_index));
 
-/*********************************************************************
-*********************************************************************/
+	/* Note that we do not convert the help to unicode at this point. The
+	 * rationale is that downloading the help text is an infrequent
+	 * operation and converting and caching all the help text would use a
+	 * lot of memory to speed up an operation that doesn't happen much.
+	 */
+    }
 
-static BOOL _reg_perfcount_marshall_perf_counter_data(prs_struct *ps, 
-						      PERF_COUNTER_BLOCK counter_data, 
-						      int depth)
-{
-	prs_debug(ps, depth, "", "_reg_perfcount_marshall_perf_counter_data");
-	depth++;
-    
-	if(!prs_align_uint64(ps))
-		return False;
-    
-	if(!prs_uint32("ByteLength", ps, depth, &counter_data.ByteLength))
-		return False;
-	if(!prs_uint8s(False, "CounterData", ps, depth, counter_data.data, counter_data.ByteLength - sizeof(uint32)))
-		return False;
-	if(!prs_align_uint64(ps))
-		return False;
-
-	return True;
+    c_name_sz = reg_perfcount_get_counter_names(&c_name_buf);
+    c_help_sz = reg_perfcount_get_counter_help(&c_help_buf);
 }
 
 /*********************************************************************
+ * Build a PERF_OBJECT_TYPE for the requested performance counters. In
+ * object_ids is NULL, the caller wants all the counters. Otherwise object_ids
+ * is a space-separated list of object indices.
 *********************************************************************/
 
-static BOOL _reg_perfcount_marshall_perf_instances(prs_struct *ps,
-						   PERF_OBJECT_TYPE object, 
-						   int depth)
+ WERROR reg_perfcount_get_hkpd(prs_struct * ps,
+			     size_t	    max_buf_size,
+			     size_t *	    outbuf_len,
+			     const char *   object_ids)
 {
-	PERF_INSTANCE_DEFINITION instance;
-	int inst;
+    /*
+     * For a detailed description of the layout of this structure, see
+     * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/perfmon/base/performance_data_format.asp
+     */
 
-	prs_debug(ps, depth, "", "_reg_perfcount_marshall_perf_instances");
-	depth++;
+    PERF_DATA_BLOCK * block;
+    ssize_t buffer_size;
 
-	for(inst = 0; inst < object.NumInstances; inst++)
-	{
-		instance = object.instances[inst];
+    if ((block = perfcount_fetch_objects(ps, object_ids)) == NULL) {
+	return(WERR_NOMEM);
+    }
 
-		if(!prs_align(ps))
-			return False;
-		if(!prs_uint32("ByteLength", ps, depth, &instance.ByteLength))
-			return False;
-		if(!prs_uint32("ParentObjectTitleIndex", ps, depth, &instance.ParentObjectTitleIndex))
-			return False;
-		if(!prs_uint32("ParentObjectTitlePointer", ps, depth, &instance.ParentObjectTitlePointer))
-			return False;
-		if(!prs_uint32("UniqueID", ps, depth, &instance.UniqueID))
-			return False;
-		if(!prs_uint32("NameOffset", ps, depth, &instance.NameOffset))
-			return False;
-		if(!prs_uint32("NameLength", ps, depth, &instance.NameLength))
-			return False;
-		if(!prs_uint8s(False, "InstanceName", ps, depth, instance.data,
-			       instance.ByteLength - instance.NameOffset))
-			return False;
-		if(_reg_perfcount_marshall_perf_counter_data(ps, instance.counter_data, depth) == False)
-			return False;
+    if (!perfcount_fetch_counter_data(block)) {
+	talloc_free(block);
+	return WERR_GENERAL_FAILURE;
+    }
+
+    buffer_size = perfcount_size_data_block(block);
+    if (buffer_size < max_buf_size) {
+	*outbuf_len = buffer_size;
+	if(marshall_hkpd(ps, block)) {
+	    talloc_free(block);
+	    return WERR_OK;
+	} else {
+	    talloc_free(block);
+	    return WERR_NOMEM;
 	}
-	
-	return True;
+    }
+
+    talloc_free(block);
+    return WERR_INSUFFICIENT_BUFFER;
 }
 
 /*********************************************************************
+ * Fill retbuf with an ordered list of unicode performance counter help
+ * strings.
 *********************************************************************/
 
-static BOOL _reg_perfcount_marshall_perf_objects(prs_struct *ps, PERF_DATA_BLOCK block, int depth)
+ ssize_t reg_perfcount_get_counter_help(char ** retbuf)
 {
-	int obj;
+    DEBUG(PERFCOUNT_TRACE, ("fetching counter help\n"));
 
-	PERF_OBJECT_TYPE object;
-    
-	prs_debug(ps, depth, "", "_reg_perfcount_marshall_perf_objects");
-	depth++;
+    if (c_help_buf == NULL) {
+	DEBUG(PERFCOUNT_TRACE, ("filling counter help cache\n"));
+	c_help_sz = get_item_strings(&c_help_buf, index_item_help);
+    }
 
-	for(obj = 0; obj < block.NumObjectTypes; obj++)
-	{
-		object = block.objects[obj];
+    if (c_help_buf) {
+	DEBUG(PERFCOUNT_TRACE,
+		("returning %ld  bytes of cached counter help\n",
+		 c_help_sz));
+	talloc_increase_ref_count(c_help_buf);
+	*retbuf = c_help_buf;
+	return c_help_sz;
+    }
 
-		if(!prs_align(ps))
-			return False;
-
-		if(!prs_uint32("TotalByteLength", ps, depth, &object.TotalByteLength))
-			return False;
-		if(!prs_uint32("DefinitionLength", ps, depth, &object.DefinitionLength))
-			return False;
-		if(!prs_uint32("HeaderLength", ps, depth, &object.HeaderLength))
-			return False;
-		if(!prs_uint32("ObjectNameTitleIndex", ps, depth, &object.ObjectNameTitleIndex))
-			return False;
-		if(!prs_uint32("ObjectNameTitlePointer", ps, depth, &object.ObjectNameTitlePointer))
-			return False;
-		if(!prs_uint32("ObjectHelpTitleIndex", ps, depth, &object.ObjectHelpTitleIndex))
-			return False;
-		if(!prs_uint32("ObjectHelpTitlePointer", ps, depth, &object.ObjectHelpTitlePointer))
-			return False;
-		if(!prs_uint32("DetailLevel", ps, depth, &object.DetailLevel))
-			return False;
-		if(!prs_uint32("NumCounters", ps, depth, &object.NumCounters))
-			return False;
-		if(!prs_uint32("DefaultCounter", ps, depth, &object.DefaultCounter))
-			return False;
-		if(!prs_uint32("NumInstances", ps, depth, &object.NumInstances))
-			return False;
-		if(!prs_uint32("CodePage", ps, depth, &object.CodePage))
-			return False;
-		if(!prs_align_uint64(ps))
-			return False;
-		if(!prs_uint64("PerfTime", ps, depth, &object.PerfTime))
-			return False;
-		if(!prs_uint64("PerfFreq", ps, depth, &object.PerfFreq))
-			return False;
-
-		/* Now do the counters */
-		/* If no instances, encode counter_data */
-		/* If instances, encode instace plus counter data for each instance */
-		if(_reg_perfcount_marshall_perf_counters(ps, object, depth) == False)
-			return False;
-		if(object.NumInstances == PERF_NO_INSTANCES)
-		{
-			if(_reg_perfcount_marshall_perf_counter_data(ps, object.counter_data, depth) == False)
-				return False;
-		}
-		else
-		{
-			if(_reg_perfcount_marshall_perf_instances(ps, object, depth) == False)
-				return False;
-		}
-	}
-
-	return True;
+    return -1;
 }
 
 /*********************************************************************
+ * Fill retbuf with an ordered list of unicode performance counter
+ * names. Prefix the buffer with the number of indexed items.
 *********************************************************************/
 
-static BOOL _reg_perfcount_marshall_hkpd(prs_struct *ps, PERF_DATA_BLOCK block)
+ ssize_t reg_perfcount_get_counter_names(char ** retbuf)
 {
-	int depth = 0;
-	if(_reg_perfcount_marshall_perf_data_block(ps, block, depth) == True)
-	{
-		if(_reg_perfcount_marshall_perf_objects(ps, block, depth) == True)
-			return True;
-	}
-	return False;
-}
+    DEBUG(PERFCOUNT_TRACE, ("fetching counter names\n"));
 
-/*********************************************************************
-*********************************************************************/
+    if (c_name_buf == NULL) {
+	DEBUG(PERFCOUNT_TRACE, ("filling counter names cache\n"));
+	c_name_sz = get_item_strings(&c_name_buf, index_item_name);
+    }
 
-WERROR reg_perfcount_get_hkpd(prs_struct *ps, uint32 max_buf_size, uint32 *outbuf_len, char *object_ids)
-{
-	/*
-	 * For a detailed description of the layout of this structure,
-	 * see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/perfmon/base/performance_data_format.asp
-	 */
-	PERF_DATA_BLOCK block;
-	uint32 buffer_size, base_index; 
-    
-	buffer_size = 0;
-	base_index = reg_perfcount_get_base_index();
-	ZERO_STRUCT(block);
+    if (c_name_buf) {
+	DEBUG(PERFCOUNT_TRACE,
+		("returning %ld  bytes of cached counter names\n",
+		 c_name_sz));
+	talloc_increase_ref_count(c_name_buf);
+	*retbuf = c_name_buf;
+	return c_name_sz;
+    }
 
-	buffer_size = reg_perfcount_get_perf_data_block(base_index, ps, &block, object_ids);
+    return -1;
+}
 
-	if(buffer_size < max_buf_size)
-	{
-		*outbuf_len = buffer_size;
-		if(_reg_perfcount_marshall_hkpd(ps, block) == True)
-			return WERR_OK;
-		else
-			return WERR_NOMEM;
-	}
-	else
-	{
-		*outbuf_len = max_buf_size;
-		_reg_perfcount_marshall_perf_data_block(ps, block, 0);
-		return WERR_INSUFFICIENT_BUFFER;
-	}
-}    
+ void reg_perfcount_get_params(struct reg_perflib_params * p)
+{
+    p->base_index = OBJECT_INDEX_MIN;
+    p->version = SAMBA_VERSION_MAJOR * 100 +
+		SAMBA_VERSION_MINOR * 10 +
+		SAMBA_VERSION_RELEASE;
+    p->last_counter = OBJECT_INDEX_MAX; /* Number of counters. */
+    p->last_help = OBJECT_INDEX_MAX;
+}
Index: source/registry/reg_objects.c
===================================================================
--- source/registry/reg_objects.c	(revision 11815)
+++ source/registry/reg_objects.c	(working copy)
@@ -288,7 +288,7 @@
 			ctr->values = ppreg;
 	}
 
-	/* allocate a new value and store the pointer in the arrya */
+	/* allocate a new value and store the pointer in the array */
 		
 	ctr->values[ctr->num_values] = TALLOC_P( ctr, REGISTRY_VALUE);
 
Index: source/tdb/Makefile
===================================================================
--- source/tdb/Makefile	(revision 11815)
+++ source/tdb/Makefile	(working copy)
@@ -3,7 +3,6 @@
 #
 
 CFLAGS = -DSTANDALONE -DTDB_DEBUG -g -DHAVE_MMAP=1
-CC = gcc
 
 ADMINPROGS = tdbdump tdbbackup
 PROGS = tdbtest tdbtool tdbtorture


More information about the samba-technical mailing list