mirror of
https://github.com/linux-msm/rmtfs.git
synced 2024-11-12 01:19:17 +00:00
299 lines
5.6 KiB
C
299 lines
5.6 KiB
C
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include "rmtfs.h"
|
|
|
|
#define MAX_CALLERS 10
|
|
#define STORAGE_MAX_SIZE (16 * 1024 * 1024)
|
|
|
|
#define BY_PARTLABEL_PATH "/dev/disk/by-partlabel"
|
|
|
|
#define MIN(x, y) ((x) < (y) ? (x) : (y))
|
|
|
|
struct partition {
|
|
const char *path;
|
|
const char *actual;
|
|
const char *partlabel;
|
|
};
|
|
|
|
struct rmtfd {
|
|
unsigned id;
|
|
unsigned node;
|
|
int fd;
|
|
unsigned dev_error;
|
|
const struct partition *partition;
|
|
|
|
void *shadow_buf;
|
|
size_t shadow_len;
|
|
};
|
|
|
|
static const char *storage_dir = "/boot";
|
|
static int storage_read_only;
|
|
static int storage_use_partitions;
|
|
|
|
static const struct partition partition_table[] = {
|
|
{ "/boot/modem_fs1", "modem_fs1", "modemst1" },
|
|
{ "/boot/modem_fs2", "modem_fs2", "modemst2" },
|
|
{ "/boot/modem_fsc", "modem_fsc", "fsc" },
|
|
{ "/boot/modem_fsg", "modem_fsg", "fsg" },
|
|
{ "/boot/modem_tunning", "modem_tunning", "tunning" },
|
|
{ "/boot/modem_tng", "modem_tng", "tunning" },
|
|
{}
|
|
};
|
|
|
|
static struct rmtfd rmtfds[MAX_CALLERS];
|
|
|
|
static int storage_populate_shadow_buf(struct rmtfd *rmtfd, const char *file);
|
|
|
|
int storage_init(const char *storage_root, bool read_only, bool use_partitions)
|
|
{
|
|
int i;
|
|
|
|
if (storage_root)
|
|
storage_dir = storage_root;
|
|
|
|
if (use_partitions) {
|
|
if (!storage_root)
|
|
storage_dir = BY_PARTLABEL_PATH;
|
|
storage_use_partitions = true;
|
|
}
|
|
|
|
storage_read_only = read_only;
|
|
|
|
for (i = 0; i < MAX_CALLERS; i++) {
|
|
rmtfds[i].id = i;
|
|
rmtfds[i].fd = -1;
|
|
rmtfds[i].shadow_buf = NULL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
struct rmtfd *storage_open(unsigned node, const char *path)
|
|
{
|
|
char *fspath;
|
|
const struct partition *part;
|
|
struct rmtfd *rmtfd = NULL;
|
|
const char *file;
|
|
size_t pathlen;
|
|
int saved_errno;
|
|
int ret;
|
|
int fd;
|
|
int i;
|
|
|
|
for (part = partition_table; part->path; part++) {
|
|
if (strcmp(part->path, path) == 0)
|
|
goto found;
|
|
}
|
|
|
|
fprintf(stderr, "[RMTFS storage] request for unknown partition '%s', rejecting\n", path);
|
|
return NULL;
|
|
|
|
found:
|
|
/* Check if this node already has the requested path open */
|
|
for (i = 0; i < MAX_CALLERS; i++) {
|
|
if ((rmtfds[i].fd != -1 || rmtfds[i].shadow_buf) &&
|
|
rmtfds[i].node == node &&
|
|
rmtfds[i].partition == part)
|
|
return &rmtfds[i];
|
|
}
|
|
|
|
for (i = 0; i < MAX_CALLERS; i++) {
|
|
if (rmtfds[i].fd == -1 && !rmtfds[i].shadow_buf) {
|
|
rmtfd = &rmtfds[i];
|
|
break;
|
|
}
|
|
}
|
|
if (!rmtfd) {
|
|
fprintf(stderr, "[storage] out of free rmtfd handles\n");
|
|
return NULL;
|
|
}
|
|
|
|
if (storage_use_partitions)
|
|
file = part->partlabel;
|
|
else
|
|
file = part->actual;
|
|
|
|
pathlen = strlen(storage_dir) + strlen(file) + 2;
|
|
fspath = alloca(pathlen);
|
|
snprintf(fspath, pathlen, "%s/%s", storage_dir, file);
|
|
if (!storage_read_only) {
|
|
fd = open(fspath, O_RDWR);
|
|
if (fd < 0) {
|
|
saved_errno = errno;
|
|
fprintf(stderr, "[storage] failed to open '%s' (requested '%s'): %s\n",
|
|
fspath, part->path, strerror(saved_errno));
|
|
errno = saved_errno;
|
|
return NULL;
|
|
}
|
|
rmtfd->fd = fd;
|
|
rmtfd->shadow_len = 0;
|
|
} else {
|
|
ret = storage_populate_shadow_buf(rmtfd, fspath);
|
|
if (ret < 0) {
|
|
saved_errno = errno;
|
|
fprintf(stderr, "[storage] failed to open '%s' (requested '%s'): %s\n",
|
|
fspath, part->path, strerror(saved_errno));
|
|
errno = saved_errno;
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
rmtfd->node = node;
|
|
rmtfd->partition = part;
|
|
|
|
return rmtfd;
|
|
}
|
|
|
|
void storage_close(struct rmtfd *rmtfd)
|
|
{
|
|
if (rmtfd->fd >= 0) {
|
|
close(rmtfd->fd);
|
|
rmtfd->fd = -1;
|
|
}
|
|
|
|
free(rmtfd->shadow_buf);
|
|
rmtfd->shadow_buf = NULL;
|
|
rmtfd->shadow_len = 0;
|
|
|
|
rmtfd->partition = NULL;
|
|
}
|
|
|
|
struct rmtfd *storage_get(unsigned node, int caller_id)
|
|
{
|
|
struct rmtfd *rmtfd;
|
|
|
|
if (caller_id >= MAX_CALLERS)
|
|
return NULL;
|
|
|
|
rmtfd = &rmtfds[caller_id];
|
|
if (rmtfd->node != node)
|
|
return NULL;
|
|
|
|
return rmtfd;
|
|
}
|
|
|
|
int storage_get_caller_id(const struct rmtfd *rmtfd)
|
|
{
|
|
return rmtfd->id;
|
|
}
|
|
|
|
int storage_get_error(const struct rmtfd *rmtfd)
|
|
{
|
|
return rmtfd->dev_error;
|
|
}
|
|
|
|
void storage_exit(void)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < MAX_CALLERS; i++)
|
|
storage_close(&rmtfds[i]);
|
|
}
|
|
|
|
ssize_t storage_pread(const struct rmtfd *rmtfd, void *buf, size_t nbyte, off_t offset)
|
|
{
|
|
ssize_t n;
|
|
|
|
if (!storage_read_only) {
|
|
n = pread(rmtfd->fd, buf, nbyte, offset);
|
|
} else {
|
|
n = MIN((ssize_t)nbyte, (ssize_t)rmtfd->shadow_len - offset);
|
|
if (n > 0)
|
|
memcpy(buf, (char*)rmtfd->shadow_buf + offset, n);
|
|
else
|
|
n = 0;
|
|
}
|
|
|
|
if (n < nbyte)
|
|
memset((char*)buf + n, 0, nbyte - n);
|
|
|
|
return nbyte;
|
|
}
|
|
|
|
ssize_t storage_pwrite(struct rmtfd *rmtfd, const void *buf, size_t nbyte, off_t offset)
|
|
{
|
|
size_t new_len = offset + nbyte;
|
|
void *new_buf;
|
|
|
|
if (!storage_read_only)
|
|
return pwrite(rmtfd->fd, buf, nbyte, offset);
|
|
|
|
if (new_len >= STORAGE_MAX_SIZE) {
|
|
fprintf(stderr, "write to %zd bytes exceededs max size\n", new_len);
|
|
errno = -EINVAL;
|
|
return -1;
|
|
}
|
|
|
|
if (new_len > rmtfd->shadow_len) {
|
|
new_buf = realloc(rmtfd->shadow_buf, new_len);
|
|
if (!new_buf) {
|
|
errno = -ENOMEM;
|
|
return -1;
|
|
}
|
|
|
|
rmtfd->shadow_buf = new_buf;
|
|
rmtfd->shadow_len = new_len;
|
|
}
|
|
|
|
memcpy((char*)rmtfd->shadow_buf + offset, buf, nbyte);
|
|
|
|
return nbyte;
|
|
}
|
|
|
|
int storage_sync(struct rmtfd *rmtfd)
|
|
{
|
|
if (storage_read_only)
|
|
return 0;
|
|
|
|
return fdatasync(rmtfd->fd);
|
|
}
|
|
|
|
static int storage_populate_shadow_buf(struct rmtfd *rmtfd, const char *file)
|
|
{
|
|
ssize_t len;
|
|
ssize_t n;
|
|
void *buf;
|
|
int ret;
|
|
int fd;
|
|
|
|
fd = open(file, O_RDONLY);
|
|
if (fd < 0)
|
|
return -1;
|
|
|
|
len = lseek(fd, 0, SEEK_END);
|
|
if (len < 0) {
|
|
ret = -1;
|
|
goto err_close_fd;
|
|
}
|
|
|
|
lseek(fd, 0, SEEK_SET);
|
|
|
|
buf = calloc(1, len);
|
|
if (!buf) {
|
|
ret = -1;
|
|
goto err_close_fd;
|
|
}
|
|
|
|
n = read(fd, buf, len);
|
|
if (n < 0) {
|
|
ret = -1;
|
|
goto err_close_fd;
|
|
}
|
|
|
|
rmtfd->shadow_buf = buf;
|
|
rmtfd->shadow_len = n;
|
|
|
|
ret = 0;
|
|
|
|
err_close_fd:
|
|
close(fd);
|
|
|
|
return ret;
|
|
}
|