~ubuntu-branches/ubuntu/utopic/xen/utopic

« back to all changes in this revision

Viewing changes to tools/fs-back/fs-ops.c

  • Committer: Bazaar Package Importer
  • Author(s): Bastian Blank
  • Date: 2010-05-06 15:47:38 UTC
  • mto: (1.3.1) (15.1.1 sid) (4.1.1 experimental)
  • mto: This revision was merged to the branch mainline in revision 3.
  • Revision ID: james.westby@ubuntu.com-20100506154738-agoz0rlafrh1fnq7
Tags: upstream-4.0.0
ImportĀ upstreamĀ versionĀ 4.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#undef NDEBUG
 
2
#include <stdio.h>
 
3
#include <aio.h>
 
4
#include <string.h>
 
5
#include <assert.h>
 
6
#include <fcntl.h>
 
7
#include <dirent.h>
 
8
#include <inttypes.h>
 
9
#include <xenctrl.h>
 
10
#include <sys/mman.h>
 
11
#include <sys/types.h>
 
12
#include <sys/stat.h>
 
13
#include <sys/statvfs.h>
 
14
#include <sys/mount.h>
 
15
#include <unistd.h>
 
16
#include <ctype.h>
 
17
#include "fs-backend.h"
 
18
#include "fs-debug.h"
 
19
 
 
20
/* For debugging only */
 
21
#include <sys/time.h>
 
22
#include <time.h>
 
23
 
 
24
 
 
25
#define BUFFER_SIZE 1024
 
26
 
 
27
static int check_export_path(const char *export_path, const char *path)
 
28
{
 
29
    int i;
 
30
    if (!export_path || !path)
 
31
        return -1;
 
32
    if (strlen(path) < strlen(export_path))
 
33
        return -1;
 
34
    if (strstr(path, "..") != NULL)
 
35
        return -1;
 
36
    for (i = 0; i < strlen(path); i++) {
 
37
        if (!isascii(path[i]))
 
38
            return -1;
 
39
    }
 
40
    if (strncmp(export_path, path, strlen(export_path)))
 
41
        return -1;
 
42
    else
 
43
        return 0;
 
44
}
 
45
 
 
46
static unsigned short get_request(struct fs_mount *mount, struct fsif_request *req)
 
47
{
 
48
    unsigned short id = get_id_from_freelist(mount->freelist); 
 
49
 
 
50
    FS_DEBUG("Private Request id: %d\n", id);
 
51
    memcpy(&mount->requests[id].req_shadow, req, sizeof(struct fsif_request));
 
52
    mount->requests[id].active = 1;
 
53
 
 
54
    return id;
 
55
}
 
56
 
 
57
static int get_fd(struct fs_mount *mount)
 
58
{
 
59
    int i;
 
60
 
 
61
    for (i = 0; i < MAX_FDS; i++)
 
62
        if (mount->fds[i] == -1)
 
63
            return i;
 
64
    return -1;
 
65
}
 
66
 
 
67
 
 
68
static void dispatch_file_open(struct fs_mount *mount, struct fsif_request *req)
 
69
{
 
70
    char *file_name;
 
71
    int fd;
 
72
    RING_IDX rsp_idx;
 
73
    fsif_response_t *rsp;
 
74
    uint16_t req_id;
 
75
 
 
76
    FS_DEBUG("Dispatching file open operation (gref=%d).\n", req->u.fopen.gref);
 
77
    /* Read the request, and open file */
 
78
    file_name = xc_gnttab_map_grant_ref(mount->gnth,
 
79
                                        mount->dom_id,
 
80
                                        req->u.fopen.gref,
 
81
                                        PROT_READ);
 
82
   
 
83
    req_id = req->id;
 
84
    FS_DEBUG("File open issued for %s\n", file_name); 
 
85
    if (check_export_path(mount->export->export_path, file_name) < 0) {
 
86
        FS_DEBUG("Filename check failed\n");
 
87
        fd = -1;
 
88
        goto out;
 
89
    }
 
90
    fd = get_fd(mount);
 
91
    if (fd >= 0) {
 
92
        int real_fd = open(file_name, O_RDWR);
 
93
        if (real_fd < 0)
 
94
            fd = -1;
 
95
        else
 
96
        {
 
97
            mount->fds[fd] = real_fd;
 
98
            FS_DEBUG("Got FD: %d for real %d\n", fd, real_fd);
 
99
        }
 
100
    }
 
101
out:
 
102
    if (xc_gnttab_munmap(mount->gnth, file_name, 1) != 0) {
 
103
        FS_DEBUG("ERROR: xc_gnttab_munmap failed errno=%d\n", errno);
 
104
        terminate_mount_request(mount);
 
105
    }
 
106
    /* We can advance the request consumer index, from here on, the request
 
107
     * should not be used (it may be overrinden by a response) */
 
108
    mount->ring.req_cons++;
 
109
 
 
110
 
 
111
    /* Get a response from the ring */
 
112
    rsp_idx = mount->ring.rsp_prod_pvt++;
 
113
    FS_DEBUG("Writing response at: idx=%d, id=%d\n", rsp_idx, req_id);
 
114
    rsp = RING_GET_RESPONSE(&mount->ring, rsp_idx);
 
115
    rsp->id = req_id; 
 
116
    rsp->u.ret_val = (uint64_t)fd;
 
117
}
 
