summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--.gitmodules3
-rw-r--r--Makefile.am2
-rwxr-xr-xautogen.sh9
m---------cmockery20
-rw-r--r--configure.ac14
-rw-r--r--doc/hacker-guide/en-US/markdown/unittest.md227
-rw-r--r--glusterfs.spec.in7
-rw-r--r--libglusterfs/src/Makefile.am17
-rw-r--r--libglusterfs/src/mem-pool.c39
-rw-r--r--libglusterfs/src/mem-pool.h13
-rw-r--r--libglusterfs/src/unittest/global_mock.c24
-rw-r--r--libglusterfs/src/unittest/log_mock.c43
-rw-r--r--libglusterfs/src/unittest/mem_pool_unittest.c472
-rw-r--r--xlators/cluster/dht/src/Makefile.am15
-rw-r--r--xlators/cluster/dht/src/dht-layout.c20
-rw-r--r--xlators/cluster/dht/src/unittest/dht_layout_mock.c63
-rw-r--r--xlators/cluster/dht/src/unittest/dht_layout_unittest.c124
-rw-r--r--xlators/storage/posix/src/posix-helpers.c10
19 files changed, 1087 insertions, 17 deletions
diff --git a/.gitignore b/.gitignore
index 1649aa6fba0..e8d0012aa06 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,6 +9,8 @@ ltmain.sh
Makefile.in
missing
py-compile
+*.gcda
+*.gcno
*.sw?
*~
*.lo
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 00000000000..58165fe0a7d
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "cmockery2"]
+ path = cmockery2
+ url = https://github.com/lpabon/cmockery2.git
diff --git a/Makefile.am b/Makefile.am
index 598ebb4103c..815d6ad3e5f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -6,7 +6,7 @@ EXTRA_DIST = autogen.sh \
gen-headers.py run-tests.sh \
$(shell find $(top_srcdir)/tests -type f -print)
-SUBDIRS = argp-standalone libglusterfs rpc api xlators glusterfsd \
+SUBDIRS = argp-standalone cmockery2 libglusterfs rpc api xlators glusterfsd \
$(FUSERMOUNT_SUBDIR) doc extras cli @SYNCDAEMON_SUBDIR@
pkgconfigdir = @pkgconfigdir@
diff --git a/autogen.sh b/autogen.sh
index cd8603b66d3..221cc2b7819 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -106,8 +106,15 @@ $AUTOCONF
echo Running ${AUTOMAKE}...
$AUTOMAKE --add-missing --copy --foreign
+# Update git modules
+echo "Obtaining git module cmockery2 ..."
+git submodule update --init cmockery2
+
# Run autogen in the argp-standalone sub-directory
-cd argp-standalone;./autogen.sh
+echo "Running autogen.sh in argp-standalone ..."
+( cd argp-standalone;./autogen.sh )
+echo "Running autogen.sh in cmockery2 ..."
+( cd cmockery2; ./autogen.sh )
# Instruct user on next steps
echo
diff --git a/cmockery2 b/cmockery2
new file mode 160000
+Subproject 4eb53ab96fd2b227fbf68c40bcc8d915b48213b
diff --git a/configure.ac b/configure.ac
index 69d25e4dad7..626f6f6289c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -630,6 +630,18 @@ AC_SUBST(HAVE_LINKAT)
dnl check for Monotonic clock
AC_CHECK_FUNC([clock_gettime], [has_monotonic_clock=yes], AC_CHECK_LIB([rt], [clock_gettime], , AC_MSG_WARN([System doesn't have monotonic clock using contrib])))
+dnl Add cmockery2 for unit testing
+AC_CONFIG_SUBDIRS([cmockery2])
+UNITTEST_CFLAGS='-g -Wall -DUNIT_TESTING=1 -DDEBUG -Werror -O0 --coverage'
+UNITTEST_CPPFLAGS='-I$(top_srcdir)/cmockery2/src'
+UNITTEST_LDADD='$(top_builddir)/cmockery2/libcmockery.la'
+UNITTEST_LDFLAGS=-lgcov
+CFLAGS="$CFLAGS ${UNITTEST_CPPFLAGS}"
+AC_SUBST(UNITTEST_CFLAGS)
+AC_SUBST(UNITTEST_CPPFLAGS)
+AC_SUBST(UNITTEST_LDADD)
+AC_SUBST(UNITTEST_LDFLAGS)
+
dnl Check for argp
AC_CHECK_HEADER([argp.h], AC_DEFINE(HAVE_ARGP, 1, [have argp]))
AC_CONFIG_SUBDIRS(argp-standalone)
@@ -900,7 +912,7 @@ CONTRIBDIR='$(top_srcdir)/contrib'
AC_SUBST(CONTRIBDIR)
GF_CPPDEFINES='-D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -D$(GF_HOST_OS)'
-GF_CPPINCLUDES='-I$(top_srcdir)/libglusterfs/src -I$(CONTRIBDIR)/uuid'
+GF_CPPINCLUDES='-I$(top_srcdir)/libglusterfs/src -I$(CONTRIBDIR)/uuid $(UNITTEST_CPPFLAGS)'
GF_CPPFLAGS="$GF_CPPDEFINES $GF_CPPINCLUDES"
AC_SUBST([GF_CPPFLAGS])
diff --git a/doc/hacker-guide/en-US/markdown/unittest.md b/doc/hacker-guide/en-US/markdown/unittest.md
new file mode 100644
index 00000000000..65e8b85d55c
--- /dev/null
+++ b/doc/hacker-guide/en-US/markdown/unittest.md
@@ -0,0 +1,227 @@
+# Unit Tests in GlusterFS
+
+## Overview
+[Art-of-unittesting][definitionofunittest] provides a good definition for unit tests. A good unit test is:
+
+* Able to be fully automated
+* Has full control over all the pieces running (Use mocks or stubs to achieve this isolation when needed)
+* Can be run in any order if part of many other tests
+* Runs in memory (no DB or File access, for example)
+* Consistently returns the same result (You always run the same test, so no random numbers, for example. save those for integration or range tests)
+* Runs fast
+* Tests a single logical concept in the system
+* Readable
+* Maintainable
+* Trustworthy (when you see its result, you don’t need to debug the code just to be sure)
+
+## Cmockery2
+GlusterFS unit test framework is based on [Cmockery2][]. Cmockery provides developers with methods to isolate and test modules written in C language. It also provides integration with Jenkins by providing JUnit XML compliant unit test results.
+
+Before continuing, you may want to familiarize yourself with Cmockery2 by reading the [usage guide][cmockery2usage].
+
+## Running Unit Tests
+To execute the unit tests, all you need is to type `make check`. Here is a step-by-step example assuming you just cloned a GlusterFS tree:
+
+```
+$ ./autogen.sh
+$ ./configure --enable-debug
+$ make check
+```
+
+Sample output:
+
+```
+PASS: mem_pool_unittest
+============================================================================
+Testsuite summary for glusterfs 3git
+============================================================================
+# TOTAL: 1
+# PASS: 1
+# SKIP: 0
+# XFAIL: 0
+# FAIL: 0
+# XPASS: 0
+# ERROR: 0
+============================================================================
+```
+
+In this example, `mem_pool_unittest` has multiple tests inside, but `make check` assumes that the program itself is the test, and that is why it only shows one test. Here is the output when we run `mem_pool_unittest` directly:
+
+```
+$ ./libglusterfs/src/mem_pool_unittest
+[==========] Running 10 test(s).
+[ RUN ] test_gf_mem_acct_enable_set
+Expected assertion data != ((void *)0) occurred
+[ OK ] test_gf_mem_acct_enable_set
+[ RUN ] test_gf_mem_set_acct_info_asserts
+Expected assertion xl != ((void *)0) occurred
+Expected assertion size > ((4 + sizeof (size_t) + sizeof (xlator_t *) + 4 + 8) + 8) occurred
+Expected assertion type <= xl->mem_acct.num_types occurred
+[ OK ] test_gf_mem_set_acct_info_asserts
+[ RUN ] test_gf_mem_set_acct_info_memory
+[ OK ] test_gf_mem_set_acct_info_memory
+[ RUN ] test_gf_calloc_default_calloc
+[ OK ] test_gf_calloc_default_calloc
+[ RUN ] test_gf_calloc_mem_acct_enabled
+[ OK ] test_gf_calloc_mem_acct_enabled
+[ RUN ] test_gf_malloc_default_malloc
+[ OK ] test_gf_malloc_default_malloc
+[ RUN ] test_gf_malloc_mem_acct_enabled
+[ OK ] test_gf_malloc_mem_acct_enabled
+[ RUN ] test_gf_realloc_default_realloc
+[ OK ] test_gf_realloc_default_realloc
+[ RUN ] test_gf_realloc_mem_acct_enabled
+[ OK ] test_gf_realloc_mem_acct_enabled
+[ RUN ] test_gf_realloc_ptr
+Expected assertion ((void *)0) != ptr occurred
+[ OK ] test_gf_realloc_ptr
+[==========] 10 test(s) run.
+[ PASSED ] 10 test(s).
+[ FAILED ] 0 test(s).
+[ REPORT ] Created libglusterfs_mem_pool_xunit.xml report
+```
+
+
+## Writing Unit Tests
+
+### Enhancing your C functions
+
+#### Programming by Contract
+Add the following to your C file:
+
+```c
+#include <cmockery/pbc.h>
+```
+
+```c
+/*
+ * Programming by Contract is a programming methodology
+ * which binds the caller and the function called to a
+ * contract. The contract is represented using Hoare Triple:
+ * {P} C {Q}
+ * where {P} is the precondition before executing command C,
+ * and {Q} is the postcondition.
+ *
+ * See also:
+ * http://en.wikipedia.org/wiki/Design_by_contract
+ * http://en.wikipedia.org/wiki/Hoare_logic
+ * http://dlang.org/dbc.html
+ */
+ #ifndef CMOCKERY_PBC_H_
+#define CMOCKERY_PBC_H_
+
+#if defined(UNIT_TESTING) || defined (DEBUG)
+
+#include <assert.h>
+
+/*
+ * Checks caller responsability against contract
+ */
+#define REQUIRE(cond) assert(cond)
+
+/*
+ * Checks function reponsability against contract.
+ */
+#define ENSURE(cond) assert(cond)
+
+/*
+ * While REQUIRE and ENSURE apply to functions, INVARIANT
+ * applies to classes/structs. It ensures that intances
+ * of the class/struct are consistant. In other words,
+ * that the instance has not been corrupted.
+ */
+#define INVARIANT(invariant_fnc) do{ (invariant_fnc) } while (0);
+
+#else
+#define REQUIRE(cond) do { } while (0);
+#define ENSURE(cond) do { } while (0);
+#define INVARIANT(invariant_fnc) do{ } while (0);
+
+#endif /* defined(UNIT_TESTING) || defined (DEBUG) */
+#endif /* CMOCKERY_PBC_H_ */
+```
+
+##### Example
+This is an _extremely_ simple example:
+
+```c
+int divide (int n, int d)
+{
+ int ans;
+
+ REQUIRE(d != 0);
+
+ ans = n / d;
+
+ // As code is added to this function throughout its lifetime,
+ // ENSURE will assert that data will be returned
+ // according to the contract. Again this is an
+ // extremely simple example. :-D
+ ENSURE( ans == (n / d) );
+
+ return ans;
+}
+
+```
+
+##### Important Note
+`REQUIRE`, `ENSURE`, and `INVARIANT` are only available when `DEBUG` or `UNIT_TESTING` are set in the CFLAGS. You must pass `--enable-debug` to `./configure` to enable PBC on your non-unittest builds.
+
+#### Overriding functions
+Cmockery2 provides its own memory allocation functions which check for buffer overrun and memory leaks. The following header file must be included **last** to be able to override any of the memory allocation functions:
+
+```c
+#include <cmockery/cmockery_override.h>
+```
+
+This file will only take effect with the `UNIT_TESTING` CFLAG is set.
+
+### Creating a unit test
+Once you identify the C file you would like to test, first create a `unittest` directory under the directory where the C file is located. This will isolate the unittests to a different directory.
+
+Next, you need to edit the `Makefile.am` file in the directory where your C file is located. Initialize the
+`Makefile.am` if it does not already have the following sections:
+
+```
+#### UNIT TESTS #####
+CLEANFILES += *.gcda *.gcno *_xunit.xml
+noinst_PROGRAMS =
+TESTS =
+```
+
+Now you can add the following for each of the unit tests that you would like to build:
+
+```
+### UNIT TEST xxx_unittest ###
+xxx_unittest_CPPFLAGS = $(UNITTEST_CPPFLAGS) $(xxx_CPPFLAGS)
+xxx_unittest_SOURCES = xxx.c \
+ unittest/xxx_unittest.c
+xxx_unittest_CFLAGS = $(UNITTEST_CFLAGS)
+xxx_unittest_LDADD = $(UNITTEST_LDADD)
+xxx_unittest_LDFLAGS = $(UNITTEST_LDFLAGS)
+noinst_PROGRAMS += xxx_unittest
+TESTS += xxx_unittest
+```
+
+Where `xxx` is the name of your C file. For example, look at `libglusterfs/src/Makefile.am`.
+
+Copy the simple unit test from `cmockery2/src/example/run_tests.c` to `unittest/xxx_unittest.c`. If you would like to see an example of a unit test, please refer to `libglusterfs/src/unittest/mem_pool_unittest.c`.
+
+#### Mocking
+You may see that the linker will complain about missing functions needed by the C file you would like to test. Identify the required functions, then place their stubs in a file called `unittest/xxx_mock.c`, then include this file in `Makefile.am` in `xxx_unittest_SOURCES`. This will allow you to you Cmockery2's mocking functions.
+
+#### Running the unit test
+You can type `make` in the directory where the C file is located. Once you built it and there are no errors, you can execute the test either by directly executing the program (in our example above it is called `xxx_unittest` ), or by running `make check`.
+
+#### Debugging
+Sometimes you may need to debug your unit test. To do that, you will have to point `gdb` to the actual binary which is located in the `.libs` subdirectory. For example, you can do the following from the root of the source tree to debug `mem_pool_unittest`:
+
+```
+$ export LD_LIBRARY_PATH=cmockery2/.libs
+$ gdb ./libglusterfs/src/.libs/mem_pool_unittest
+```
+
+
+[Cmockery2]: https://github.com/lpabon/cmockery2
+[definitionofunittest]: http://artofunittesting.com/definition-of-a-unit-test/
+[cmockery2usage]: https://github.com/lpabon/cmockery2/blob/master/doc/usage.md
diff --git a/glusterfs.spec.in b/glusterfs.spec.in
index 43662b5a9ef..5e661399f28 100644
--- a/glusterfs.spec.in
+++ b/glusterfs.spec.in
@@ -450,6 +450,10 @@ pushd api/examples
FLAGS="$RPM_OPT_FLAGS" python setup.py build
popd
+%check
+
+LD_LIBRARY_PATH=$PWD/cmockery2/.libs make check
+
%install
rm -rf %{buildroot}
make install DESTDIR=%{buildroot}
@@ -666,6 +670,9 @@ rm -rf %{buildroot}
%exclude %{_libdir}/glusterfs/%{version}%{?prereltag}/xlator/encryption/rot-13*
%exclude %{_libdir}/glusterfs/%{version}%{?prereltag}/xlator/features/mac-compat*
%exclude %{_libdir}/glusterfs/%{version}%{?prereltag}/xlator/testing/performance/symlink-cache*
+# exclude cmockery
+%exclude %{_includedir}/cmockery*
+%exclude %{_prefix}/share/doc/cmockery*
%post libs
/sbin/ldconfig
diff --git a/libglusterfs/src/Makefile.am b/libglusterfs/src/Makefile.am
index 634e217ed4d..ac6a3b9ecde 100644
--- a/libglusterfs/src/Makefile.am
+++ b/libglusterfs/src/Makefile.am
@@ -55,3 +55,20 @@ y.tab.h: graph.y
CLEANFILES = graph.lex.c y.tab.c y.tab.h
CONFIG_CLEAN_FILES = $(CONTRIB_BUILDDIR)/uuid/uuid_types.h
+
+#### UNIT TESTS #####
+CLEANFILES += *.gcda *.gcno *_xunit.xml
+noinst_PROGRAMS =
+TESTS =
+
+mem_pool_unittest_CPPFLAGS = $(UNITTEST_CPPFLAGS) $(libglusterfs_la_CPPFLAGS)
+mem_pool_unittest_SOURCES = mem-pool.c \
+ mem-pool.h \
+ unittest/mem_pool_unittest.c \
+ unittest/log_mock.c \
+ unittest/global_mock.c
+mem_pool_unittest_CFLAGS = $(UNITTEST_CFLAGS)
+mem_pool_unittest_LDADD = $(UNITTEST_LDADD)
+mem_pool_unittest_LDFLAGS = $(UNITTEST_LDFLAGS)
+noinst_PROGRAMS += mem_pool_unittest
+TESTS += mem_pool_unittest
diff --git a/libglusterfs/src/mem-pool.c b/libglusterfs/src/mem-pool.c
index b901dd7a862..96e04910513 100644
--- a/libglusterfs/src/mem-pool.c
+++ b/libglusterfs/src/mem-pool.c
@@ -22,29 +22,30 @@
#define is_mem_chunk_in_use(ptr) (*ptr == 1)
#define mem_pool_from_ptr(ptr) ((ptr) + GF_MEM_POOL_LIST_BOUNDARY)
-#define GF_MEM_HEADER_SIZE (4 + sizeof (size_t) + sizeof (xlator_t *) + 4 + 8)
-#define GF_MEM_TRAILER_SIZE 8
-
-#define GF_MEM_HEADER_MAGIC 0xCAFEBABE
-#define GF_MEM_TRAILER_MAGIC 0xBAADF00D
-
#define GLUSTERFS_ENV_MEM_ACCT_STR "GLUSTERFS_DISABLE_MEM_ACCT"
+#include <cmockery/pbc.h>
+#include <cmockery/cmockery_override.h>
+
void
gf_mem_acct_enable_set (void *data)
{
glusterfs_ctx_t *ctx = NULL;
+ REQUIRE(data != NULL);
+
ctx = data;
- GF_ASSERT (ctx);
+ GF_ASSERT (ctx != NULL);
ctx->mem_acct_enable = 1;
+ ENSURE(1 == ctx->mem_acct_enable);
+
return;
}
-void
+int
gf_mem_set_acct_info (xlator_t *xl, char **alloc_ptr,
size_t size, uint32_t type)
{
@@ -52,7 +53,7 @@ gf_mem_set_acct_info (xlator_t *xl, char **alloc_ptr,
char *ptr = NULL;
if (!alloc_ptr)
- return;
+ return -1;
ptr = (char *) (*alloc_ptr);
@@ -88,7 +89,7 @@ gf_mem_set_acct_info (xlator_t *xl, char **alloc_ptr,
*(uint32_t *) (ptr + size) = GF_MEM_TRAILER_MAGIC;
*alloc_ptr = (void *)ptr;
- return;
+ return 0;
}
@@ -150,10 +151,13 @@ __gf_realloc (void *ptr, size_t size)
char *orig_ptr = NULL;
xlator_t *xl = NULL;
uint32_t type = 0;
+ char *new_ptr;
if (!THIS->ctx->mem_acct_enable)
return REALLOC (ptr, size);
+ REQUIRE(NULL != ptr);
+
tot_size = size + GF_MEM_HEADER_SIZE + GF_MEM_TRAILER_SIZE;
orig_ptr = (char *)ptr - 8 - 4;
@@ -166,15 +170,22 @@ __gf_realloc (void *ptr, size_t size)
orig_ptr = (char *)ptr - GF_MEM_HEADER_SIZE;
type = *(uint32_t *)orig_ptr;
- ptr = realloc (orig_ptr, tot_size);
- if (!ptr) {
+ new_ptr = realloc (orig_ptr, tot_size);
+ if (!new_ptr) {
gf_log_nomem ("", GF_LOG_ALERT, tot_size);
return NULL;
}
- gf_mem_set_acct_info (xl, (char **)&ptr, size, type);
+ /*
+ * We used to pass (char **)&ptr as the second
+ * argument after the value of realloc was saved
+ * in ptr, but the compiler warnings complained
+ * about the casting to and forth from void ** to
+ * char **.
+ */
+ gf_mem_set_acct_info (xl, &new_ptr, size, type);
- return (void *)ptr;
+ return (void *)new_ptr;
}
int
diff --git a/libglusterfs/src/mem-pool.h b/libglusterfs/src/mem-pool.h
index 31f49f75cbb..aa6bf784363 100644
--- a/libglusterfs/src/mem-pool.h
+++ b/libglusterfs/src/mem-pool.h
@@ -20,6 +20,19 @@
#include <string.h>
#include <stdarg.h>
+/*
+ * Need this for unit tests since inline functions
+ * access memory allocation and need to use the
+ * unit test versions
+ */
+#ifdef UNIT_TESTING
+#include <cmockery/cmockery_override.h>
+#endif
+
+#define GF_MEM_HEADER_SIZE (4 + sizeof (size_t) + sizeof (xlator_t *) + 4 + 8)
+#define GF_MEM_TRAILER_SIZE 8
+#define GF_MEM_HEADER_MAGIC 0xCAFEBABE
+#define GF_MEM_TRAILER_MAGIC 0xBAADF00D
struct mem_acct {
uint32_t num_types;
diff --git a/libglusterfs/src/unittest/global_mock.c b/libglusterfs/src/unittest/global_mock.c
new file mode 100644
index 00000000000..b50638d1023
--- /dev/null
+++ b/libglusterfs/src/unittest/global_mock.c
@@ -0,0 +1,24 @@
+/*
+ Copyright (c) 2014 Red Hat, Inc. <http://www.redhat.com>
+ This file is part of GlusterFS.
+
+ This file is licensed to you under your choice of the GNU Lesser
+ General Public License, version 3 or any later version (LGPLv3 or
+ later), or the GNU General Public License, version 2 (GPLv2), in all
+ cases as published by the Free Software Foundation.
+*/
+
+#include "logging.h"
+#include "xlator.h"
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <inttypes.h>
+
+#include <cmockery/cmockery.h>
+
+xlator_t **__glusterfs_this_location ()
+{
+ return ((xlator_t **)(uintptr_t)mock());
+}
diff --git a/libglusterfs/src/unittest/log_mock.c b/libglusterfs/src/unittest/log_mock.c
new file mode 100644
index 00000000000..676df7cfdad
--- /dev/null
+++ b/libglusterfs/src/unittest/log_mock.c
@@ -0,0 +1,43 @@
+/*
+ Copyright (c) 2014 Red Hat, Inc. <http://www.redhat.com>
+ This file is part of GlusterFS.
+
+ This file is licensed to you under your choice of the GNU Lesser
+ General Public License, version 3 or any later version (LGPLv3 or
+ later), or the GNU General Public License, version 2 (GPLv2), in all
+ cases as published by the Free Software Foundation.
+*/
+
+#include "logging.h"
+#include "xlator.h"
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <inttypes.h>
+
+#include <cmockery/cmockery.h>
+
+int _gf_log (const char *domain, const char *file,
+ const char *function, int32_t line, gf_loglevel_t level,
+ const char *fmt, ...)
+{
+ return 0;
+}
+
+int _gf_log_callingfn (const char *domain, const char *file,
+ const char *function, int32_t line, gf_loglevel_t level,
+ const char *fmt, ...)
+{
+ return 0;
+}
+
+int _gf_log_nomem (const char *domain, const char *file,
+ const char *function, int line, gf_loglevel_t level,
+ size_t size)
+{
+ return 0;
+}
+
+void
+gf_log_globals_init (void *data) {}
diff --git a/libglusterfs/src/unittest/mem_pool_unittest.c b/libglusterfs/src/unittest/mem_pool_unittest.c
new file mode 100644
index 00000000000..3c0724d65e5
--- /dev/null
+++ b/libglusterfs/src/unittest/mem_pool_unittest.c
@@ -0,0 +1,472 @@
+/*
+ Copyright (c) 2014 Red Hat, Inc. <http://www.redhat.com>
+ This file is part of GlusterFS.
+
+ This file is licensed to you under your choice of the GNU Lesser
+ General Public License, version 3 or any later version (LGPLv3 or
+ later), or the GNU General Public License, version 2 (GPLv2), in all
+ cases as published by the Free Software Foundation.
+*/
+
+#include "mem-pool.h"
+#include "logging.h"
+#include "xlator.h"
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <inttypes.h>
+#include <string.h>
+#include <cmockery/pbc.h>
+#include <cmockery/cmockery.h>
+
+/*
+ * memory header for gf_mem_set_acct_info
+ */
+typedef struct __attribute__((packed)) {
+ uint32_t type;
+ size_t size;
+ xlator_t *xl;
+ uint32_t header_magic;
+ uint8_t pad[8];
+} mem_header_t;
+
+/*
+ * Prototypes to private functions
+ */
+int
+gf_mem_set_acct_info (xlator_t *xl, char **alloc_ptr,
+ size_t size, uint32_t type);
+
+/*
+ * Helper functions
+ */
+static xlator_t *
+helper_xlator_init(uint32_t num_types)
+{
+ xlator_t *xl;
+ int i, ret;
+
+ REQUIRE(num_types > 0);
+
+ xl = test_calloc(1, sizeof(xlator_t));
+ assert_non_null(xl);
+ xl->mem_acct.num_types = num_types;
+ xl->mem_acct.rec = test_calloc(num_types, sizeof(struct mem_acct_rec));
+ assert_non_null(xl->mem_acct.rec);
+
+ xl->ctx = test_calloc(1, sizeof(glusterfs_ctx_t));
+ assert_non_null(xl->ctx);
+
+ for (i = 0; i < num_types; i++) {
+ ret = LOCK_INIT(&(xl->mem_acct.rec[i].lock));
+ assert_int_equal(ret, 0);
+ }
+
+ ENSURE(num_types == xl->mem_acct.num_types);
+ ENSURE(NULL != xl);
+
+ return xl;
+}
+
+static int
+helper_xlator_destroy(xlator_t *xl)
+{
+ int i, ret;
+
+ for (i = 0; i < xl->mem_acct.num_types; i++) {
+ ret = LOCK_DESTROY(&(xl->mem_acct.rec[i].lock));
+ assert_int_equal(ret, 0);
+ }
+
+ free(xl->mem_acct.rec);
+ free(xl->ctx);
+ free(xl);
+ return 0;
+}
+
+static void
+helper_check_memory_headers( char *mem,
+ xlator_t *xl,
+ size_t size,
+ uint32_t type)
+{
+ mem_header_t *p;
+
+ p = (mem_header_t *)mem,
+ assert_int_equal(p->type, type);
+ assert_int_equal(p->size, size);
+ assert_true(p->xl == xl);
+ assert_int_equal(p->header_magic, GF_MEM_HEADER_MAGIC);
+ assert_true(*(uint32_t *)(mem+sizeof(mem_header_t)+size) == GF_MEM_TRAILER_MAGIC);
+
+}
+
+/*
+ * Tests
+ */
+static void
+test_gf_mem_acct_enable_set(void **state)
+{
+ (void) state;
+ glusterfs_ctx_t test_ctx;
+
+ expect_assert_failure(gf_mem_acct_enable_set(NULL));
+
+ memset(&test_ctx, 0, sizeof(test_ctx));
+ assert_true(NULL == test_ctx.process_uuid);
+ gf_mem_acct_enable_set((void *)&test_ctx);
+ assert_true(1 == test_ctx.mem_acct_enable);
+ assert_true(NULL == test_ctx.process_uuid);
+}
+
+static void
+test_gf_mem_set_acct_info_asserts(void **state)
+{
+ xlator_t *xl;
+ xlator_t xltest;
+ char *alloc_ptr;
+ size_t size;
+ uint32_t type;
+
+ memset(&xltest, 0, sizeof(xlator_t));
+ xl = (xlator_t *)0xBADD;
+ alloc_ptr = (char *)0xBADD;
+ size = 8196;
+ type = 0;
+
+
+ // Check xl is NULL
+ expect_assert_failure(gf_mem_set_acct_info(NULL, &alloc_ptr, size, type));
+ // Check xl->mem_acct.rec = NULL
+ expect_assert_failure(gf_mem_set_acct_info(&xltest, &alloc_ptr, 0, type));
+ // Check type <= xl->mem_acct.num_types
+ type = 100;
+ expect_assert_failure(gf_mem_set_acct_info(&xltest, &alloc_ptr, 0, type));
+ // Check alloc is NULL
+ assert_int_equal(-1, gf_mem_set_acct_info(&xltest, NULL, size, type));
+
+ // Initialize xl
+ xl = helper_xlator_init(10);
+
+ // Test number of types
+ type = 100;
+ assert_true(NULL != xl->mem_acct.rec);
+ assert_true(type > xl->mem_acct.num_types);
+ expect_assert_failure(gf_mem_set_acct_info(xl, &alloc_ptr, size, type));
+
+ helper_xlator_destroy(xl);
+}
+
+static void
+test_gf_mem_set_acct_info_memory(void **state)
+{
+ xlator_t *xl;
+ char *alloc_ptr;
+ char *temp_ptr;
+ size_t size;
+ uint32_t type;
+
+ size = 8196;
+ type = 9;
+
+ // Initialize xl
+ xl = helper_xlator_init(10);
+
+ // Test allocation
+ temp_ptr = test_calloc(1, size + GF_MEM_HEADER_SIZE + GF_MEM_TRAILER_SIZE);
+ assert_non_null(temp_ptr);
+ alloc_ptr = temp_ptr;
+ gf_mem_set_acct_info(xl, &alloc_ptr, size, type);
+
+ //Check values
+ assert_int_equal(xl->mem_acct.rec[type].size, size);
+ assert_int_equal(xl->mem_acct.rec[type].num_allocs, 1);
+ assert_int_equal(xl->mem_acct.rec[type].total_allocs, 1);
+ assert_int_equal(xl->mem_acct.rec[type].max_size, size);
+ assert_int_equal(xl->mem_acct.rec[type].max_num_allocs, 1);
+
+ // Check memory
+ helper_check_memory_headers(temp_ptr, xl, size, type);
+
+ // Check that alloc_ptr has been moved correctly
+ // by gf_mem_set_acct_info
+ {
+ mem_header_t *p;
+
+ p = (mem_header_t *)temp_ptr;
+ p++;
+ p->type = 1234;
+ assert_int_equal(*(uint32_t *)alloc_ptr, p->type);
+ }
+
+ free(temp_ptr);
+ helper_xlator_destroy(xl);
+}
+
+static void
+test_gf_calloc_default_calloc(void **state)
+{
+ xlator_t *xl;
+ void *mem;
+ size_t size;
+ uint32_t type;
+
+ // Initialize xl
+ xl = helper_xlator_init(10);
+ assert_int_equal(xl->ctx->mem_acct_enable, 0);
+ will_return(__glusterfs_this_location, &xl);
+
+ // Call __gf_calloc
+ size = 1024;
+ type = 3;
+ mem = __gf_calloc(1, size, type);
+ assert_non_null(mem);
+ memset(mem, 0x5A, size);
+
+ // Check xl did not change
+ assert_int_equal(xl->mem_acct.rec[type].size, 0);
+ assert_int_equal(xl->mem_acct.rec[type].num_allocs, 0);
+ assert_int_equal(xl->mem_acct.rec[type].total_allocs, 0);
+ assert_int_equal(xl->mem_acct.rec[type].max_size, 0);
+ assert_int_equal(xl->mem_acct.rec[type].max_num_allocs, 0);
+
+ free(mem);
+ helper_xlator_destroy(xl);
+}
+
+static void
+test_gf_calloc_mem_acct_enabled(void **state)
+{
+ xlator_t *xl;
+ void *mem;
+ size_t size;
+ uint32_t type;
+
+ // Initialize xl
+ xl = helper_xlator_init(10);
+ assert_int_equal(xl->ctx->mem_acct_enable, 0);
+ xl->ctx->mem_acct_enable = 1;
+
+ // For line mem-pool.c:115 and mem-pool:118
+ will_always_return(__glusterfs_this_location, &xl);
+
+ // Call __gf_calloc
+ size = 1024;
+ type = 3;
+ mem = __gf_calloc(1, size, type);
+ assert_non_null(mem);
+ memset(mem, 0x5A, size);
+
+ // Check xl values
+ assert_int_equal(xl->mem_acct.rec[type].size, size);
+ assert_int_equal(xl->mem_acct.rec[type].num_allocs, 1);
+ assert_int_equal(xl->mem_acct.rec[type].total_allocs, 1);
+ assert_int_equal(xl->mem_acct.rec[type].max_size, size);
+ assert_int_equal(xl->mem_acct.rec[type].max_num_allocs, 1);
+
+ // Check memory
+ helper_check_memory_headers(mem - sizeof(mem_header_t), xl, size, type);
+ free(mem - sizeof(mem_header_t));
+ helper_xlator_destroy(xl);
+}
+
+static void
+test_gf_malloc_default_malloc(void **state)
+{
+ xlator_t *xl;
+ void *mem;
+ size_t size;
+ uint32_t type;
+
+ // Initialize xl
+ xl = helper_xlator_init(10);
+ assert_int_equal(xl->ctx->mem_acct_enable, 0);
+ will_return(__glusterfs_this_location, &xl);
+
+ // Call __gf_malloc
+ size = 1024;
+ type = 3;
+ mem = __gf_malloc(size, type);
+ assert_non_null(mem);
+ memset(mem, 0x5A, size);
+
+ // Check xl did not change
+ assert_int_equal(xl->mem_acct.rec[type].size, 0);
+ assert_int_equal(xl->mem_acct.rec[type].num_allocs, 0);
+ assert_int_equal(xl->mem_acct.rec[type].total_allocs, 0);
+ assert_int_equal(xl->mem_acct.rec[type].max_size, 0);
+ assert_int_equal(xl->mem_acct.rec[type].max_num_allocs, 0);
+
+ free(mem);
+ helper_xlator_destroy(xl);
+}
+
+static void
+test_gf_malloc_mem_acct_enabled(void **state)
+{
+ xlator_t *xl;
+ void *mem;
+ size_t size;
+ uint32_t type;
+
+ // Initialize xl
+ xl = helper_xlator_init(10);
+ assert_int_equal(xl->ctx->mem_acct_enable, 0);
+ xl->ctx->mem_acct_enable = 1;
+
+ // For line mem-pool.c:115 and mem-pool:118
+ will_always_return(__glusterfs_this_location, &xl);
+
+ // Call __gf_malloc
+ size = 1024;
+ type = 3;
+ mem = __gf_malloc(size, type);
+ assert_non_null(mem);
+ memset(mem, 0x5A, size);
+
+ // Check xl values
+ assert_int_equal(xl->mem_acct.rec[type].size, size);
+ assert_int_equal(xl->mem_acct.rec[type].num_allocs, 1);
+ assert_int_equal(xl->mem_acct.rec[type].total_allocs, 1);
+ assert_int_equal(xl->mem_acct.rec[type].max_size, size);
+ assert_int_equal(xl->mem_acct.rec[type].max_num_allocs, 1);
+
+ // Check memory
+ helper_check_memory_headers(mem - sizeof(mem_header_t), xl, size, type);
+ free(mem - sizeof(mem_header_t));
+ helper_xlator_destroy(xl);
+}
+
+static void
+test_gf_realloc_default_realloc(void **state)
+{
+ xlator_t *xl;
+ void *mem;
+ size_t size;
+ uint32_t type;
+
+ // Initialize xl
+ xl = helper_xlator_init(10);
+ assert_int_equal(xl->ctx->mem_acct_enable, 0);
+ will_always_return(__glusterfs_this_location, &xl);
+
+ // Call __gf_malloc then realloc
+ size = 10;
+ type = 3;
+ mem = __gf_malloc(size, type);
+ assert_non_null(mem);
+ memset(mem, 0xA5, size);
+
+ size = 1024;
+ mem = __gf_realloc(mem, size);
+ assert_non_null(mem);
+ memset(mem, 0x5A, size);
+
+ // Check xl did not change
+ assert_int_equal(xl->mem_acct.rec[type].size, 0);
+ assert_int_equal(xl->mem_acct.rec[type].num_allocs, 0);
+ assert_int_equal(xl->mem_acct.rec[type].total_allocs, 0);
+ assert_int_equal(xl->mem_acct.rec[type].max_size, 0);
+ assert_int_equal(xl->mem_acct.rec[type].max_num_allocs, 0);
+
+ free(mem);
+ helper_xlator_destroy(xl);
+}
+
+static void
+test_gf_realloc_mem_acct_enabled(void **state)
+{
+ xlator_t *xl;
+ void *mem;
+ size_t size;
+ uint32_t type;
+
+ // Initialize xl
+ xl = helper_xlator_init(10);
+ assert_int_equal(xl->ctx->mem_acct_enable, 0);
+ xl->ctx->mem_acct_enable = 1;
+
+ // For line mem-pool.c:115 and mem-pool:118
+ will_always_return(__glusterfs_this_location, &xl);
+
+ // Call __gf_malloc then realloc
+ size = 1024;
+ type = 3;
+ mem = __gf_malloc(size, type);
+ assert_non_null(mem);
+ memset(mem, 0xA5, size);
+
+ size = 2048;
+ mem = __gf_realloc(mem, size);
+ assert_non_null(mem);
+ memset(mem, 0x5A, size);
+
+ // Check xl values
+ //
+ // :TODO: This is really weird. I would have expected
+ // xl to only have a size equal to that of the realloc
+ // not to the realloc + the malloc.
+ // Is this a bug?
+ //
+ assert_int_equal(xl->mem_acct.rec[type].size, size+1024);
+ assert_int_equal(xl->mem_acct.rec[type].num_allocs, 2);
+ assert_int_equal(xl->mem_acct.rec[type].total_allocs, 2);
+ assert_int_equal(xl->mem_acct.rec[type].max_size, size+1024);
+ assert_int_equal(xl->mem_acct.rec[type].max_num_allocs, 2);
+
+ // Check memory
+ helper_check_memory_headers(mem - sizeof(mem_header_t), xl, size, type);
+ free(mem - sizeof(mem_header_t));
+ helper_xlator_destroy(xl);
+}
+
+static void
+test_gf_realloc_ptr(void **state)
+{
+ xlator_t *xl;
+ void *mem;
+ size_t size;
+
+ // Initialize xl
+ xl = helper_xlator_init(10);
+ assert_int_equal(xl->ctx->mem_acct_enable, 0);
+
+ // For line mem-pool.c:115 and mem-pool:118
+ will_always_return(__glusterfs_this_location, &xl);
+
+ // Tests according to the manpage for realloc
+
+ // Like a malloc
+ size = 1024;
+ mem = __gf_realloc(NULL, size);
+ assert_non_null(mem);
+ memset(mem, 0xA5, size);
+
+ // Like a free
+ mem = __gf_realloc(mem, 0);
+ assert_null(mem);
+
+ // Now enable xl context
+ xl->ctx->mem_acct_enable = 1;
+ expect_assert_failure(__gf_realloc(NULL, size));
+
+ helper_xlator_destroy(xl);
+}
+
+int main(void) {
+ const UnitTest tests[] = {
+ unit_test(test_gf_mem_acct_enable_set),
+ unit_test(test_gf_mem_set_acct_info_asserts),
+ unit_test(test_gf_mem_set_acct_info_memory),
+ unit_test(test_gf_calloc_default_calloc),
+ unit_test(test_gf_calloc_mem_acct_enabled),
+ unit_test(test_gf_malloc_default_malloc),
+ unit_test(test_gf_malloc_mem_acct_enabled),
+ unit_test(test_gf_realloc_default_realloc),
+ unit_test(test_gf_realloc_mem_acct_enabled),
+ unit_test(test_gf_realloc_ptr),
+ };
+
+ return run_tests(tests, "libglusterfs_mem_pool");
+}
diff --git a/xlators/cluster/dht/src/Makefile.am b/xlators/cluster/dht/src/Makefile.am
index 174bea84110..3032705b5d5 100644
--- a/xlators/cluster/dht/src/Makefile.am
+++ b/xlators/cluster/dht/src/Makefile.am
@@ -36,3 +36,18 @@ uninstall-local:
install-data-hook:
ln -sf dht.so $(DESTDIR)$(xlatordir)/distribute.so
+
+#### UNIT TESTS #####
+CLEANFILES += *.gcda *.gcno *_xunit.xml
+noinst_PROGRAMS =
+TESTS =
+
+dht_layout_unittest_CPPFLAGS = $(UNITTEST_CPPFLAGS) $(AM_CPPFLAGS)
+dht_layout_unittest_SOURCES = unittest/dht_layout_unittest.c \
+ unittest/dht_layout_mock.c \
+ dht-layout.c
+dht_layout_unittest_CFLAGS = $(UNITTEST_CFLAGS)
+dht_layout_unittest_LDADD = $(UNITTEST_LDADD)
+dht_layout_unittest_LDFLAGS = $(UNITTEST_LDFLAGS)
+noinst_PROGRAMS += dht_layout_unittest
+TESTS += dht_layout_unittest
diff --git a/xlators/cluster/dht/src/dht-layout.c b/xlators/cluster/dht/src/dht-layout.c
index 31d85a5060b..deaa493f908 100644
--- a/xlators/cluster/dht/src/dht-layout.c
+++ b/xlators/cluster/dht/src/dht-layout.c
@@ -25,6 +25,19 @@
#define layout_size(cnt) (layout_base_size + (cnt * layout_entry_size))
+#include <cmockery/pbc.h>
+#include <cmockery/cmockery_override.h>
+
+// Change GF_CALLOC and GF_FREE to use
+// cmockery2 memory allocation versions
+#ifdef UNIT_TESTING
+#undef GF_CALLOC
+#define GF_CALLOC(n, s, t) test_calloc(n, s)
+#undef GF_FREE
+#define GF_FREE test_free
+#endif
+
+
dht_layout_t *
dht_layout_new (xlator_t *this, int cnt)
@@ -32,6 +45,8 @@ dht_layout_new (xlator_t *this, int cnt)
dht_layout_t *layout = NULL;
dht_conf_t *conf = NULL;
+ REQUIRE(NULL != this);
+ REQUIRE(cnt >= 0);
conf = this->private;
@@ -50,6 +65,11 @@ dht_layout_new (xlator_t *this, int cnt)
}
layout->ref = 1;
+
+ ENSURE(NULL != layout);
+ ENSURE(layout->type == DHT_HASH_TYPE_DM);
+ ENSURE(layout->cnt == cnt);
+ ENSURE(layout->ref == 1);
out:
return layout;
}
diff --git a/xlators/cluster/dht/src/unittest/dht_layout_mock.c b/xlators/cluster/dht/src/unittest/dht_layout_mock.c
new file mode 100644
index 00000000000..aa19ddc575d
--- /dev/null
+++ b/xlators/cluster/dht/src/unittest/dht_layout_mock.c
@@ -0,0 +1,63 @@
+/*
+ Copyright (c) 2014 Red Hat, Inc. <http://www.redhat.com>
+ This file is part of GlusterFS.
+
+ This file is licensed to you under your choice of the GNU Lesser
+ General Public License, version 3 or any later version (LGPLv3 or
+ later), or the GNU General Public License, version 2 (GPLv2), in all
+ cases as published by the Free Software Foundation.
+*/
+#ifndef _CONFIG_H
+#define _CONFIG_H
+#include "config.h"
+#endif
+
+#include "glusterfs.h"
+#include "xlator.h"
+#include "dht-common.h"
+#include "byte-order.h"
+
+int
+dht_hash_compute (xlator_t *this, int type, const char *name, uint32_t *hash_p)
+{
+ return 0;
+}
+
+int
+dht_inode_ctx_layout_get (inode_t *inode, xlator_t *this, dht_layout_t **layout)
+{
+ return 0;
+}
+
+int
+dht_inode_ctx_layout_set (inode_t *inode, xlator_t *this,
+ dht_layout_t *layout_int)
+{
+ return 0;
+}
+
+int
+dict_get_ptr (dict_t *this, char *key, void **ptr)
+{
+ return 0;
+}
+
+int
+dict_get_ptr_and_len (dict_t *this, char *key, void **ptr, int *len)
+{
+ return 0;
+}
+
+int _gf_log (const char *domain, const char *file,
+ const char *function, int32_t line, gf_loglevel_t level,
+ const char *fmt, ...)
+{
+ return 0;
+}
+
+int _gf_log_callingfn (const char *domain, const char *file,
+ const char *function, int32_t line, gf_loglevel_t level,
+ const char *fmt, ...)
+{
+ return 0;
+}
diff --git a/xlators/cluster/dht/src/unittest/dht_layout_unittest.c b/xlators/cluster/dht/src/unittest/dht_layout_unittest.c
new file mode 100644
index 00000000000..b5233d235d0
--- /dev/null
+++ b/xlators/cluster/dht/src/unittest/dht_layout_unittest.c
@@ -0,0 +1,124 @@
+/*
+ Copyright (c) 2008-2014 Red Hat, Inc. <http://www.redhat.com>
+ This file is part of GlusterFS.
+
+ This file is licensed to you under your choice of the GNU Lesser
+ General Public License, version 3 or any later version (LGPLv3 or
+ later), or the GNU General Public License, version 2 (GPLv2), in all
+ cases as published by the Free Software Foundation.
+*/
+
+#include "dht-common.h"
+#include "logging.h"
+#include "xlator.h"
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <inttypes.h>
+#include <cmockery/pbc.h>
+#include <cmockery/cmockery.h>
+
+/*
+ * Helper functions
+ */
+
+static xlator_t *
+helper_xlator_init(uint32_t num_types)
+{
+ xlator_t *xl;
+ int i, ret;
+
+ REQUIRE(num_types > 0);
+
+ xl = test_calloc(1, sizeof(xlator_t));
+ assert_non_null(xl);
+ xl->mem_acct.num_types = num_types;
+ xl->mem_acct.rec = test_calloc(num_types, sizeof(struct mem_acct_rec));
+ assert_non_null(xl->mem_acct.rec);
+
+ xl->ctx = test_calloc(1, sizeof(glusterfs_ctx_t));
+ assert_non_null(xl->ctx);
+
+ for (i = 0; i < num_types; i++) {
+ ret = LOCK_INIT(&(xl->mem_acct.rec[i].lock));
+ assert_false(ret);
+ }
+
+ ENSURE(num_types == xl->mem_acct.num_types);
+ ENSURE(NULL != xl);
+
+ return xl;
+}
+
+static int
+helper_xlator_destroy(xlator_t *xl)
+{
+ int i, ret;
+
+ for (i = 0; i < xl->mem_acct.num_types; i++) {
+ ret = LOCK_DESTROY(&(xl->mem_acct.rec[i].lock));
+ assert_int_equal(ret, 0);
+ }
+
+ free(xl->mem_acct.rec);
+ free(xl->ctx);
+ free(xl);
+ return 0;
+}
+
+/*
+ * Unit tests
+ */
+static void
+test_dht_layout_new(void **state)
+{
+ xlator_t *xl;
+ dht_layout_t *layout;
+ dht_conf_t *conf;
+ int cnt;
+
+ expect_assert_failure(dht_layout_new(NULL, 0));
+ expect_assert_failure(dht_layout_new((xlator_t *)0x12345, -1));
+ xl = helper_xlator_init(10);
+
+ // xl->private is NULL
+ assert_null(xl->private);
+ cnt = 100;
+ layout = dht_layout_new(xl, cnt);
+ assert_non_null(layout);
+ assert_int_equal(layout->type, DHT_HASH_TYPE_DM);
+ assert_int_equal(layout->cnt, cnt);
+ assert_int_equal(layout->ref, 1);
+ assert_int_equal(layout->gen, 0);
+ assert_int_equal(layout->spread_cnt, 0);
+ free(layout);
+
+ // xl->private is not NULL
+ cnt = 110;
+ conf = (dht_conf_t *)test_calloc(1, sizeof(dht_conf_t));
+ assert_non_null(conf);
+ conf->dir_spread_cnt = 12345;
+ conf->gen = -123;
+ xl->private = conf;
+
+ layout = dht_layout_new(xl, cnt);
+ assert_non_null(layout);
+ assert_int_equal(layout->type, DHT_HASH_TYPE_DM);
+ assert_int_equal(layout->cnt, cnt);
+ assert_int_equal(layout->ref, 1);
+ assert_int_equal(layout->gen, conf->gen);
+ assert_int_equal(layout->spread_cnt, conf->dir_spread_cnt);
+ free(layout);
+
+ free(conf);
+ helper_xlator_destroy(xl);
+}
+
+int main(void) {
+ const UnitTest tests[] = {
+ unit_test(test_dht_layout_new),
+ };
+
+ return run_tests(tests, "xlator_dht_layout");
+}
diff --git a/xlators/storage/posix/src/posix-helpers.c b/xlators/storage/posix/src/posix-helpers.c
index 2cf46669e57..5725cad7d92 100644
--- a/xlators/storage/posix/src/posix-helpers.c
+++ b/xlators/storage/posix/src/posix-helpers.c
@@ -266,6 +266,16 @@ _posix_xattr_get_set (dict_t *xattr_req,
goto err;
}
+ /*
+ * There could be a situation where the ia_size is
+ * zero. GF_CALLOC will return a pointer to the
+ * memory initialized by gf_mem_set_acct_info.
+ * This function adds a header and a footer to
+ * the allocated memory. The returned pointer
+ * points to the memory just after the header, but
+ * when size is zero, there is no space for user
+ * data. The memory can be freed by calling GF_FREE.
+ */
databuf = GF_CALLOC (1, filler->stbuf->ia_size,
gf_posix_mt_char);
if (!databuf) {