From: "Mihai Donțu" <mdontu@bitdefender.com>
To: Andrew Cooper <andrew.cooper3@citrix.com>
Cc: keir@xen.org, ian.campbell@citrix.com, tim@xen.org,
ian.jackson@eu.citrix.com, xen-devel@lists.xen.org,
jbeulich@suse.com
Subject: Re: [PATCH v4] xmalloc: add support for checking the pool integrity
Date: Tue, 12 May 2015 21:14:50 +0300 [thread overview]
Message-ID: <20150512211450.3658555e@bitdefender.com> (raw)
In-Reply-To: <54AD8706.5020802@citrix.com>
On Wednesday 07 January 2015 19:20:38 Andrew Cooper wrote:
> On 16/12/14 19:33, Mihai Donțu wrote:
> > Implemented xmem_pool_check(), xmem_pool_check_locked() and
> > xmem_pool_check_unlocked() to verity the integrity of the TLSF matrix.
> >
> > Signed-off-by: Mihai Donțu <mdontu@bitdefender.com>
>
> This review supersedes (and is adjusted accordingly for) the two
> discussion threads which happened off my first review.
>
> >
> > ---
> > Changes since v3:
> > - try harder to respect the 80 column limit
> > - use 'unsigned int' instead of 'int' where possible
> > - made the logged messages even shorter
> > - dropped the use of goto (didn't really make sense)
> >
> > Changes since v2:
> > - print the name of the corrupted pool
> > - adjusted the messages to better fit within 80 columns
> > - minor style change (a ? a : b -> a ?: b)
> >
> > Changes since v1:
> > - fixed the codingstyle
> > - swaped _locked/_unlocked naming
> > - reworked __xmem_pool_check_locked() a bit
> > - used bool_t where appropriate
> > - made xmem_pool_check() take a pool argument which can be NULL
> > ---
> > xen/common/xmalloc_tlsf.c | 121 +++++++++++++++++++++++++++++++++++++++++++++-
> > xen/include/xen/xmalloc.h | 7 +++
> > 2 files changed, 126 insertions(+), 2 deletions(-)
> >
> > diff --git a/xen/common/xmalloc_tlsf.c b/xen/common/xmalloc_tlsf.c
> > index a5769c9..eca4f1c 100644
> > --- a/xen/common/xmalloc_tlsf.c
> > +++ b/xen/common/xmalloc_tlsf.c
> > @@ -120,9 +120,122 @@ struct xmem_pool {
> > char name[MAX_POOL_NAME_LEN];
> > };
> >
> > +static struct xmem_pool *xenpool;
> > +
> > +static inline void MAPPING_INSERT(unsigned long r, int *fl, int *sl);
> > +
> > /*
> > * Helping functions
> > */
> > +#ifndef NDEBUG
> > +static bool_t xmem_pool_check_size(const struct xmem_pool *pool,
> > + int fl, int sl)
> > +{
> > + const struct bhdr *b = pool->matrix[fl][sl];
> > +
> > + while ( b )
> > + {
> > + int __fl;
> > + int __sl;
> > +
> > + MAPPING_INSERT(b->size, &__fl, &__sl);
> > + if ( __fl != fl || __sl != sl )
> > + {
> > + printk(XENLOG_ERR
> > + "xmem_pool: %s: misplaced block %p:%u ({%d,%d} -> {%d,%d})\n",
> > + pool->name, b, b->size, fl, sl, __fl, __sl);
>
> Is it liable to get confusing with a hex number and a decimal number
> combined with just a colon?
>
> Is b even a useful pointer to print? You have the pool name, indicies
> and size which seem to be the salient information.
>
I think you are right. I went ahead and printed all information
available just because I had access to it thinking someone other than
myself might find it valuable.
> > + return 0;
> > + }
> > + b = b->ptr.free_ptr.next;
> > + }
> > + return 1;
> > +}
> > +
> > +/*
> > + * This function must be called from a context where pool->lock is
> > + * already acquired.
> > + *
> > + * Returns true if the pool has been corrupted, false otherwise
> > + */
> > +#define xmem_pool_check_locked(pool) \
> > + __xmem_pool_check_locked(__FILE__, __LINE__, pool)
> > +static bool_t __xmem_pool_check_locked(const char *file, int line,
> > + const struct xmem_pool *pool)
> > +{
> > + unsigned int i;
> > + static bool_t once = 1;
> > +
> > + if ( !once )
> > + return 1;
> > + for ( i = 0; i < REAL_FLI; i++ )
> > + {
> > + int fl = (pool->fl_bitmap & (1 << i)) ? i : -1;
> > +
> > + if ( fl >= 0 )
> > + {
> > + unsigned int j;
> > +
> > + if ( !pool->sl_bitmap[fl] )
> > + {
> > + printk(XENLOG_ERR
> > + "xmem_pool: %s: TLSF bitmap corrupt (!empty FL, empty SL)\n",
> > + pool->name);
> > + __warn(file, line);
> > + once = 0;
> > + break;
> > + }
> > + for ( j = 0; j < MAX_SLI; j++ )
> > + {
> > + int sl = (pool->sl_bitmap[fl] & (1 << j)) ? j : -1;
> > +
> > + if ( sl < 0 )
> > + continue;
> > + if ( !pool->matrix[fl][sl] )
> > + {
> > + printk(XENLOG_ERR
> > + "xmem_pool: %s: TLSF bitmap corrupt (!matrix[%d][%d])\n",
> > + pool->name, fl, sl);
> > + __warn(file, line);
> > + once = 0;
> > + break;
> > + }
> > + if ( !xmem_pool_check_size(pool, fl, sl) )
> > + {
> > + printk(XENLOG_ERR "xmem_pool: %s: TLSF chunk matrix corrupt\n",
> > + pool->name);
> > + __warn(file, line);
> > + once = 0;
> > + break;
> > + }
> > + }
> > + if ( !once )
> > + break;
> > + }
> > + }
> > + return !once;
> > +}
>
> I want to remove __bug() and __warn() because they are currently unused
> in the code, and are a cludge on ARM (lack of working
> run_in_exception_handler()). You can use BUG()/WARN() instead, which
> will work as expected ARM.
>
> However, once memory corruption has been detected, all bets are off
> regarding correct functioning of the host. I would suggest printing as
> much error information as possible and using BUG() to bring Xen down.
> This allows you to remove 'once' (dubious being static, yet applying to
> arbitrary xmem pools), and to change the function to be void.
>
I used the 'once' variable to keep the code from spamming dmesg. I
figured once one sees the message, he/she knows things are about to go
downhill.
I will use BUG().
> > +
> > +#define xmem_pool_check_unlocked(pool) \
> > + __xmem_pool_check_unlocked(__FILE__, __LINE__, pool)
> > +static bool_t __xmem_pool_check_unlocked(const char *file, int line,
> > + struct xmem_pool *pool)
> > +{
> > + bool_t oops;
> > +
> > + spin_lock(&pool->lock);
> > + oops = __xmem_pool_check_locked(file, line, pool);
> > + spin_unlock(&pool->lock);
> > + return oops;
> > +}
> > +
> > +bool_t __xmem_pool_check(const char *file, int line, struct xmem_pool *pool)
> > +{
> > + return __xmem_pool_check_unlocked(file, line, pool ?: xenpool);
> > +}
> > +#else
> > +#define xmem_pool_check_locked(pool) ((void)(pool))
> > +#define xmem_pool_check_unlocked(pool) ((void)(pool))
> > +#endif
> >
> > /**
> > * Returns indexes (fl, sl) of the list used to serve request of size r
> > @@ -381,6 +494,8 @@ void *xmem_pool_alloc(unsigned long size, struct xmem_pool *pool)
> > int fl, sl;
> > unsigned long tmp_size;
> >
> > + xmem_pool_check_unlocked(pool);
> > +
> > if ( pool->init_region == NULL )
> > {
> > if ( (region = pool->get_mem(pool->init_size)) == NULL )
> > @@ -442,11 +557,13 @@ void *xmem_pool_alloc(unsigned long size, struct xmem_pool *pool)
> >
> > pool->used_size += (b->size & BLOCK_SIZE_MASK) + BHDR_OVERHEAD;
> >
> > + xmem_pool_check_locked(pool);
> > spin_unlock(&pool->lock);
> > return (void *)b->ptr.buffer;
> >
> > /* Failed alloc */
> > out_locked:
> > + xmem_pool_check_locked(pool);
> > spin_unlock(&pool->lock);
> >
> > out:
> > @@ -464,6 +581,7 @@ void xmem_pool_free(void *ptr, struct xmem_pool *pool)
> > b = (struct bhdr *)((char *) ptr - BHDR_OVERHEAD);
> >
> > spin_lock(&pool->lock);
> > + xmem_pool_check_locked(pool);
> > b->size |= FREE_BLOCK;
> > pool->used_size -= (b->size & BLOCK_SIZE_MASK) + BHDR_OVERHEAD;
> > b->ptr.free_ptr = (struct free_ptr) { NULL, NULL};
> > @@ -500,6 +618,7 @@ void xmem_pool_free(void *ptr, struct xmem_pool *pool)
> > tmp_b->size |= PREV_FREE;
> > tmp_b->prev_hdr = b;
> > out:
> > + xmem_pool_check_locked(pool);
> > spin_unlock(&pool->lock);
> > }
> >
> > @@ -512,8 +631,6 @@ int xmem_pool_maxalloc(struct xmem_pool *pool)
> > * Glue for xmalloc().
> > */
> >
> > -static struct xmem_pool *xenpool;
> > -
> > static void *xmalloc_pool_get(unsigned long size)
> > {
> > ASSERT(size == PAGE_SIZE);
> > diff --git a/xen/include/xen/xmalloc.h b/xen/include/xen/xmalloc.h
> > index 24a99ac..ad48930 100644
> > --- a/xen/include/xen/xmalloc.h
> > +++ b/xen/include/xen/xmalloc.h
> > @@ -123,4 +123,11 @@ unsigned long xmem_pool_get_used_size(struct xmem_pool *pool);
> > */
> > unsigned long xmem_pool_get_total_size(struct xmem_pool *pool);
> >
> > +#ifndef NDEBUG
> > +#define xmem_pool_check(pool) __xmem_pool_check(__FILE__, __LINE__, pool)
> > +bool_t __xmem_pool_check(const char *file, int line, struct xmem_pool *pool);
> > +#else
> > +#define xmem_pool_check(pool) ((void)0)
>
> This needs to be ((void)(pool)) to evaluate the potential side effects.
>
>
> What are the overheads of pool consistency checking? It looks to be
> moderately high, given a full inspection of the matrix on each
> allocation and free. Would it be possible to have one easier-to-alter
> compile time knob so the default can be overridden in a single location?
In my tests, I have not noticed a slowdown, or maybe Haswells these
days are that good.
> Perhaps something like:
>
> #ifndef NDEBUG
> #define XMEM_POOL_CHECKS
> #endif
>
> #ifdef XMEM_POOL_CHECKS
> ...
> #else
> ...
> #endif
Sure thing. My interest is in only having an upstream method to detect
these, other than a patch somewhere on my disk.
Thank you,
--
Mihai DONȚU
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel
prev parent reply other threads:[~2015-05-12 18:14 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-12-16 19:33 [PATCH v4] xmalloc: add support for checking the pool integrity Mihai Donțu
2014-12-16 20:28 ` Andrew Cooper
2014-12-16 23:06 ` Julien Grall
2014-12-16 23:26 ` Andrew Cooper
2014-12-16 23:37 ` Julien Grall
2014-12-17 10:11 ` Andrew Cooper
2014-12-17 10:24 ` Julien Grall
2014-12-17 10:39 ` Andrew Cooper
2014-12-17 10:40 ` Jan Beulich
2014-12-17 12:46 ` Julien Grall
2014-12-17 9:59 ` Jan Beulich
2014-12-17 10:08 ` Andrew Cooper
2014-12-17 10:22 ` Jan Beulich
2015-01-07 15:41 ` Jan Beulich
2015-01-07 15:52 ` Andrew Cooper
2015-01-07 19:20 ` Andrew Cooper
2015-05-12 18:14 ` Mihai Donțu [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20150512211450.3658555e@bitdefender.com \
--to=mdontu@bitdefender.com \
--cc=andrew.cooper3@citrix.com \
--cc=ian.campbell@citrix.com \
--cc=ian.jackson@eu.citrix.com \
--cc=jbeulich@suse.com \
--cc=keir@xen.org \
--cc=tim@xen.org \
--cc=xen-devel@lists.xen.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.