118
 
 
119
static void dispatch_file_close(struct fs_mount *mount, struct fsif_request *req)
 
120
{
 
121
    int ret;
 
122
    RING_IDX rsp_idx;
 
123
    fsif_response_t *rsp;
 
124
    uint16_t req_id;
 
125
 
 
126
    FS_DEBUG("Dispatching file close operation (fd=%d).\n", req->u.fclose.fd);
 
127
   
 
128
    req_id = req->id;
 
129
    if (req->u.fclose.fd < MAX_FDS) {
 
130
        int fd = mount->fds[req->u.fclose.fd];
 
131
        ret = close(fd);
 
132
        mount->fds[req->u.fclose.fd] = -1;
 
133
    } else
 
134
        ret = -1;
 
135
    FS_DEBUG("Got ret: %d\n", ret);
 
136
    /* We can advance the request consumer index, from here on, the request
 
137
     * should not be used (it may be overrinden by a response) */
 
138
    mount->ring.req_cons++;
 
139
 
 
140
 
 
141
    /* Get a response from the ring */
 
142
    rsp_idx = mount->ring.rsp_prod_pvt++;
 
143
    FS_DEBUG("Writing response at: idx=%d, id=%d\n", rsp_idx, req_id);
 
144
    rsp = RING_GET_RESPONSE(&mount->ring, rsp_idx);
 
145
    rsp->id = req_id; 
 
146
    rsp->u.ret_val = (uint64_t)ret;
 
147
}
 
148
 
 
149
#define MAX_GNTS 16
 
150
static void dispatch_file_read(struct fs_mount *mount, struct fsif_request *req)
 
151
{
 
152
    void *buf;
 
153
    int fd, count;
 
154
    uint16_t req_id;
 
155
    unsigned short priv_id;
 
156
    struct fs_request *priv_req;
 
157
 
 
158
    /* Read the request */
 
159
    assert(req->u.fread.len > 0); 
 
160
    count = (req->u.fread.len - 1) / XC_PAGE_SIZE + 1;
 
161
    assert(count <= FSIF_NR_READ_GNTS);
 
162
    buf = xc_gnttab_map_domain_grant_refs(mount->gnth,
 
163
                                          count,
 
164
                                          mount->dom_id,
 
165
                                          req->u.fread.grefs,
 
166
                                          PROT_WRITE);
 
167
   
 
168
    req_id = req->id;
 
169
    FS_DEBUG("File read issued for FD=%d (len=%"PRIu64", offest=%"PRIu64")\n", 
 
170
            req->u.fread.fd, req->u.fread.len, req->u.fread.offset); 
 
171
 
 
172
    if (req->u.fread.fd < MAX_FDS)
 
173
        fd = mount->fds[req->u.fread.fd];
 
174
    else
 
175
        fd = -1;
 
176
 
 
177
    priv_id = get_request(mount, req);
 
178
    FS_DEBUG("Private id is: %d\n", priv_id);
 
179
    priv_req = &mount->requests[priv_id];
 
180
    priv_req->page = buf;
 
181
    priv_req->count = count;
 
182
    priv_req->id = priv_id;
 
183
 
 
184
    /* Dispatch AIO read request */
 
185
    bzero(&priv_req->aiocb, sizeof(struct aiocb));
 
186
    priv_req->aiocb.aio_fildes = fd;
 
187
    priv_req->aiocb.aio_nbytes = req->u.fread.len;
 
188
    priv_req->aiocb.aio_offset = req->u.fread.offset;
 
189
    priv_req->aiocb.aio_buf = buf;
 
190
    priv_req->aiocb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
 
191
    priv_req->aiocb.aio_sigevent.sigev_signo = SIGUSR2;
 
192
    priv_req->aiocb.aio_sigevent.sigev_value.sival_ptr = priv_req;
 
193
    if (aio_read(&priv_req->aiocb) < 0) {
 
194
        FS_DEBUG("ERROR: aio_read failed errno=%d\n", errno);
 
195
        xc_gnttab_munmap(mount->gnth, priv_req->page, priv_req->count);
 
196
        terminate_mount_request(mount);
 
197
    }
 
198
 
 
199
    /* We can advance the request consumer index, from here on, the request
 
200
     * should not be used (it may be overrinden by a response) */
 
201
    mount->ring.req_cons++;
 
202
}
 
203
 
 
204
static void end_file_read(struct fs_mount *mount, struct fs_request *priv_req)
 
