1
0
Fork 0
forked from len0rd/rockbox

Dircache: Improve freed name memory recallocation

There's only a need to check every MAX_TINYNAME+1 bytes and that the
last character of the needed size 0xff in order to verify the size
of the block since the minimum indirectly-stored string is
MAX_TINYNAME+1.

Change-Id: Ic789376b8575bab9266fcd54c610db0961de5d7f
This commit is contained in:
Michael Sevakis 2017-01-18 08:29:54 -05:00
parent 05739efe8d
commit bfd04df480

View file

@ -781,56 +781,66 @@ static int alloc_name(size_t size)
if (dircache.namesfree >= size) if (dircache.namesfree >= size)
{ {
/* scan for a free gap starting at the hint point - first fit */ /* scan for a free gap starting at the hint point - first fit */
unsigned char *start = get_name(dircache.nextnamefree), *p = start; unsigned char * const start = get_name(dircache.nextnamefree);
unsigned char *namesend = get_name(dircache.names + dircache.sizenames); unsigned char * const bufend = get_name(dircache.names + dircache.sizenames);
size_t gapsize = 0; unsigned char *p = start;
unsigned char *end = bufend;
while (gapsize < size) while (1)
{ {
if ((p = memchr(p, 0xff, namesend - p))) if ((size_t)(bufend - p) >= size && (p = memchr(p, 0xff, end - p)))
{ {
/* found a sentinel; see if there are enough in a row */ /* found a sentinel; see if there are enough in a row */
gapsize = 1; unsigned char *q = p + size - 1;
while (*++p == 0xff && gapsize < size)
gapsize++; /* check end byte and every MAX_TINYNAME+1 bytes from the end;
the minimum-length indirectly allocated string that could be
in between must have at least one character at one of those
locations */
while (q > p && *q == 0xff)
q -= MAX_TINYNAME+1;
if (q <= p)
{
nameidx = get_nameidx(p);
break;
}
p += size;
} }
else else
{ {
if (namesend == start) if (end == start)
break; /* exhausted */ break; /* exhausted */
/* wrap */ /* wrap */
namesend = start; end = start;
p = get_name(dircache.names); p = get_name(dircache.names);
if (p == namesend) if (p == end)
break; /* initial hint was at names start */ break; /* initial hint was at names start */
} }
} }
if (gapsize >= size) if (nameidx)
{ {
unsigned char *namep = p - gapsize; unsigned char *q = p + size;
nameidx = get_nameidx(namep); if (q[0] == 0xff && q[MAX_TINYNAME] != 0xff)
if (*p == 0xff)
{ {
/* if only a tiny block remains after buffer, claim it too */ /* if only a tiny block remains after buffer, claim it and
size_t tinysize = 1; hide it from scans since it's too small for indirect
while (*++p == 0xff && tinysize <= MAX_TINYNAME) allocation */
tinysize++; do
if (tinysize <= MAX_TINYNAME)
{ {
/* mark with tiny block sentinel */ *q = 0xfe;
memset(p - tinysize, 0xfe, tinysize); size++;
size += tinysize;
} }
while (*++q == 0xff);
} }
dircache.namesfree -= size; dircache.namesfree -= size;
dircache.sizeused += size; dircache.sizeused += size;
set_namesfree_hint(namep + size); set_namesfree_hint(p + size);
} }
} }