From: Li Ruilin liruilin4@huawei.com
euleros inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4LOJ6 CVE: NA
------------------------------
Add a sample for new prefetch frame on bcache. As a sample, the program just reads every read request received by bcache device and send a prefetch request for each read request. The length of the prefetch request is equal as the read request and the position of the prefetch request is follow the read request.
Signed-off-by: Li Ruilin liruilin4@huawei.com Reviewed-by: Luan Jianhai luanjianhai@huawei.com Reviewed-by: Peng Junyi pengjunyi1@huawei.com Acked-by: Xie Xiuqi xiexiuqi@huawei.com Signed-off-by: Cheng Jian cj.chengjian@huawei.com Reviewed-by: Guangxing Deng dengguangxing@huawei.com Reviewed-by: chao song chao.song@huawei.com Reviewed-by: chao song chao.song@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- samples/acache_client/Makefile | 13 +++ samples/acache_client/connect.c | 144 ++++++++++++++++++++++++++++++++ samples/acache_client/connect.h | 74 ++++++++++++++++ samples/acache_client/main.c | 133 +++++++++++++++++++++++++++++ 4 files changed, 364 insertions(+) create mode 100644 samples/acache_client/Makefile create mode 100644 samples/acache_client/connect.c create mode 100644 samples/acache_client/connect.h create mode 100644 samples/acache_client/main.c
diff --git a/samples/acache_client/Makefile b/samples/acache_client/Makefile new file mode 100644 index 000000000000..13e5485b3d2f --- /dev/null +++ b/samples/acache_client/Makefile @@ -0,0 +1,13 @@ +.PHONY: client clean + +CC = $(CROSS_COMPILE)gcc +CFLAGS = -Wall -g + + +OBJ = main.o connect.o +client: ${OBJ} + $(CC) $(CFLAGS) $^ -o acache_client +.c.o: + $(CC) $(CFLAGS) -c $< -o $@ +clean: + rm -f *.o acache_client diff --git a/samples/acache_client/connect.c b/samples/acache_client/connect.c new file mode 100644 index 000000000000..2dd442415ee2 --- /dev/null +++ b/samples/acache_client/connect.c @@ -0,0 +1,144 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <unistd.h> +#include <errno.h> + +#include "connect.h" + +static int ACACHE_READWRITE_CAPACITY = 4096; +static struct connection readwrite_conn; +static struct readwrite_conn_metadata { + int initialized; + int fd; +} private; + +void *initialize(struct connection *self) +{ + long ret; + + private.fd = open(acache_path, O_RDWR | O_SYNC); + if (private.fd == -1) { + fprintf(stderr, "error opening device: %s\n", strerror(errno)); + exit(-1); + } + + struct acache_metadata { + uint32_t magic; + uint32_t conntype; + uint32_t devsize; + } acache_metadata; +#define ACACHE_GET_METADATA _IOR('a', 1, struct acache_metadata) + ret = ioctl(private.fd, ACACHE_GET_METADATA, &acache_metadata); + if (ret) { + fprintf(stderr, "error getting device memory length: %s\n", strerror(errno)); + exit(-1); + } + if (acache_metadata.magic != ACACHE_MAGIC) { + fprintf(stderr, "version not match; client: %u kernel: %u\n", + ACACHE_MAGIC, acache_metadata.magic); + exit(-1); + } + if (acache_metadata.conntype != ACACHE_READWRITE_CONN) { + fprintf(stderr, "connect type not match; client: %u kernel: %u\n", + ACACHE_READWRITE_CONN, acache_metadata.conntype); + exit(-1); + } + printf("got dev size %u\n", acache_metadata.devsize); + private.initialized = 1; + + return (void *)&private; +} + +struct readwrite_conn_metadata* get_metadata(struct connection *self) +{ + struct readwrite_conn_metadata *metadata; + + if (self == NULL) { + fprintf(stderr, "connenction uninitailized\n"); + return NULL; + } + + metadata = (struct readwrite_conn_metadata *)self->private; + + if (metadata->initialized == 0) { + fprintf(stderr, "connenction uninitailized\n"); + return NULL; + } + return metadata; +} + +int send_items(struct connection *self, struct acache_info *infos, + size_t count) +{ + long ret; + struct readwrite_conn_metadata *metadata = get_metadata(self); + + if (!metadata) { + return 0; + } + ret = write(metadata->fd, (void*)infos, count * sizeof(struct acache_info)); + if (ret < 0) { + fprintf(stderr, "error writing data: %ld\n", ret); + return 0; + } + if (ret % sizeof(struct acache_info)) { + fprintf(stderr, "error writing data: data length is not multiple of sizeof(struct acache_info): %ld %ld\n", + ret, sizeof(struct acache_info)); + return 0; + } + return ret / sizeof(struct acache_info); +} + +int fetch_items(struct connection *self, struct acache_info *infos, + size_t count) +{ + long ret; + struct readwrite_conn_metadata *metadata = get_metadata(self); + + if (!metadata) { + return 0; + } + ret = read(metadata->fd, (void*)infos, count * sizeof(struct acache_info)); + if (ret < 0) { + fprintf(stderr, "error reading data: %ld\n", ret); + return 0; + } + if (ret % sizeof(struct acache_info)) { + fprintf(stderr, "error reading data: data length is not multiple of sizeof(struct acache_info): %ld %ld\n", + ret, sizeof(struct acache_info)); + return 0; + } + return ret / sizeof(struct acache_info); +} + +int get_capacity() { + return ACACHE_READWRITE_CAPACITY; +} + +int close_conn(struct connection *self) +{ + struct readwrite_conn_metadata *metadata = get_metadata(self); + + if (!metadata) { + return 0; + } + close(metadata->fd); + return 0; + +} + +struct connection *initialize_conn_rw(void) +{ + readwrite_conn.ops.close = close_conn; + readwrite_conn.ops.initialize = initialize; + readwrite_conn.ops.send_items = send_items; + readwrite_conn.ops.fetch_items = fetch_items; + readwrite_conn.ops.get_capacity = get_capacity; + readwrite_conn.private = initialize(&readwrite_conn); + return &readwrite_conn; +} diff --git a/samples/acache_client/connect.h b/samples/acache_client/connect.h new file mode 100644 index 000000000000..b0357c78c8c4 --- /dev/null +++ b/samples/acache_client/connect.h @@ -0,0 +1,74 @@ +#ifndef ACACHE_CONNENECT_H +#define ACACHE_CONNENECT_H +#include <stdint.h> + +#define ACACHE_MAGIC 2 +enum acache_conn_types { + ACACHE_NO_CONN = 0, + ACACHE_RINGBUFFER_CONN, + ACACHE_READWRITE_CONN, +}; +#define acache_path "/dev/acache" + +struct acache_info { + uint64_t length; + uint64_t offset; + uint64_t start_time; + uint32_t dev; + int opcode; +}; + +struct connection; +struct connection_operations { + + /* + * initialize connnection + * parameters: none + * return values: + * - void *: private data for connection + */ + void *(*initialize)(struct connection *self); + /* + * send_items send items to peer side + * parameters: + * - infos: data to send + * - count: data length + * return values: + * - number of sent items + */ + int (*send_items)(struct connection *self, struct acache_info *infos, + size_t count); + /* + * send_items recieve items from peer side + * paremeters: + * - infos: buffer to place recieved items + * - count: length of buffer + * return values: + * - number of recieved items + */ + int (*fetch_items)(struct connection *self, struct acache_info *infos, + size_t count); + /* + * close closes the connection + */ + int (*close)(struct connection *self); + + /* + * get_capacity return the capacity of items that can send and revice at once + */ + int (*get_capacity)(struct connection *self); + +}; + +struct connection { + /* + * private data for specific connnetion + */ + void *private; + struct connection_operations ops; +}; + +struct connection *initialize_conn_rw(void); + +#endif + diff --git a/samples/acache_client/main.c b/samples/acache_client/main.c new file mode 100644 index 000000000000..929c70798cfb --- /dev/null +++ b/samples/acache_client/main.c @@ -0,0 +1,133 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <signal.h> +#include <unistd.h> +#include <errno.h> + +#include "connect.h" + +/* + * dev_t in userspace is 8-bytes long but 4-byte long in kernel + * work around this + */ +#define MINORBITS 20 +#define MINORMASK ((1U << MINORBITS) - 1) +#define MKDEV(ma, mi) ((ma)<<MINORBITS | (mi)) +#define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS)) +#define MINOR(dev) ((unsigned int) ((dev) & MINORMASK)) + +struct acache_info *inbuf, *outbuf; +struct connection *conn; + +void print_infos(const char *prefix, struct acache_info *infos, size_t length) +{ + size_t i; + struct acache_info *info; + + for (i = 0; i < length; i++) { + info = infos + i; + + printf("%4s,%20lu,%8u,%8u,%15lu,%12lu\n", + prefix, info->start_time, MAJOR(info->dev), + MINOR(info->dev), info->offset, info->length); + } +} + +int malloc_buffers(struct acache_info **inbuf, struct acache_info **outbuf, + size_t capacity) +{ + /* prepare buffers to store incoming or outgoing items */ + *inbuf = (struct acache_info *)malloc(sizeof(struct acache_info) * capacity); + *outbuf = (struct acache_info *)malloc(sizeof(struct acache_info) * capacity); + + if (!*inbuf || !*outbuf) { + fprintf(stderr, "error malloc memory: %s\n, size: %lu, %lu\n", + strerror(errno), + sizeof(struct acache_info) * capacity, + sizeof(struct acache_info) * capacity); + return -errno; + } + return 0; +} + +void free_buffer(struct acache_info **buf) +{ + if (buf && *buf) { + free(*buf); + *buf = NULL; + } +} + +void elegant_exit(int sig) { + printf("exiting..."); + free_buffer(&inbuf); + free_buffer(&outbuf); + conn->ops.close(conn); + exit(0); +} + +int main(int argc, char **argv) +{ + int debug = 0; + int ret; + int outbuf_tail; + size_t capacity; + + conn = initialize_conn_rw(); + + if (conn == NULL) { + fprintf(stderr, "error initialzied connnection\n"); + return -1; + } + + if (argc > 1 && strcmp("-d", argv[1]) == 0) + debug = 1; + + /* prepare buffers to store incoming or outgoing items */ + capacity = conn->ops.get_capacity(conn); + ret = malloc_buffers(&inbuf, &outbuf, capacity); + + if (ret < 0) + return ret; + + if (debug) { + printf("%4s,%20s,%8s,%8s,%15s,%12s\n", + "op","time(ns)","majorDev","minorDev","offset(B)","length(B)"); + } + /* main loop */ + if (signal(SIGINT, elegant_exit) == SIG_ERR) { + fprintf(stderr, "error handling SIGINT: %s\n", strerror(errno)); + } + if (signal(SIGTERM, elegant_exit) == SIG_ERR) { + fprintf(stderr, "error handling SIGTERM: %s\n", strerror(errno)); + } + while (1) { + unsigned int i, inlen; + + inlen = conn->ops.fetch_items(conn, inbuf, capacity); + if (!inlen) { + usleep(100); + continue; + } + + outbuf_tail = 0; + for (i = 0; i < inlen; i++) { + /* customize prefetch strategy here */ + memcpy(outbuf + outbuf_tail, inbuf + i, sizeof(struct acache_info)); + outbuf[outbuf_tail].offset += outbuf[outbuf_tail].length >> 9; + outbuf_tail++; + } + if (debug) { + print_infos("R", inbuf, inlen); + print_infos("P", outbuf, outbuf_tail); + } + if (outbuf_tail) { + conn->ops.send_items(conn, outbuf, outbuf_tail); + } + } + return 0; +}