205
{
 
206
    RING_IDX rsp_idx;
 
207
    fsif_response_t *rsp;
 
208
    uint16_t req_id;
 
209
 
 
210
    /* Release the grant */
 
211
    if (xc_gnttab_munmap(mount->gnth, priv_req->page, priv_req->count) != 0) {
 
212
        FS_DEBUG("ERROR: xc_gnttab_munmap failed errno=%d\n", errno);
 
213
        terminate_mount_request(mount);
 
214
    }
 
215
 
 
216
    /* Get a response from the ring */
 
217
    rsp_idx = mount->ring.rsp_prod_pvt++;
 
218
    req_id = priv_req->req_shadow.id; 
 
219
    FS_DEBUG("Writing response at: idx=%d, id=%d\n", rsp_idx, req_id);
 
220
    rsp = RING_GET_RESPONSE(&mount->ring, rsp_idx);
 
221
    rsp->id = req_id; 
 
222
    rsp->u.ret_val = (uint64_t)aio_return(&priv_req->aiocb);
 
223
}
 
224
 
 
225
static void dispatch_file_write(struct fs_mount *mount, struct fsif_request *req)
 
226
{
 
227
    void *buf;
 
228
    int fd, count;
 
229
    uint16_t req_id;
 
230
    unsigned short priv_id;
 
231
    struct fs_request *priv_req;
 
232
 
 
233
    /* Read the request */
 
234
    assert(req->u.fwrite.len > 0); 
 
235
    count = (req->u.fwrite.len - 1) / XC_PAGE_SIZE + 1;
 
236
    assert(count <= FSIF_NR_WRITE_GNTS);
 
237
    buf = xc_gnttab_map_domain_grant_refs(mount->gnth,
 
238
                                          count,
 
239
                                          mount->dom_id,
 
240
                                          req->u.fwrite.grefs,
 
241
                                          PROT_READ);
 
242
   
 
243
    req_id = req->id;
 
244
    FS_DEBUG("File write issued for FD=%d (len=%"PRIu64", offest=%"PRIu64")\n", 
 
245
            req->u.fwrite.fd, req->u.fwrite.len, req->u.fwrite.offset); 
 
246
   
 
247
    if (req->u.fwrite.fd < MAX_FDS)
 
248
        fd = mount->fds[req->u.fwrite.fd];
 
249
    else
 
250
        fd = -1;
 
251
 
 
252
    priv_id = get_request(mount, req);
 
253
    FS_DEBUG("Private id is: %d\n", priv_id);
 
254
    priv_req = &mount->requests[priv_id];
 
255
    priv_req->page = buf;
 
256
    priv_req->count = count;
 
257
    priv_req->id = priv_id;
 
258
 
 
259
    /* Dispatch AIO write request */
 
260
    bzero(&priv_req->aiocb, sizeof(struct aiocb));
 
261
    priv_req->aiocb.aio_fildes = fd;
 
262
    priv_req->aiocb.aio_nbytes = req->u.fwrite.len;
 
263
    priv_req->aiocb.aio_offset = req->u.fwrite.offset;
 
264
    priv_req->aiocb.aio_buf = buf;
 
265
    priv_req->aiocb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
 
266
    priv_req->aiocb.aio_sigevent.sigev_signo = SIGUSR2;
 
267
    priv_req->aiocb.aio_sigevent.sigev_value.sival_ptr = priv_req;
 
268
    if (aio_write(&priv_req->aiocb) < 0) {
 
269
        FS_DEBUG("ERROR: aio_write failed errno=%d\n", errno);
 
270
        xc_gnttab_munmap(mount->gnth, priv_req->page, priv_req->count);
 
271
        terminate_mount_request(mount);
 
272
    }
 
273
 
 
274
     
 
275
    /* We can advance the request consumer index, from here on, the request
 
276
     * should not be used (it may be overrinden by a response) */
 
277
    mount->ring.req_cons++;
 
278
}
 
279
 
 
280
static void end_file_write(struct fs_mount *mount, struct fs_request *priv_req)
 
281
{
 
282
    RING_IDX rsp_idx;
 
283
    fsif_response_t *rsp;
 
284
    uint16_t req_id;
 
285
 
 
286
    /* Release the grant */
 
287
    if (xc_gnttab_munmap(mount->gnth, priv_req->page, priv_req->count) != 0) {
 
288
        FS_DEBUG("ERROR: xc_gnttab_munmap failed errno=%d\n", errno);
 
289
        terminate_mount_request(mount);
 
290
    }
 
291
    
 
292
    /* Get a response from the ring */
 
293
    rsp_idx = mount->ring.rsp_prod_pvt++;
 
294
    req_id = priv_req->req_shadow.id; 
 
295
    FS_DEBUG("Writing response at: idx=%d, id=%d\n", rsp_idx, req_id);
 
296
    rsp = RING_GET_RESPONSE(&mount->ring, rsp_idx);
 
297
    rsp->id = req_id; 
 
298
    rsp->u.ret_val = (uint64_t)aio_return(&priv_req->aiocb);
 
299
}
 
