1/*
2 * Copyright (c) 2014, University of Washington.
3 * All rights reserved.
4 *
5 * This file is distributed under the terms in the attached LICENSE file.
6 * If you do not find this file, copies can be found by writing to:
7 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
8 */
9
10#include <stdlib.h>
11#include <stdio.h>
12#include <assert.h>
13#include <unistd.h>
14#include <errno.h>
15#include <sys/types.h>
16#include <sys/stat.h>
17#include <fcntl.h>
18#include <aio.h>
19#include <string.h>
20#include <errors/errno.h>
21#include <storage/vsic.h>
22#include <storage/vsa.h>
23
24#define MAX_CBS         10
25
26struct file_vsic {
27    struct aiocb cb[MAX_CBS];
28    const struct aiocb *cb_list[MAX_CBS];
29};
30
31static struct aiocb *get_aiocb(struct file_vsic *vsic)
32{
33    for(int i = 0; i < MAX_CBS; i++) {
34        if(vsic->cb_list[i] == NULL) {
35            vsic->cb_list[i] = &vsic->cb[i];
36            return &vsic->cb[i];
37        }
38    }
39
40    return NULL;
41}
42
43static errval_t vsic_write(struct storage_vsic *vsic, struct storage_vsa *vsa,
44                           off_t offset, size_t size, void *buffer)
45{
46    assert(vsic != NULL);
47    assert(vsa != NULL);
48    assert(buffer != NULL);
49    struct file_vsic *mydata = vsic->data;
50    struct aiocb *cb = get_aiocb(mydata);
51    assert(cb != NULL);
52
53    cb->aio_fildes = vsa->fd;
54    cb->aio_offset = offset;
55    cb->aio_buf = buffer;
56    cb->aio_nbytes = size;
57
58    int r = aio_write(cb);
59    assert(r == 0);
60
61    return SYS_ERR_OK;
62}
63
64static errval_t vsic_read(struct storage_vsic *vsic, struct storage_vsa *vsa,
65                          off_t offset, size_t size, void *buffer)
66{
67    assert(vsic != NULL);
68    assert(vsa != NULL);
69    assert(buffer != NULL);
70    struct file_vsic *mydata = vsic->data;
71    struct aiocb *cb = get_aiocb(mydata);
72    assert(cb != NULL);
73
74    cb->aio_fildes = vsa->fd;
75    cb->aio_offset = offset;
76    cb->aio_buf = buffer;
77    cb->aio_nbytes = size;
78
79    int r = aio_read(cb);
80    assert(r == 0);
81
82    return SYS_ERR_OK;
83}
84
85static errval_t vsic_flush(struct storage_vsic *vsic, struct storage_vsa *vsa)
86{
87    assert(vsic != NULL);
88    assert(vsa != NULL);
89    struct file_vsic *mydata = vsic->data;
90    struct aiocb *cb = get_aiocb(mydata);
91    assert(cb != NULL);
92
93    cb->aio_fildes = vsa->fd;
94    int r = aio_fsync(O_SYNC, cb);
95    assert(r == 0);
96
97    return SYS_ERR_OK;
98}
99
100static errval_t vsic_wait(struct storage_vsic *vsic)
101{
102    assert(vsic != NULL);
103    struct file_vsic *mydata = vsic->data;
104
105    for(;;) {
106        int entries = 0;
107
108        for(int i = 0; i < MAX_CBS; i++) {
109            if(mydata->cb_list[i] != NULL) {
110                int err = aio_error(mydata->cb_list[i]);
111
112                if(err == 0) {
113                    int status = aio_return((struct aiocb *)mydata->cb_list[i]);
114                    /* printf("Status: %zd\n", status); */
115
116                    // Completed successfully
117                    mydata->cb_list[i] = NULL;
118
119                    if(status == 0) {
120                        return VFS_ERR_EOF;
121                    }
122                } else if(err == EINPROGRESS) {
123                    entries++;
124                } else {
125		  // Error! Report it.
126		  printf("Error: %s\n", strerror(err));
127		  return VFS_ERR_IN_READ;
128                }
129            }
130        }
131
132        if(entries == 0) {
133            break;
134        }
135
136        int r = aio_suspend(mydata->cb_list, MAX_CBS, NULL);
137        assert(r == 0);
138    }
139
140    return SYS_ERR_OK;
141}
142
143static struct storage_vsic_ops file_ops = {
144    .write = vsic_write,
145    .read = vsic_read,
146    .flush = vsic_flush,
147    .wait = vsic_wait,
148};
149
150static errval_t file_vsic_alloc(struct storage_vsic *vsic)
151{
152    assert(vsic != NULL);
153    struct file_vsic *mydata = malloc(sizeof(struct file_vsic));
154    assert(mydata != NULL);
155    memset(mydata, 0, sizeof(struct file_vsic));
156
157    // Init VSIC data structures
158    vsic->ops = file_ops;
159    vsic->data = mydata;
160    vsic->blocksize = 512;	// XXX: Determine from drive?
161
162    return SYS_ERR_OK;
163}
164
165errval_t storage_vsic_driver_init(int argc, const char **argv,
166				  struct storage_vsic *vsic)
167{
168    return file_vsic_alloc(vsic);
169}
170
171/* errval_t storage_vsa_alloc(struct storage_vsa *vsa, size_t size) */
172/* { */
173/*     static int vsa_num = 0; */
174/*     char filename[32]; */
175
176/*     snprintf(filename, 32, "%u.vsa", vsa_num++); */
177/*     vsa->fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, 0644); */
178/*     assert(vsa->fd != -1); */
179
180/*     return SYS_ERR_OK; */
181/* } */
182
183errval_t storage_vsa_acquire(struct storage_vsa *vsa, const char *name,
184			     size_t size)
185{
186    char filename[32];
187
188    snprintf(filename, 32, "%s.vsa", name);
189    vsa->fd = open(filename, O_RDWR | O_CREAT, 0644);
190    assert(vsa->fd != -1);
191
192    return SYS_ERR_OK;
193}
194
195errval_t storage_vsa_resize(struct storage_vsa *vsa, size_t size)
196{
197    // No-op
198    return SYS_ERR_OK;
199}
200