ublock.c revision 2045e6e39d6dbfed1e46c333c2910c66e788cd36
12045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle/* 22045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle * Copyright (C) 2010 The Android Open Source Project 32045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle * 42045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle * Licensed under the Apache License, Version 2.0 (the "License"); 52045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle * you may not use this file except in compliance with the License. 62045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle * You may obtain a copy of the License at 72045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle * 82045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle * http://www.apache.org/licenses/LICENSE-2.0 92045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle * 102045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle * Unless required by applicable law or agreed to in writing, software 112045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle * distributed under the License is distributed on an "AS IS" BASIS, 122045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 132045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle * See the License for the specific language governing permissions and 142045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle * limitations under the License. 152045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle */ 162045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 172045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle#include <assert.h> 182045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle#include <errno.h> 192045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle#include <fcntl.h> 202045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle#include <linux/ublock.h> 212045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle#include <stdint.h> 222045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle#include <stdio.h> 232045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle#include <stdlib.h> 242045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle#include <sys/types.h> 252045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle#include <ublock/ublock.h> 262045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 272045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle#define CONTROL_FILE "/dev/ublockctl" 282045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 292045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttlestruct ublock_ctx { 302045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle struct ublock_ops *ops; 312045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 322045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle uint32_t index; 332045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle uint64_t size; 342045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle uint32_t max_buf; 352045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 362045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle char *in_buf; 372045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle char *out_buf; 382045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 392045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle int flags; 402045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle int fd; 412045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle int fails; 422045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle}; 432045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 442045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle#define CTX_INITED 0x1 452045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle#define CTX_READY 0x2 462045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle#define CTX_RUNNING 0x4 472045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 482045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle#define MAX_BUF 65536 492045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 502045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle#define MAX_FAILURES 10 512045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 522045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttlestatic inline void ublock_succeed(struct ublock_ctx *ub_ctx) 532045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle{ 542045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle assert(ub_ctx); 552045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 562045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle ub_ctx->fails = 0; 572045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle} 582045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 592045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttlestatic void ublock_fail(struct ublock_ctx *ub_ctx) 602045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle{ 612045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle assert(ub_ctx); 622045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 632045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle ub_ctx->fails++; 642045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle if (ub_ctx->fails > MAX_FAILURES) 652045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle ublock_stop(ub_ctx); 662045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle} 672045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 682045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttlestatic int ublock_handle_init(struct ublock_ctx *ub_ctx, 692045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle const void *in, size_t in_len, 702045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle void *out, size_t *out_len) 712045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle{ 722045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle const struct ublock_init_in *in_h; 732045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle struct ublock_init_out *out_h; 742045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 752045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle assert(ub_ctx); 762045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle assert(in); 772045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle assert(out); 782045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 792045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle if (in_len != sizeof(*in_h)) 802045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle return -EPROTO; 812045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 822045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle in_h = (const struct ublock_init_in *)in; 832045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 842045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle if (in_h->version != UBLOCK_VERSION) 852045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle return -EPROTO; 862045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 872045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle out_h = (struct ublock_init_out *)out; 882045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle out_h->version = UBLOCK_VERSION; 892045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle out_h->size = ub_ctx->size; 902045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle if (in_h->max_buf < MAX_BUF) 912045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle ub_ctx->max_buf = in_h->max_buf; 922045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle else 932045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle ub_ctx->max_buf = MAX_BUF; 942045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle out_h->max_buf = ub_ctx->max_buf; 952045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 962045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle *out_len = sizeof(*out_h); 972045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 982045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle ub_ctx->index = in_h->index; 992045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle ub_ctx->flags |= CTX_INITED; 1002045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 1012045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle return 0; 1022045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle} 1032045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 1042045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttlestatic int ublock_handle_ready(struct ublock_ctx *ub_ctx, 1052045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle const void *in, size_t in_len, 1062045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle void *out, size_t *out_len) 1072045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle{ 1082045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle struct ublock_ready_out *out_h; 1092045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 1102045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle assert(ub_ctx); 1112045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle assert(in); 1122045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle assert(out); 1132045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 1142045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle if (in_len != sizeof(struct ublock_ready_in)) 1152045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle return -EPROTO; 1162045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 1172045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle *out_len = sizeof(struct ublock_ready_out); 1182045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 1192045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle ub_ctx->flags |= CTX_READY; 1202045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 1212045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle return 0; 1222045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle} 1232045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 1242045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttlestatic int ublock_handle_read(struct ublock_ctx *ub_ctx, 1252045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle const void *in, size_t in_len, 1262045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle void *out, size_t *out_len) 1272045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle{ 1282045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle const struct ublock_read_in *in_h; 1292045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle struct ublock_read_out *out_h; 1302045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle char *out_buf; 1312045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 1322045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle assert(ub_ctx); 1332045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle assert(in); 1342045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle assert(out); 1352045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 1362045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle if (in_len != sizeof(*in_h)) 1372045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle return -EPROTO; 1382045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 1392045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle in_h = (const struct ublock_read_in *)in; 1402045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 1412045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle out_h = (struct ublock_read_out *)out; 1422045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle out_buf = (char *)(out_h + 1); 1432045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 1442045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle out_h->status = (ub_ctx->ops->read)(out_buf, in_h->length, in_h->offset); 1452045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 1462045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle if (out_h->status >= 0) 1472045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle *out_len = sizeof(*out_h) + in_h->length; 1482045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle else 1492045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle *out_len = sizeof(*out_h); 1502045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 1512045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle return 0; 1522045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle} 1532045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 1542045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttlestatic int ublock_handle_write(struct ublock_ctx *ub_ctx, 1552045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle const void *in, size_t in_len, 1562045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle void *out, size_t *out_len) 1572045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle{ 1582045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle const struct ublock_write_in *in_h; 1592045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle const char *in_buf; 1602045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle struct ublock_write_out *out_h; 1612045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 1622045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle assert(ub_ctx); 1632045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle assert(in); 1642045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle assert(out); 1652045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 1662045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle if (in_len < sizeof(*in_h)) 1672045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle return -EPROTO; 1682045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 1692045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle in_h = (const struct ublock_write_in *)in; 1702045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle in_buf = (const char*)(in_h + 1); 1712045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 1722045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle out_h = (struct ublock_write_out *)out; 1732045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle *out_len = sizeof(*out_h); 1742045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 1752045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle out_h->status = (ub_ctx->ops->write)(in_buf, in_h->length, in_h->offset); 1762045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 1772045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle return 0; 1782045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle} 1792045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 1802045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttlestatic int ublock_handle_request(struct ublock_ctx *ub_ctx, 1812045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle const void *in, size_t in_len, 1822045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle void *out, size_t *out_len) 1832045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle{ 1842045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle const struct ublock_in_header *in_h; 1852045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle const void *in_buf; 1862045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle size_t in_buf_len; 1872045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 1882045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle struct ublock_out_header *out_h; 1892045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle void *out_buf; 1902045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle size_t out_buf_len; 1912045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 1922045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle int result; 1932045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle int (*handle_fn)(struct ublock_ctx *, const void *, size_t, void *, size_t *); 1942045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 1952045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle assert(ub_ctx); 1962045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle assert(in); 1972045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle assert(out); 1982045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 1992045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle if (in_len < sizeof(*in_h)) 2002045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle return -EPROTO; 2012045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 2022045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle in_h = (const struct ublock_in_header *)in; 2032045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle in_buf = in_h + 1; 2042045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle in_buf_len = in_len - sizeof(*in_h); 2052045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 2062045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle out_h = (struct ublock_out_header *)out; 2072045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle out_buf = out_h + 1; 2082045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 2092045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle switch (in_h->opcode) { 2102045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle case UBLOCK_INIT_IN: 2112045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle out_h->opcode = UBLOCK_INIT_OUT; 2122045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle handle_fn = &ublock_handle_init; 2132045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle break; 2142045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle case UBLOCK_READY_IN: 2152045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle out_h->opcode = UBLOCK_READY_OUT; 2162045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle handle_fn = &ublock_handle_ready; 2172045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle break; 2182045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle case UBLOCK_READ_IN: 2192045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle out_h->opcode = UBLOCK_READ_OUT; 2202045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle handle_fn = &ublock_handle_read; 2212045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle break; 2222045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle case UBLOCK_WRITE_IN: 2232045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle out_h->opcode = UBLOCK_WRITE_OUT; 2242045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle handle_fn = &ublock_handle_write; 2252045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle break; 2262045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle default: 2272045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle return -EPROTO; 2282045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle } 2292045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 2302045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle out_h->seq = in_h->seq; 2312045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle result = (handle_fn)(ub_ctx, in_buf, in_buf_len, out_buf, &out_buf_len); 2322045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle *out_len = sizeof(*out_h) + out_buf_len; 2332045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 2342045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle return result; 2352045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle} 2362045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 2372045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttlestatic int ublock_do_request(struct ublock_ctx *ub_ctx, 2382045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle void *in_buf, size_t in_size, 2392045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle void *out_buf, size_t out_size) 2402045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle{ 2412045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle size_t out_len; 2422045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle ssize_t in_len, out_wrote; 2432045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle int result; 2442045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 2452045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle assert(ub_ctx); 2462045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle assert(in_buf); 2472045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle assert(out_buf); 2482045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 2492045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle in_len = read(ub_ctx->fd, in_buf, in_size); 2502045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle if (in_len < 0) 2512045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle return -EPROTO; 2522045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 2532045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle result = ublock_handle_request(ub_ctx, in_buf, in_len, out_buf, &out_len); 2542045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 2552045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle assert(out_len <= out_size); 2562045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 2572045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle out_wrote = write(ub_ctx->fd, out_buf, out_len); 2582045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 2592045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle if (out_wrote < out_len) 2602045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle return -EPROTO; 2612045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 2622045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle if (result) 2632045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle ublock_fail(ub_ctx); 2642045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle else 2652045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle ublock_succeed(ub_ctx); 2662045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 2672045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle return result; 2682045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle} 2692045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 2702045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle#define EXIT_READY 1 2712045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle#define EXIT_STOPPED 2 2722045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle#define EXIT_FAIL 4 2732045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 2742045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttlestatic int ublock_loop(struct ublock_ctx *ub_ctx, int exit_cond) 2752045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle{ 2762045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle size_t in_len, out_len; 2772045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle int result; 2782045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 2792045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle result = 0; 2802045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle while (((exit_cond & EXIT_READY) && (!(ub_ctx->flags & CTX_READY))) || 2812045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle ((exit_cond & EXIT_STOPPED) && (ub_ctx->flags & CTX_RUNNING)) || 2822045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle ((exit_cond & EXIT_FAIL) && (result))) { 2832045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle result = ublock_do_request(ub_ctx, 2842045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle ub_ctx->in_buf, ub_ctx->max_buf, 2852045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle ub_ctx->out_buf, ub_ctx->max_buf); 2862045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle if (result) 2872045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle return result; 2882045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle } 2892045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 2902045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle return 0; 2912045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle} 2922045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 2932045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttleint ublock_run(struct ublock_ctx *ub_ctx) 2942045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle{ 2952045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle if (!ub_ctx) 2962045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle return -EFAULT; 2972045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 2982045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle if (!(ub_ctx->flags & CTX_INITED)) 2992045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle return -EINVAL; 3002045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 3012045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle ub_ctx->flags |= CTX_RUNNING; 3022045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle ublock_loop(ub_ctx, EXIT_STOPPED); 3032045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 3042045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle return 0; 3052045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle} 3062045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 3072045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttlevoid ublock_stop(struct ublock_ctx *ub_ctx) 3082045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle{ 3092045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle if (!ub_ctx) 3102045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle return; 3112045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 3122045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle if (!(ub_ctx->flags & CTX_INITED)) 3132045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle return; 3142045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 3152045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle ub_ctx->flags &= ~CTX_RUNNING; 3162045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle} 3172045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 3182045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttleint ublock_index(struct ublock_ctx *ub_ctx) 3192045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle{ 3202045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle if (!ub_ctx) 3212045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle return -EFAULT; 3222045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 3232045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle if (!(ub_ctx->flags & CTX_INITED)) 3242045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle return -EINVAL; 3252045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 3262045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle return ub_ctx->index; 3272045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle} 3282045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 3292045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttlestatic inline size_t ublock_init_buf_size(void) 3302045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle{ 3312045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle size_t in_size = sizeof(struct ublock_in_header) + 3322045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle sizeof(struct ublock_init_in); 3332045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle size_t out_size = sizeof(struct ublock_out_header) + 3342045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle sizeof(struct ublock_init_out); 3352045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 3362045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle return (in_size > out_size) ? in_size : out_size; 3372045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle} 3382045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 3392045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttleint ublock_init(struct ublock_ctx **ub_ctx_out, struct ublock_ops *ops, 3402045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle uint64_t dev_size) 3412045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle{ 3422045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle struct ublock_ctx *ub_ctx; 3432045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle char *in_buf, *out_buf; 3442045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle size_t size; 3452045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle int result; 3462045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 3472045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle if (!ub_ctx_out || !ops) 3482045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle return -EFAULT; 3492045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 3502045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle in_buf = out_buf = NULL; 3512045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 3522045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle ub_ctx = malloc(sizeof(struct ublock_ctx)); 3532045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle if (!ub_ctx) { 3542045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle result = -ENOMEM; 3552045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle goto error; 3562045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle } 3572045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 3582045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle size = ublock_init_buf_size(); 3592045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle in_buf = malloc(size); 3602045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle out_buf = malloc(size); 3612045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle if (!(in_buf && out_buf)) { 3622045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle result = -ENOMEM; 3632045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle goto error; 3642045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle } 3652045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 3662045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle ub_ctx->ops = ops; 3672045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle ub_ctx->size = dev_size; 3682045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle ub_ctx->max_buf = 0; 3692045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle ub_ctx->flags = 0; 3702045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 3712045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle ub_ctx->fd = open(CONTROL_FILE, O_RDWR); 3722045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle if (ub_ctx->fd < 0) { 3732045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle result = -ENOENT; 3742045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle goto error; 3752045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle } 3762045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 3772045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle result = ublock_do_request(ub_ctx, in_buf, size, out_buf, size); 3782045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle if (result) { 3792045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle result = -EPROTO; 3802045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle goto error; 3812045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle } 3822045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle if (!ub_ctx->flags & CTX_INITED) { 3832045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle result = -EPROTO; 3842045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle goto error; 3852045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle } 3862045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 3872045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle free(in_buf); 3882045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle in_buf = NULL; 3892045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle free(out_buf); 3902045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle out_buf = NULL; 3912045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 3922045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle ub_ctx->in_buf = malloc(ub_ctx->max_buf); 3932045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle ub_ctx->out_buf = malloc(ub_ctx->max_buf); 3942045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle if (!(ub_ctx->in_buf && ub_ctx->out_buf)) { 3952045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle result = -ENOMEM; 3962045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle goto error; 3972045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle } 3982045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 3992045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle ublock_loop(ub_ctx, EXIT_READY); 4002045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 4012045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle *ub_ctx_out = ub_ctx; 4022045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 4032045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle return 0; 4042045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 4052045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttleerror: 4062045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle if (ub_ctx) { 4072045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle if (ub_ctx->in_buf) 4082045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle free(ub_ctx->in_buf); 4092045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle if (ub_ctx->out_buf) 4102045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle free(ub_ctx->out_buf); 4112045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle if (ub_ctx->fd) 4122045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle close(ub_ctx->fd); 4132045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle free(ub_ctx); 4142045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle } 4152045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle if (in_buf) 4162045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle free(in_buf); 4172045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle if (out_buf) 4182045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle free(out_buf); 4192045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 4202045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle return result; 4212045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle} 4222045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 4232045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttlevoid ublock_destroy(struct ublock_ctx *ub_ctx) 4242045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle{ 4252045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle if (!ub_ctx) 4262045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle return; 4272045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle 4282045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle close(ub_ctx->fd); 4292045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle free(ub_ctx); 4302045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle} 431