300
 
 
301
static void dispatch_stat(struct fs_mount *mount, struct fsif_request *req)
 
302
{
 
303
    struct stat stat;
 
304
    int fd, ret;
 
305
    uint16_t req_id;
 
306
    RING_IDX rsp_idx;
 
307
    fsif_response_t *rsp;
 
308
 
 
309
    req_id = req->id;
 
310
    if (req->u.fstat.fd < MAX_FDS)
 
311
        fd = mount->fds[req->u.fstat.fd];
 
312
    else
 
313
        fd = -1;
 
314
 
 
315
    FS_DEBUG("File stat issued for FD=%d\n", req->u.fstat.fd); 
 
316
   
 
317
    /* We can advance the request consumer index, from here on, the request
 
318
     * should not be used (it may be overrinden by a response) */
 
319
    mount->ring.req_cons++;
 
320
   
 
321
    /* Stat, and create the response */ 
 
322
    ret = fstat(fd, &stat);
 
323
    FS_DEBUG("Mode=%o, uid=%d, a_time=%ld\n",
 
324
            stat.st_mode, stat.st_uid, (long)stat.st_atime);
 
325
    
 
326
    /* Get a response from the ring */
 
327
    rsp_idx = mount->ring.rsp_prod_pvt++;
 
328
    FS_DEBUG("Writing response at: idx=%d, id=%d\n", rsp_idx, req_id);
 
329
    rsp = RING_GET_RESPONSE(&mount->ring, rsp_idx);
 
330
    rsp->id = req_id; 
 
331
    rsp->u.fstat.stat_ret = (uint32_t)ret;
 
332
    rsp->u.fstat.stat_mode  = stat.st_mode;
 
333
    rsp->u.fstat.stat_uid   = stat.st_uid;
 
334
    rsp->u.fstat.stat_gid   = stat.st_gid;
 
335
#ifdef BLKGETSIZE
 
336
    if (S_ISBLK(stat.st_mode)) {
 
337
        unsigned long sectors;
 
338
        if (ioctl(fd, BLKGETSIZE, &sectors)) {
 
339
            perror("getting device size\n");
 
340
            rsp->u.fstat.stat_size = 0;
 
341
        } else
 
342
            rsp->u.fstat.stat_size = sectors << 9;
 
343
    } else
 
344
#endif
 
345
        rsp->u.fstat.stat_size  = stat.st_size;
 
346
    rsp->u.fstat.stat_atime = stat.st_atime;
 
347
    rsp->u.fstat.stat_mtime = stat.st_mtime;
 
348
    rsp->u.fstat.stat_ctime = stat.st_ctime;
 
349
}
 
350
 
 
351
 
 
352
static void dispatch_truncate(struct fs_mount *mount, struct fsif_request *req)
 
353
{
 
354
    int fd, ret;
 
355
    uint16_t req_id;
 
356
    RING_IDX rsp_idx;
 
357
    fsif_response_t *rsp;
 
358
    int64_t length;
 
359
 
 
360
    req_id = req->id;
 
361
    length = req->u.ftruncate.length;
 
362
    FS_DEBUG("File truncate issued for FD=%d, length=%"PRId64"\n", req->u.ftruncate.fd, length); 
 
363
   
 
364
    if (req->u.ftruncate.fd < MAX_FDS)
 
365
        fd = mount->fds[req->u.ftruncate.fd];
 
366
    else
 
367
        fd = -1;
 
368
 
 
369
    /* We can advance the request consumer index, from here on, the request
 
370
     * should not be used (it may be overrinden by a response) */
 
371
    mount->ring.req_cons++;
 
372
   
 
373
    /* Stat, and create the response */ 
 
374
    ret = ftruncate(fd, length);
 
375
 
 
376
    /* Get a response from the ring */
 
377
    rsp_idx = mount->ring.rsp_prod_pvt++;
 
378
    FS_DEBUG("Writing response at: idx=%d, id=%d\n", rsp_idx, req_id);
 
379
    rsp = RING_GET_RESPONSE(&mount->ring, rsp_idx);
 
380
    rsp->id = req_id; 
 
381
    rsp->u.ret_val = (uint64_t)ret;
 
382
}
 
383
 
 
384
static void dispatch_remove(struct fs_mount *mount, struct fsif_request *req)
 
