~galfy/helenos/bird-port-mainline

« back to all changes in this revision

Viewing changes to uspace/srv/bd/file_bd/file_bd.c

  • Committer: Martin Decky
  • Date: 2009-08-04 11:19:19 UTC
  • Revision ID: martin@uranus.dsrg.hide.ms.mff.cuni.cz-20090804111919-evyclddlr3v5lhmp
Initial import

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2009 Jiri Svoboda
 
3
 * All rights reserved.
 
4
 *
 
5
 * Redistribution and use in source and binary forms, with or without
 
6
 * modification, are permitted provided that the following conditions
 
7
 * are met:
 
8
 *
 
9
 * - Redistributions of source code must retain the above copyright
 
10
 *   notice, this list of conditions and the following disclaimer.
 
11
 * - Redistributions in binary form must reproduce the above copyright
 
12
 *   notice, this list of conditions and the following disclaimer in the
 
13
 *   documentation and/or other materials provided with the distribution.
 
14
 * - The name of the author may not be used to endorse or promote products
 
15
 *   derived from this software without specific prior written permission.
 
16
 *
 
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
25
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
27
 */
 
28
 
 
29
/** @addtogroup bd
 
30
 * @{
 
31
 */
 
32
 
 
33
/**
 
34
 * @file
 
35
 * @brief File-backed block device driver
 
36
 *
 
37
 * Allows accessing a file as a block device. Useful for, e.g., mounting
 
38
 * a disk image.
 
39
 */
 
40
 
 
41
#include <stdio.h>
 
42
#include <unistd.h>
 
43
#include <ipc/ipc.h>
 
44
#include <ipc/bd.h>
 
45
#include <async.h>
 
46
#include <as.h>
 
47
#include <fibril_sync.h>
 
48
#include <devmap.h>
 
49
#include <sys/types.h>
 
50
#include <errno.h>
 
51
#include <bool.h>
 
52
#include <task.h>
 
53
 
 
54
#define NAME "file_bd"
 
55
 
 
56
static size_t comm_size;
 
57
static FILE *img;
 
58
 
 
59
static dev_handle_t dev_handle;
 
60
static fibril_mutex_t dev_lock;
 
61
 
 
62
static int file_bd_init(const char *fname);
 
63
static void file_bd_connection(ipc_callid_t iid, ipc_call_t *icall);
 
64
static int file_bd_read(off_t blk_idx, size_t size, void *buf);
 
65
static int file_bd_write(off_t blk_idx, size_t size, void *buf);
 
66
 
 
67
int main(int argc, char **argv)
 
68
{
 
69
        int rc;
 
70
 
 
71
        printf(NAME ": File-backed block device driver\n");
 
72
 
 
73
        if (argc != 3) {
 
74
                printf("Expected two arguments (image name, device name).\n");
 
75
                return -1;
 
76
        }
 
77
 
 
78
        if (file_bd_init(argv[1]) != EOK)
 
79
                return -1;
 
80
 
 
81
        rc = devmap_device_register(argv[2], &dev_handle);
 
82
        if (rc != EOK) {
 
83
                devmap_hangup_phone(DEVMAP_DRIVER);
 
84
                printf(NAME ": Unable to register device %s.\n",
 
85
                        argv[2]);
 
86
                return rc;
 
87
        }
 
88
 
 
89
        printf(NAME ": Accepting connections\n");
 
90
        task_retval(0);
 
91
        async_manager();
 
92
 
 
93
        /* Not reached */
 
94
        return 0;
 
95
}
 
96
 
 
97
static int file_bd_init(const char *fname)
 
98
{
 
99
        int rc;
 
100
 
 
101
        rc = devmap_driver_register(NAME, file_bd_connection);
 
102
        if (rc < 0) {
 
103
                printf(NAME ": Unable to register driver.\n");
 
104
                return rc;
 
105
        }
 
106
 
 
107
        img = fopen(fname, "rb+");
 
108
        if (img == NULL)
 
109
                return EINVAL;
 
110
 
 
111
        fibril_mutex_initialize(&dev_lock);
 
112
 
 
113
        return EOK;
 
114
}
 
