cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

string-stream.c (4860B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * C++ stream style string builder used in KUnit for building messages.
      4 *
      5 * Copyright (C) 2019, Google LLC.
      6 * Author: Brendan Higgins <brendanhiggins@google.com>
      7 */
      8
      9#include <kunit/test.h>
     10#include <linux/list.h>
     11#include <linux/slab.h>
     12
     13#include "string-stream.h"
     14
     15struct string_stream_fragment_alloc_context {
     16	struct kunit *test;
     17	int len;
     18	gfp_t gfp;
     19};
     20
     21static int string_stream_fragment_init(struct kunit_resource *res,
     22				       void *context)
     23{
     24	struct string_stream_fragment_alloc_context *ctx = context;
     25	struct string_stream_fragment *frag;
     26
     27	frag = kunit_kzalloc(ctx->test, sizeof(*frag), ctx->gfp);
     28	if (!frag)
     29		return -ENOMEM;
     30
     31	frag->test = ctx->test;
     32	frag->fragment = kunit_kmalloc(ctx->test, ctx->len, ctx->gfp);
     33	if (!frag->fragment)
     34		return -ENOMEM;
     35
     36	res->data = frag;
     37
     38	return 0;
     39}
     40
     41static void string_stream_fragment_free(struct kunit_resource *res)
     42{
     43	struct string_stream_fragment *frag = res->data;
     44
     45	list_del(&frag->node);
     46	kunit_kfree(frag->test, frag->fragment);
     47	kunit_kfree(frag->test, frag);
     48}
     49
     50static struct string_stream_fragment *alloc_string_stream_fragment(
     51		struct kunit *test, int len, gfp_t gfp)
     52{
     53	struct string_stream_fragment_alloc_context context = {
     54		.test = test,
     55		.len = len,
     56		.gfp = gfp
     57	};
     58
     59	return kunit_alloc_resource(test,
     60				    string_stream_fragment_init,
     61				    string_stream_fragment_free,
     62				    gfp,
     63				    &context);
     64}
     65
     66static int string_stream_fragment_destroy(struct string_stream_fragment *frag)
     67{
     68	return kunit_destroy_resource(frag->test,
     69				      kunit_resource_instance_match,
     70				      frag);
     71}
     72
     73int string_stream_vadd(struct string_stream *stream,
     74		       const char *fmt,
     75		       va_list args)
     76{
     77	struct string_stream_fragment *frag_container;
     78	int len;
     79	va_list args_for_counting;
     80
     81	/* Make a copy because `vsnprintf` could change it */
     82	va_copy(args_for_counting, args);
     83
     84	/* Need space for null byte. */
     85	len = vsnprintf(NULL, 0, fmt, args_for_counting) + 1;
     86
     87	va_end(args_for_counting);
     88
     89	frag_container = alloc_string_stream_fragment(stream->test,
     90						      len,
     91						      stream->gfp);
     92	if (!frag_container)
     93		return -ENOMEM;
     94
     95	len = vsnprintf(frag_container->fragment, len, fmt, args);
     96	spin_lock(&stream->lock);
     97	stream->length += len;
     98	list_add_tail(&frag_container->node, &stream->fragments);
     99	spin_unlock(&stream->lock);
    100
    101	return 0;
    102}
    103
    104int string_stream_add(struct string_stream *stream, const char *fmt, ...)
    105{
    106	va_list args;
    107	int result;
    108
    109	va_start(args, fmt);
    110	result = string_stream_vadd(stream, fmt, args);
    111	va_end(args);
    112
    113	return result;
    114}
    115
    116static void string_stream_clear(struct string_stream *stream)
    117{
    118	struct string_stream_fragment *frag_container, *frag_container_safe;
    119
    120	spin_lock(&stream->lock);
    121	list_for_each_entry_safe(frag_container,
    122				 frag_container_safe,
    123				 &stream->fragments,
    124				 node) {
    125		string_stream_fragment_destroy(frag_container);
    126	}
    127	stream->length = 0;
    128	spin_unlock(&stream->lock);
    129}
    130
    131char *string_stream_get_string(struct string_stream *stream)
    132{
    133	struct string_stream_fragment *frag_container;
    134	size_t buf_len = stream->length + 1; /* +1 for null byte. */
    135	char *buf;
    136
    137	buf = kunit_kzalloc(stream->test, buf_len, stream->gfp);
    138	if (!buf)
    139		return NULL;
    140
    141	spin_lock(&stream->lock);
    142	list_for_each_entry(frag_container, &stream->fragments, node)
    143		strlcat(buf, frag_container->fragment, buf_len);
    144	spin_unlock(&stream->lock);
    145
    146	return buf;
    147}
    148
    149int string_stream_append(struct string_stream *stream,
    150			 struct string_stream *other)
    151{
    152	const char *other_content;
    153
    154	other_content = string_stream_get_string(other);
    155
    156	if (!other_content)
    157		return -ENOMEM;
    158
    159	return string_stream_add(stream, other_content);
    160}
    161
    162bool string_stream_is_empty(struct string_stream *stream)
    163{
    164	return list_empty(&stream->fragments);
    165}
    166
    167struct string_stream_alloc_context {
    168	struct kunit *test;
    169	gfp_t gfp;
    170};
    171
    172static int string_stream_init(struct kunit_resource *res, void *context)
    173{
    174	struct string_stream *stream;
    175	struct string_stream_alloc_context *ctx = context;
    176
    177	stream = kunit_kzalloc(ctx->test, sizeof(*stream), ctx->gfp);
    178	if (!stream)
    179		return -ENOMEM;
    180
    181	res->data = stream;
    182	stream->gfp = ctx->gfp;
    183	stream->test = ctx->test;
    184	INIT_LIST_HEAD(&stream->fragments);
    185	spin_lock_init(&stream->lock);
    186
    187	return 0;
    188}
    189
    190static void string_stream_free(struct kunit_resource *res)
    191{
    192	struct string_stream *stream = res->data;
    193
    194	string_stream_clear(stream);
    195}
    196
    197struct string_stream *alloc_string_stream(struct kunit *test, gfp_t gfp)
    198{
    199	struct string_stream_alloc_context context = {
    200		.test = test,
    201		.gfp = gfp
    202	};
    203
    204	return kunit_alloc_resource(test,
    205				    string_stream_init,
    206				    string_stream_free,
    207				    gfp,
    208				    &context);
    209}
    210
    211int string_stream_destroy(struct string_stream *stream)
    212{
    213	return kunit_destroy_resource(stream->test,
    214				      kunit_resource_instance_match,
    215				      stream);
    216}