385
{
 
386
    char *file_name;
 
387
    int ret;
 
388
    RING_IDX rsp_idx;
 
389
    fsif_response_t *rsp;
 
390
    uint16_t req_id;
 
391
 
 
392
    FS_DEBUG("Dispatching remove operation (gref=%d).\n", req->u.fremove.gref);
 
393
    /* Read the request, and open file */
 
394
    file_name = xc_gnttab_map_grant_ref(mount->gnth,
 
395
                                        mount->dom_id,
 
396
                                        req->u.fremove.gref,
 
397
                                        PROT_READ);
 
398
   
 
399
    req_id = req->id;
 
400
    FS_DEBUG("File remove issued for %s\n", file_name); 
 
401
    if (check_export_path(mount->export->export_path, file_name) < 0) {
 
402
        FS_DEBUG("Filename check failed\n");
 
403
        ret = -1;
 
404
    } else {
 
405
        ret = remove(file_name);
 
406
    }
 
407
    FS_DEBUG("Got ret: %d\n", ret);
 
408
    if (xc_gnttab_munmap(mount->gnth, file_name, 1) != 0) {
 
409
        FS_DEBUG("ERROR: xc_gnttab_munmap failed errno=%d\n", errno);
 
410
        terminate_mount_request(mount);
 
411
    }
 
412
    /* We can advance the request consumer index, from here on, the request
 
413
     * should not be used (it may be overrinden by a response) */
 
414
    mount->ring.req_cons++;
 
415
 
 
416
 
 
417
    /* Get a response from the ring */
 
418
    rsp_idx = mount->ring.rsp_prod_pvt++;
 
419
    FS_DEBUG("Writing response at: idx=%d, id=%d\n", rsp_idx, req_id);
 
420
    rsp = RING_GET_RESPONSE(&mount->ring, rsp_idx);
 
421
    rsp->id = req_id; 
 
422
    rsp->u.ret_val = (uint64_t)ret;
 
423
}
 
424
 
 
425
 
 
426
static void dispatch_rename(struct fs_mount *mount, struct fsif_request *req)
 
427
{
 
428
    char *buf, *old_file_name, *new_file_name;
 
429
    int ret;
 
430
    RING_IDX rsp_idx;
 
431
    fsif_response_t *rsp;
 
432
    uint16_t req_id;
 
433
 
 
434
    FS_DEBUG("Dispatching rename operation (gref=%d).\n", req->u.fremove.gref);
 
435
    /* Read the request, and open file */
 
436
    buf = xc_gnttab_map_grant_ref(mount->gnth,
 
437
                                  mount->dom_id,
 
438
                                  req->u.frename.gref,
 
439
                                  PROT_READ);
 
440
   
 
441
    req_id = req->id;
 
442
    old_file_name = buf + req->u.frename.old_name_offset;
 
443
    new_file_name = buf + req->u.frename.new_name_offset;
 
444
    FS_DEBUG("File rename issued for %s -> %s (buf=%s)\n", 
 
445
            old_file_name, new_file_name, buf); 
 
446
    if (check_export_path(mount->export->export_path, old_file_name) < 0 ||
 
447
        check_export_path(mount->export->export_path, new_file_name) < 0) {
 
448
        FS_DEBUG("Filename check failed\n");
 
449
        ret = -1;
 
450
    } else {
 
451
        ret = rename(old_file_name, new_file_name);
 
452
    }
 
453
    FS_DEBUG("Got ret: %d\n", ret);
 
454
    if (xc_gnttab_munmap(mount->gnth, buf, 1) != 0) {
 
455
        FS_DEBUG("ERROR: xc_gnttab_munmap failed errno=%d\n", errno);
 
456
        terminate_mount_request(mount);
 
457
    }
 
458
    /* We can advance the request consumer index, from here on, the request
 
459
     * should not be used (it may be overrinden by a response) */
 
460
    mount->ring.req_cons++;
 
461
 
 
462
 
 
463
    /* Get a response from the ring */
 
464
    rsp_idx = mount->ring.rsp_prod_pvt++;
 
465
    FS_DEBUG("Writing response at: idx=%d, id=%d\n", rsp_idx, req_id);
 
466
    rsp = RING_GET_RESPONSE(&mount->ring, rsp_idx);
 
467
    rsp->id = req_id; 
 
468
    rsp->u.ret_val = (uint64_t)ret;
 
469
}
 
470
 
 
471
 
 
472
static void dispatch_create(struct fs_mount *mount, struct fsif_request *req)
 
