diff options
author | Michael Sevakis <jethead71@rockbox.org> | 2017-01-18 08:29:54 -0500 |
---|---|---|
committer | Michael Sevakis <jethead71@rockbox.org> | 2017-03-21 23:11:55 -0400 |
commit | bfd04df4807197261b9d36f16c5788a733129c05 (patch) | |
tree | d86208f0908516579fb7324fa880e8baef191d98 /firmware/common | |
parent | 05739efe8d9df2a83b983a86d07cb0715c6d19ee (diff) | |
download | rockbox-bfd04df4807197261b9d36f16c5788a733129c05.tar.gz rockbox-bfd04df4807197261b9d36f16c5788a733129c05.zip |
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
Diffstat (limited to 'firmware/common')
-rw-r--r-- | firmware/common/dircache.c | 62 |
1 files changed, 36 insertions, 26 deletions
diff --git a/firmware/common/dircache.c b/firmware/common/dircache.c index e8f149cad0..0cdaf1bd4a 100644 --- a/firmware/common/dircache.c +++ b/firmware/common/dircache.c | |||
@@ -781,56 +781,66 @@ static int alloc_name(size_t size) | |||
781 | if (dircache.namesfree >= size) | 781 | if (dircache.namesfree >= size) |
782 | { | 782 | { |
783 | /* scan for a free gap starting at the hint point - first fit */ | 783 | /* scan for a free gap starting at the hint point - first fit */ |
784 | unsigned char *start = get_name(dircache.nextnamefree), *p = start; | 784 | unsigned char * const start = get_name(dircache.nextnamefree); |
785 | unsigned char *namesend = get_name(dircache.names + dircache.sizenames); | 785 | unsigned char * const bufend = get_name(dircache.names + dircache.sizenames); |
786 | size_t gapsize = 0; | 786 | unsigned char *p = start; |
787 | unsigned char *end = bufend; | ||
787 | 788 | ||
788 | while (gapsize < size) | 789 | while (1) |
789 | { | 790 | { |
790 | if ((p = memchr(p, 0xff, namesend - p))) | 791 | if ((size_t)(bufend - p) >= size && (p = memchr(p, 0xff, end - p))) |
791 | { | 792 | { |
792 | /* found a sentinel; see if there are enough in a row */ | 793 | /* found a sentinel; see if there are enough in a row */ |
793 | gapsize = 1; | 794 | unsigned char *q = p + size - 1; |
794 | while (*++p == 0xff && gapsize < size) | 795 | |
795 | gapsize++; | 796 | /* check end byte and every MAX_TINYNAME+1 bytes from the end; |
797 | the minimum-length indirectly allocated string that could be | ||
798 | in between must have at least one character at one of those | ||
799 | locations */ | ||
800 | while (q > p && *q == 0xff) | ||
801 | q -= MAX_TINYNAME+1; | ||
802 | |||
803 | if (q <= p) | ||
804 | { | ||
805 | nameidx = get_nameidx(p); | ||
806 | break; | ||
807 | } | ||
808 | |||
809 | p += size; | ||
796 | } | 810 | } |
797 | else | 811 | else |
798 | { | 812 | { |
799 | if (namesend == start) | 813 | if (end == start) |
800 | break; /* exhausted */ | 814 | break; /* exhausted */ |
801 | 815 | ||
802 | /* wrap */ | 816 | /* wrap */ |
803 | namesend = start; | 817 | end = start; |
804 | p = get_name(dircache.names); | 818 | p = get_name(dircache.names); |
805 | 819 | ||
806 | if (p == namesend) | 820 | if (p == end) |
807 | break; /* initial hint was at names start */ | 821 | break; /* initial hint was at names start */ |
808 | } | 822 | } |
809 | } | 823 | } |
810 | 824 | ||
811 | if (gapsize >= size) | 825 | if (nameidx) |
812 | { | 826 | { |
813 | unsigned char *namep = p - gapsize; | 827 | unsigned char *q = p + size; |
814 | nameidx = get_nameidx(namep); | 828 | if (q[0] == 0xff && q[MAX_TINYNAME] != 0xff) |
815 | |||
816 | if (*p == 0xff) | ||
817 | { | 829 | { |
818 | /* if only a tiny block remains after buffer, claim it too */ | 830 | /* if only a tiny block remains after buffer, claim it and |
819 | size_t tinysize = 1; | 831 | hide it from scans since it's too small for indirect |
820 | while (*++p == 0xff && tinysize <= MAX_TINYNAME) | 832 | allocation */ |
821 | tinysize++; | 833 | do |
822 | |||
823 | if (tinysize <= MAX_TINYNAME) | ||
824 | { | 834 | { |
825 | /* mark with tiny block sentinel */ | 835 | *q = 0xfe; |
826 | memset(p - tinysize, 0xfe, tinysize); | 836 | size++; |
827 | size += tinysize; | ||
828 | } | 837 | } |
838 | while (*++q == 0xff); | ||
829 | } | 839 | } |
830 | 840 | ||
831 | dircache.namesfree -= size; | 841 | dircache.namesfree -= size; |
832 | dircache.sizeused += size; | 842 | dircache.sizeused += size; |
833 | set_namesfree_hint(namep + size); | 843 | set_namesfree_hint(p + size); |
834 | } | 844 | } |
835 | } | 845 | } |
836 | 846 | ||