115
 
 
116
static void file_bd_connection(ipc_callid_t iid, ipc_call_t *icall)
 
117
{
 
118
        void *fs_va = NULL;
 
119
        ipc_callid_t callid;
 
120
        ipc_call_t call;
 
121
        ipcarg_t method;
 
122
        int flags;
 
123
        int retval;
 
124
        off_t idx;
 
125
        size_t size;
 
126
 
 
127
        /* Answer the IPC_M_CONNECT_ME_TO call. */
 
128
        ipc_answer_0(iid, EOK);
 
129
 
 
130
        if (!ipc_share_out_receive(&callid, &comm_size, &flags)) {
 
131
                ipc_answer_0(callid, EHANGUP);
 
132
                return;
 
133
        }
 
134
 
 
135
        fs_va = as_get_mappable_page(comm_size);
 
136
        if (fs_va == NULL) {
 
137
                ipc_answer_0(callid, EHANGUP);
 
138
                return;
 
139
        }
 
140
 
 
141
        (void) ipc_share_out_finalize(callid, fs_va);
 
142
 
 
143
        while (1) {
 
144
                callid = async_get_call(&call);
 
145
                method = IPC_GET_METHOD(call);
 
146
                switch (method) {
 
147
                case IPC_M_PHONE_HUNGUP:
 
148
                        /* The other side has hung up. */
 
149
                        ipc_answer_0(callid, EOK);
 
150
                        return;
 
151
                case BD_READ_BLOCK:
 
152
                case BD_WRITE_BLOCK:
 
153
                        idx = IPC_GET_ARG1(call);
 
154
                        size = IPC_GET_ARG2(call);
 
155
                        if (size > comm_size) {
 
156
                                retval = EINVAL;
 
157
                                break;
 
158
                        }
 
159
                        if (method == BD_READ_BLOCK)
 
160
                                retval = file_bd_read(idx, size, fs_va);
 
161
                        else
 
162
                                retval = file_bd_write(idx, size, fs_va);
 
163
                        break;
 
164
                default:
 
165
                        retval = EINVAL;
 
166
                        break;
 
167
                }
 
168
                ipc_answer_0(callid, retval);
 
169
        }
 
170
}
 
171
 
 
172
static int file_bd_read(off_t blk_idx, size_t size, void *buf)
 
173
{
 
174
        size_t n_rd;
 
175
 
 
176
        fibril_mutex_lock(&dev_lock);
 
177
 
 
178
        fseek(img, blk_idx * size, SEEK_SET);
 
179
        n_rd = fread(buf, 1, size, img);
 
180
 
 
181
        if (ferror(img)) {
 
182
                fibril_mutex_unlock(&dev_lock);
 
183
                return EIO;     /* Read error */
 
184
        }
 
185
 
 
186
        fibril_mutex_unlock(&dev_lock);
 
187
 
 
188
        if (n_rd < size) 
 
189
                return EINVAL;  /* Read beyond end of disk */
 
190
 
 
191
        return EOK;
 
192
}
 
193
 
 
194
static int file_bd_write(off_t blk_idx, size_t size, void *buf)
 
195
{
 
196
        size_t n_wr;
 
197
 
 
198
        fibril_mutex_lock(&dev_lock);
 
199
 
 
200
        fseek(img, blk_idx * size, SEEK_SET);
 
201
        n_wr = fread(buf, 1, size, img);
 
202
 
 
203
        if (ferror(img) || n_wr < size) {
 
204
                fibril_mutex_unlock(&dev_lock);
 
205
                return EIO;     /* Write error */
 
206
        }
 
207
 
 
208
        fibril_mutex_unlock(&dev_lock);
 
209
 
 
210
        return EOK;
 
211
}
 
212
 
 
213
/**
 
214
 * @}
 
215
 */