473
{
 
474
    char *file_name;
 
475
    int ret;
 
476
    int8_t directory;
 
477
    int32_t mode;
 
478
    RING_IDX rsp_idx;
 
479
    fsif_response_t *rsp;
 
480
    uint16_t req_id;
 
481
 
 
482
    FS_DEBUG("Dispatching file create operation (gref=%d).\n", req->u.fcreate.gref);
 
483
    /* Read the request, and create file/directory */
 
484
    mode = req->u.fcreate.mode;
 
485
    directory = req->u.fcreate.directory;
 
486
    file_name = xc_gnttab_map_grant_ref(mount->gnth,
 
487
                                        mount->dom_id,
 
488
                                        req->u.fcreate.gref,
 
489
                                        PROT_READ);
 
490
   
 
491
    req_id = req->id;
 
492
    if (check_export_path(mount->export->export_path, file_name) < 0) {
 
493
        FS_DEBUG("Filename check failed\n");
 
494
        ret = -1;
 
495
        goto out;
 
496
    }
 
497
    /* We can advance the request consumer index, from here on, the request
 
498
     * should not be used (it may be overrinden by a response) */
 
499
    mount->ring.req_cons++;
 
500
 
 
501
    if(directory)
 
502
    {
 
503
        FS_DEBUG("Issuing create for directory: %s\n", file_name);
 
504
        ret = mkdir(file_name, mode);
 
505
    }
 
506
    else
 
507
    {
 
508
        FS_DEBUG("Issuing create for file: %s\n", file_name);
 
509
        ret = get_fd(mount);
 
510
        if (ret >= 0) {
 
511
            int real_fd = creat(file_name, mode);
 
512
            if (real_fd < 0)
 
513
                ret = -1;
 
514
            else
 
515
            {
 
516
                mount->fds[ret] = real_fd;
 
517
                FS_DEBUG("Got FD: %d for real %d\n", ret, real_fd);
 
518
            }
 
519
        }
 
520
    }
 
521
out:
 
522
    if (xc_gnttab_munmap(mount->gnth, file_name, 1) != 0) {
 
523
        FS_DEBUG("ERROR: xc_gnttab_munmap failed errno=%d\n", errno);
 
524
        terminate_mount_request(mount);
 
525
    }
 
526
    FS_DEBUG("Got ret %d (errno=%d)\n", ret, errno);
 
527
 
 
528
    /* Get a response from the ring */
 
529
    rsp_idx = mount->ring.rsp_prod_pvt++;
 
530
    FS_DEBUG("Writing response at: idx=%d, id=%d\n", rsp_idx, req_id);
 
531
    rsp = RING_GET_RESPONSE(&mount->ring, rsp_idx);
 
532
    rsp->id = req_id; 
 
533
    rsp->u.ret_val = (uint64_t)ret;
 
534
}
 
535
 
 
536
static void dispatch_list(struct fs_mount *mount, struct fsif_request *req)
 
537
{
 
538
    char *file_name, *buf;
 
539
    uint32_t offset = 0, nr_files = 0, error_code = 0;
 
540
    uint64_t ret_val;
 
541
    RING_IDX rsp_idx;
 
542
    fsif_response_t *rsp;
 
543
    uint16_t req_id;
 
544
    DIR *dir;
 
545
    struct dirent *dirent = NULL;
 
546
 
 
547
    FS_DEBUG("Dispatching list operation (gref=%d).\n", req->u.flist.gref);
 
548
    /* Read the request, and list directory */
 
549
    offset = req->u.flist.offset;
 
550
    buf = file_name = xc_gnttab_map_grant_ref(mount->gnth,
 
551
                                        mount->dom_id,
 
552
                                        req->u.flist.gref,
 
553
                                        PROT_READ | PROT_WRITE);
 
554
   
 
555
    req_id = req->id;
 
556
    FS_DEBUG("Dir list issued for %s\n", file_name); 
 
557
    if (check_export_path(mount->export->export_path, file_name) < 0) {
 
558
        FS_DEBUG("Filename check failed\n");
 
559
        error_code = 1;
 
560
        goto error_out;
 
561
    }
 
562
    /* We can advance the request consumer index, from here on, the request
 
563
     * should not be used (it may be overrinden by a response) */
 
564
    mount->ring.req_cons++;
 
565
 
 
566
    ret_val = 0;
 
567
    nr_files = 0;
 
568
    dir = opendir(file_name);
 
569
    if(dir == NULL)
 
570
    {
 
571
        error_code = errno;
 
572
        goto error_out;
 
573
    }
 
574
    /* Skip offset dirs */
 
575
    dirent = readdir(dir);
 
576
    while(offset-- > 0 && dirent != NULL)
 
577
        dirent = readdir(dir);
 
578
    /* If there was any error with reading the directory, errno will be set */
 
579
    error_code = errno;
 
580
    /* Copy file names of the remaining non-NULL dirents into buf */
 
581
    if (NAME_MAX >= XC_PAGE_SIZE >> 1)
 
582
        goto error_out;
 
583
    while(dirent != NULL && 
 
584
            (XC_PAGE_SIZE - ((unsigned long)buf & XC_PAGE_MASK) > NAME_MAX))
 
585
    {
 
586
        int curr_length = strlen(dirent->d_name) + 1;
 
587
        
 
588
        memcpy(buf, dirent->d_name, curr_length);
 
589
        buf += curr_length;
 
590
        dirent = readdir(dir);
 
591
        error_code = errno;
 
592
        nr_files++;
 
593
    }
 
594
error_out:    
 
595
    ret_val = ((nr_files << NR_FILES_SHIFT) & NR_FILES_MASK) | 
 
596
              ((error_code << ERROR_SHIFT) & ERROR_MASK) | 
 
597
              (dirent != NULL ? HAS_MORE_FLAG : 0);
 
598
    if (xc_gnttab_munmap(mount->gnth, file_name, 1) != 0) {
 
599
        FS_DEBUG("ERROR: xc_gnttab_munmap failed errno=%d\n", errno);
 
600
        terminate_mount_request(mount);
 
601
    }
 
602
 
 
603
    /* Get a response from the ring */
 
604
    rsp_idx = mount->ring.rsp_prod_pvt++;
 
605
    FS_DEBUG("Writing response at: idx=%d, id=%d\n", rsp_idx, req_id);
 
606
    rsp = RING_GET_RESPONSE(&mount->ring, rsp_idx);
 
607
    rsp->id = req_id; 
 
608
    rsp->u.ret_val = ret_val;
 
609
}
 
610
 
 
611
static void dispatch_chmod(struct fs_mount *mount, struct fsif_request *req)
 
612
{
 
613
    int fd, ret;
 
614
    RING_IDX rsp_idx;
 
615
    fsif_response_t *rsp;
 
616
    uint16_t req_id;
 
617
    int32_t mode;
 
618
 
 
619
    FS_DEBUG("Dispatching file chmod operation (fd=%d, mode=%o).\n", 
 
620
            req->u.fchmod.fd, req->u.fchmod.mode);
 
621
    req_id = req->id;
 
622
    if (req->u.fchmod.fd < MAX_FDS)
 
623
        fd = mount->fds[req->u.fchmod.fd];
 
624
    else
 
625
        fd = -1;
 
626
 
 
627
    mode = req->u.fchmod.mode;
 
628
    /* We can advance the request consumer index, from here on, the request
 
629
     * should not be used (it may be overrinden by a response) */
 
630
    mount->ring.req_cons++;
 
631
 
 
632
    ret = fchmod(fd, mode); 
 
633
 
 
634
    /* Get a response from the ring */
 
635
    rsp_idx = mount->ring.rsp_prod_pvt++;
 
636
    FS_DEBUG("Writing response at: idx=%d, id=%d\n", rsp_idx, req_id);
 
637
    rsp = RING_GET_RESPONSE(&mount->ring, rsp_idx);
 
638
    rsp->id = req_id; 
 
639
    rsp->u.ret_val = (uint64_t)ret;
 
640
}
 
641
 
 
642
static void dispatch_fs_space(struct fs_mount *mount, struct fsif_request *req)
 
643
{
 
644
    char *file_name;
 
645
    RING_IDX rsp_idx;
 
646
    fsif_response_t *rsp;
 
647
    uint16_t req_id;
 
648
    struct statvfs stat;
 
649
    int64_t ret;
 
650
 
 
651
    FS_DEBUG("Dispatching fs space operation (gref=%d).\n", req->u.fspace.gref);
 
652
    /* Read the request, and open file */
 
653
    file_name = xc_gnttab_map_grant_ref(mount->gnth,
 
654
                                        mount->dom_id,
 
655
                                        req->u.fspace.gref,
 
656
                                        PROT_READ);
 
657
   
 
658
    req_id = req->id;
 
659
    FS_DEBUG("Fs space issued for %s\n", file_name); 
 
660
    if (check_export_path(mount->export->export_path, file_name) < 0) {
 
661
        FS_DEBUG("Filename check failed\n");
 
662
        ret = -1;
 
663
    } else {
 
664
        ret = statvfs(file_name, &stat);
 
665
    }
 
666
    if(ret >= 0)
 
667
        ret = stat.f_bsize * stat.f_bfree;
 
668
 
 
669
    if (xc_gnttab_munmap(mount->gnth, file_name, 1) != 0) {
 
670
        FS_DEBUG("ERROR: xc_gnttab_munmap failed errno=%d\n", errno);
 
671
        terminate_mount_request(mount);
 
672
    }
 
673
    /* We can advance the request consumer index, from here on, the request
 
674
     * should not be used (it may be overrinden by a response) */
 
675
    mount->ring.req_cons++;
 
676
 
 
677
 
 
678
    /* Get a response from the ring */
 
679
    rsp_idx = mount->ring.rsp_prod_pvt++;
 
680
    FS_DEBUG("Writing response at: idx=%d, id=%d\n", rsp_idx, req_id);
 
681
    rsp = RING_GET_RESPONSE(&mount->ring, rsp_idx);
 
682
    rsp->id = req_id; 
 
683
    rsp->u.ret_val = (uint64_t)ret;
 
684
}
 
685
 
 
686
static void dispatch_file_sync(struct fs_mount *mount, struct fsif_request *req)
 
687
{
 
688
    int fd;
 
689
    uint16_t req_id;
 
690
    unsigned short priv_id;
 
691
    struct fs_request *priv_req;
 
692
 
 
693
    req_id = req->id;
 
694
    if (req->u.fsync.fd < MAX_FDS)
 
695
        fd = mount->fds[req->u.fsync.fd];
 
696
    else
 
697
        fd = -1;
 
698
 
 
699
    FS_DEBUG("File sync issued for FD=%d\n", req->u.fsync.fd); 
 
700
   
 
701
    priv_id = get_request(mount, req);
 
702
    FS_DEBUG("Private id is: %d\n", priv_id);
 
703
    priv_req = &mount->requests[priv_id];
 
704
    priv_req->id = priv_id;
 
705
 
 
706
    /* Dispatch AIO read request */
 
707
    bzero(&priv_req->aiocb, sizeof(struct aiocb));
 
708
    priv_req->aiocb.aio_fildes = fd;
 
709
    priv_req->aiocb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
 
710
    priv_req->aiocb.aio_sigevent.sigev_signo = SIGUSR2;
 
711
    priv_req->aiocb.aio_sigevent.sigev_value.sival_ptr = priv_req;
 
712
    if (aio_fsync(O_SYNC, &priv_req->aiocb) < 0) {
 
713
        FS_DEBUG("ERROR: aio_fsync failed errno=%d\n", errno);
 
714
        terminate_mount_request(mount);
 
715
    }
 
716
 
 
717
    /* We can advance the request consumer index, from here on, the request
 
718
     * should not be used (it may be overrinden by a response) */
 
719
    mount->ring.req_cons++;
 
720
}
 
721
 
 
722
static void end_file_sync(struct fs_mount *mount, struct fs_request *priv_req)
 
723
{
 
724
    RING_IDX rsp_idx;
 
725
    fsif_response_t *rsp;
 
726
    uint16_t req_id;
 
727
 
 
728
    /* Get a response from the ring */
 
729
    rsp_idx = mount->ring.rsp_prod_pvt++;
 
730
    req_id = priv_req->req_shadow.id; 
 
731
    FS_DEBUG("Writing response at: idx=%d, id=%d\n", rsp_idx, req_id);
 
732
    rsp = RING_GET_RESPONSE(&mount->ring, rsp_idx);
 
733
    rsp->id = req_id; 
 
734
    rsp->u.ret_val = (uint64_t)aio_return(&priv_req->aiocb);
 
735
}
 
736
 
 
737
struct fs_op fopen_op     = {.type             = REQ_FILE_OPEN,
 
738
                             .dispatch_handler = dispatch_file_open,
 
739
                             .response_handler = NULL};
 
740
struct fs_op fclose_op    = {.type             = REQ_FILE_CLOSE,
 
741
                             .dispatch_handler = dispatch_file_close,
 
742
                             .response_handler = NULL};
 
743
struct fs_op fread_op     = {.type             = REQ_FILE_READ,
 
744
                             .dispatch_handler = dispatch_file_read,
 
745
                             .response_handler = end_file_read};
 
746
struct fs_op fwrite_op    = {.type             = REQ_FILE_WRITE,
 
747
                             .dispatch_handler = dispatch_file_write,
 
748
                             .response_handler = end_file_write};
 
749
struct fs_op fstat_op     = {.type             = REQ_STAT,
 
750
                             .dispatch_handler = dispatch_stat,
 
751
                             .response_handler = NULL};
 
752
struct fs_op ftruncate_op = {.type             = REQ_FILE_TRUNCATE,
 
753
                             .dispatch_handler = dispatch_truncate,
 
754
                             .response_handler = NULL};
 
755
struct fs_op fremove_op   = {.type             = REQ_REMOVE,
 
756
                             .dispatch_handler = dispatch_remove,
 
757
                             .response_handler = NULL};
 
758
struct fs_op frename_op   = {.type             = REQ_RENAME,
 
759
                             .dispatch_handler = dispatch_rename,
 
760
                             .response_handler = NULL};
 
761
struct fs_op fcreate_op   = {.type             = REQ_CREATE,
 
762
                             .dispatch_handler = dispatch_create,
 
763
                             .response_handler = NULL};
 
764
struct fs_op flist_op     = {.type             = REQ_DIR_LIST,
 
765
                             .dispatch_handler = dispatch_list,
 
766
                             .response_handler = NULL};
 
767
struct fs_op fchmod_op    = {.type             = REQ_CHMOD,
 
768
                             .dispatch_handler = dispatch_chmod,
 
769
                             .response_handler = NULL};
 
770
struct fs_op fspace_op    = {.type             = REQ_FS_SPACE,
 
771
                             .dispatch_handler = dispatch_fs_space,
 
772
                             .response_handler = NULL};
 
773
struct fs_op fsync_op     = {.type             = REQ_FILE_SYNC,
 
774
                             .dispatch_handler = dispatch_file_sync,
 
775
                             .response_handler = end_file_sync};
 
776
 
 
777
 
 
778
struct fs_op *fsops[] = {&fopen_op, 
 
779
                         &fclose_op, 
 
780
                         &fread_op, 
 
781
                         &fwrite_op, 
 
782
                         &fstat_op, 
 
783
                         &ftruncate_op, 
 
784
                         &fremove_op, 
 
785
                         &frename_op, 
 
786
                         &fcreate_op, 
 
787
                         &flist_op, 
 
788
                         &fchmod_op, 
 
789
                         &fspace_op, 
 
790
                         &fsync_op, 
 
791
                         NULL};