Files
xen/tools/fs-back/fs-ops.c
T
Keir Fraser 6d821524b1 fs-back: better error handling in fs-backend
Currently most of the error checking in fs-backend is done by the use
of asserts that would terminate the daemon in case of a single error
on a single request.  This patch replaces the asserts with debugging
messages and terminates the connection on which the error occurred.
With this patch applied I was able to complete successfully over 1000
live migrations with stubdoms.

Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
2009-07-08 10:58:09 +01:00

792 lines
26 KiB
C

#undef NDEBUG
#include <stdio.h>
#include <aio.h>
#include <string.h>
#include <assert.h>
#include <fcntl.h>
#include <dirent.h>
#include <inttypes.h>
#include <xenctrl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
#include <sys/mount.h>
#include <unistd.h>
#include <ctype.h>
#include "fs-backend.h"
#include "fs-debug.h"
/* For debugging only */
#include <sys/time.h>
#include <time.h>
#define BUFFER_SIZE 1024
static int check_export_path(const char *export_path, const char *path)
{
int i;
if (!export_path || !path)
return -1;
if (strlen(path) < strlen(export_path))
return -1;
if (strstr(path, "..") != NULL)
return -1;
for (i = 0; i < strlen(path); i++) {
if (!isascii(path[i]))
return -1;
}
if (strncmp(export_path, path, strlen(export_path)))
return -1;
else
return 0;
}
static unsigned short get_request(struct fs_mount *mount, struct fsif_request *req)
{
unsigned short id = get_id_from_freelist(mount->freelist);
FS_DEBUG("Private Request id: %d\n", id);
memcpy(&mount->requests[id].req_shadow, req, sizeof(struct fsif_request));
mount->requests[id].active = 1;
return id;
}
static int get_fd(struct fs_mount *mount)
{
int i;
for (i = 0; i < MAX_FDS; i++)
if (mount->fds[i] == -1)
return i;
return -1;
}
static void dispatch_file_open(struct fs_mount *mount, struct fsif_request *req)
{
char *file_name;
int fd;
RING_IDX rsp_idx;
fsif_response_t *rsp;
uint16_t req_id;
FS_DEBUG("Dispatching file open operation (gref=%d).\n", req->u.fopen.gref);
/* Read the request, and open file */
file_name = xc_gnttab_map_grant_ref(mount->gnth,
mount->dom_id,
req->u.fopen.gref,
PROT_READ);
req_id = req->id;
FS_DEBUG("File open issued for %s\n", file_name);
if (check_export_path(mount->export->export_path, file_name) < 0) {
FS_DEBUG("Filename check failed\n");
fd = -1;
goto out;
}
fd = get_fd(mount);
if (fd >= 0) {
int real_fd = open(file_name, O_RDWR);
if (real_fd < 0)
fd = -1;
else
{
mount->fds[fd] = real_fd;
FS_DEBUG("Got FD: %d for real %d\n", fd, real_fd);
}
}
out:
if (xc_gnttab_munmap(mount->gnth, file_name, 1) != 0) {
FS_DEBUG("ERROR: xc_gnttab_munmap failed errno=%d\n", errno);
terminate_mount_request(mount);
}
/* We can advance the request consumer index, from here on, the request
* should not be used (it may be overrinden by a response) */
mount->ring.req_cons++;
/* Get a response from the ring */
rsp_idx = mount->ring.rsp_prod_pvt++;
FS_DEBUG("Writing response at: idx=%d, id=%d\n", rsp_idx, req_id);
rsp = RING_GET_RESPONSE(&mount->ring, rsp_idx);
rsp->id = req_id;
rsp->u.ret_val = (uint64_t)fd;
}
static void dispatch_file_close(struct fs_mount *mount, struct fsif_request *req)
{
int ret;
RING_IDX rsp_idx;
fsif_response_t *rsp;
uint16_t req_id;
FS_DEBUG("Dispatching file close operation (fd=%d).\n", req->u.fclose.fd);
req_id = req->id;
if (req->u.fclose.fd < MAX_FDS) {
int fd = mount->fds[req->u.fclose.fd];
ret = close(fd);
mount->fds[req->u.fclose.fd] = -1;
} else
ret = -1;
FS_DEBUG("Got ret: %d\n", ret);
/* We can advance the request consumer index, from here on, the request
* should not be used (it may be overrinden by a response) */
mount->ring.req_cons++;
/* Get a response from the ring */
rsp_idx = mount->ring.rsp_prod_pvt++;
FS_DEBUG("Writing response at: idx=%d, id=%d\n", rsp_idx, req_id);
rsp = RING_GET_RESPONSE(&mount->ring, rsp_idx);
rsp->id = req_id;
rsp->u.ret_val = (uint64_t)ret;
}
#define MAX_GNTS 16
static void dispatch_file_read(struct fs_mount *mount, struct fsif_request *req)
{
void *buf;
int fd, count;
uint16_t req_id;
unsigned short priv_id;
struct fs_request *priv_req;
/* Read the request */
assert(req->u.fread.len > 0);
count = (req->u.fread.len - 1) / XC_PAGE_SIZE + 1;
assert(count <= FSIF_NR_READ_GNTS);
buf = xc_gnttab_map_domain_grant_refs(mount->gnth,
count,
mount->dom_id,
req->u.fread.grefs,
PROT_WRITE);
req_id = req->id;
FS_DEBUG("File read issued for FD=%d (len=%"PRIu64", offest=%"PRIu64")\n",
req->u.fread.fd, req->u.fread.len, req->u.fread.offset);
if (req->u.fread.fd < MAX_FDS)
fd = mount->fds[req->u.fread.fd];
else
fd = -1;
priv_id = get_request(mount, req);
FS_DEBUG("Private id is: %d\n", priv_id);
priv_req = &mount->requests[priv_id];
priv_req->page = buf;
priv_req->count = count;
priv_req->id = priv_id;
/* Dispatch AIO read request */
bzero(&priv_req->aiocb, sizeof(struct aiocb));
priv_req->aiocb.aio_fildes = fd;
priv_req->aiocb.aio_nbytes = req->u.fread.len;
priv_req->aiocb.aio_offset = req->u.fread.offset;
priv_req->aiocb.aio_buf = buf;
priv_req->aiocb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
priv_req->aiocb.aio_sigevent.sigev_signo = SIGUSR2;
priv_req->aiocb.aio_sigevent.sigev_value.sival_ptr = priv_req;
if (aio_read(&priv_req->aiocb) < 0) {
FS_DEBUG("ERROR: aio_read failed errno=%d\n", errno);
xc_gnttab_munmap(mount->gnth, priv_req->page, priv_req->count);
terminate_mount_request(mount);
}
/* We can advance the request consumer index, from here on, the request
* should not be used (it may be overrinden by a response) */
mount->ring.req_cons++;
}
static void end_file_read(struct fs_mount *mount, struct fs_request *priv_req)
{
RING_IDX rsp_idx;
fsif_response_t *rsp;
uint16_t req_id;
/* Release the grant */
if (xc_gnttab_munmap(mount->gnth, priv_req->page, priv_req->count) != 0) {
FS_DEBUG("ERROR: xc_gnttab_munmap failed errno=%d\n", errno);
terminate_mount_request(mount);
}
/* Get a response from the ring */
rsp_idx = mount->ring.rsp_prod_pvt++;
req_id = priv_req->req_shadow.id;
FS_DEBUG("Writing response at: idx=%d, id=%d\n", rsp_idx, req_id);
rsp = RING_GET_RESPONSE(&mount->ring, rsp_idx);
rsp->id = req_id;
rsp->u.ret_val = (uint64_t)aio_return(&priv_req->aiocb);
}
static void dispatch_file_write(struct fs_mount *mount, struct fsif_request *req)
{
void *buf;
int fd, count;
uint16_t req_id;
unsigned short priv_id;
struct fs_request *priv_req;
/* Read the request */
assert(req->u.fwrite.len > 0);
count = (req->u.fwrite.len - 1) / XC_PAGE_SIZE + 1;
assert(count <= FSIF_NR_WRITE_GNTS);
buf = xc_gnttab_map_domain_grant_refs(mount->gnth,
count,
mount->dom_id,
req->u.fwrite.grefs,
PROT_READ);
req_id = req->id;
FS_DEBUG("File write issued for FD=%d (len=%"PRIu64", offest=%"PRIu64")\n",
req->u.fwrite.fd, req->u.fwrite.len, req->u.fwrite.offset);
if (req->u.fwrite.fd < MAX_FDS)
fd = mount->fds[req->u.fwrite.fd];
else
fd = -1;
priv_id = get_request(mount, req);
FS_DEBUG("Private id is: %d\n", priv_id);
priv_req = &mount->requests[priv_id];
priv_req->page = buf;
priv_req->count = count;
priv_req->id = priv_id;
/* Dispatch AIO write request */
bzero(&priv_req->aiocb, sizeof(struct aiocb));
priv_req->aiocb.aio_fildes = fd;
priv_req->aiocb.aio_nbytes = req->u.fwrite.len;
priv_req->aiocb.aio_offset = req->u.fwrite.offset;
priv_req->aiocb.aio_buf = buf;
priv_req->aiocb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
priv_req->aiocb.aio_sigevent.sigev_signo = SIGUSR2;
priv_req->aiocb.aio_sigevent.sigev_value.sival_ptr = priv_req;
if (aio_write(&priv_req->aiocb) < 0) {
FS_DEBUG("ERROR: aio_write failed errno=%d\n", errno);
xc_gnttab_munmap(mount->gnth, priv_req->page, priv_req->count);
terminate_mount_request(mount);
}
/* We can advance the request consumer index, from here on, the request
* should not be used (it may be overrinden by a response) */
mount->ring.req_cons++;
}
static void end_file_write(struct fs_mount *mount, struct fs_request *priv_req)
{
RING_IDX rsp_idx;
fsif_response_t *rsp;
uint16_t req_id;
/* Release the grant */
if (xc_gnttab_munmap(mount->gnth, priv_req->page, priv_req->count) != 0) {
FS_DEBUG("ERROR: xc_gnttab_munmap failed errno=%d\n", errno);
terminate_mount_request(mount);
}
/* Get a response from the ring */
rsp_idx = mount->ring.rsp_prod_pvt++;
req_id = priv_req->req_shadow.id;
FS_DEBUG("Writing response at: idx=%d, id=%d\n", rsp_idx, req_id);
rsp = RING_GET_RESPONSE(&mount->ring, rsp_idx);
rsp->id = req_id;
rsp->u.ret_val = (uint64_t)aio_return(&priv_req->aiocb);
}
static void dispatch_stat(struct fs_mount *mount, struct fsif_request *req)
{
struct stat stat;
int fd, ret;
uint16_t req_id;
RING_IDX rsp_idx;
fsif_response_t *rsp;
req_id = req->id;
if (req->u.fstat.fd < MAX_FDS)
fd = mount->fds[req->u.fstat.fd];
else
fd = -1;
FS_DEBUG("File stat issued for FD=%d\n", req->u.fstat.fd);
/* We can advance the request consumer index, from here on, the request
* should not be used (it may be overrinden by a response) */
mount->ring.req_cons++;
/* Stat, and create the response */
ret = fstat(fd, &stat);
FS_DEBUG("Mode=%o, uid=%d, a_time=%ld\n",
stat.st_mode, stat.st_uid, (long)stat.st_atime);
/* Get a response from the ring */
rsp_idx = mount->ring.rsp_prod_pvt++;
FS_DEBUG("Writing response at: idx=%d, id=%d\n", rsp_idx, req_id);
rsp = RING_GET_RESPONSE(&mount->ring, rsp_idx);
rsp->id = req_id;
rsp->u.fstat.stat_ret = (uint32_t)ret;
rsp->u.fstat.stat_mode = stat.st_mode;
rsp->u.fstat.stat_uid = stat.st_uid;
rsp->u.fstat.stat_gid = stat.st_gid;
#ifdef BLKGETSIZE
if (S_ISBLK(stat.st_mode)) {
unsigned long sectors;
if (ioctl(fd, BLKGETSIZE, &sectors)) {
perror("getting device size\n");
rsp->u.fstat.stat_size = 0;
} else
rsp->u.fstat.stat_size = sectors << 9;
} else
#endif
rsp->u.fstat.stat_size = stat.st_size;
rsp->u.fstat.stat_atime = stat.st_atime;
rsp->u.fstat.stat_mtime = stat.st_mtime;
rsp->u.fstat.stat_ctime = stat.st_ctime;
}
static void dispatch_truncate(struct fs_mount *mount, struct fsif_request *req)
{
int fd, ret;
uint16_t req_id;
RING_IDX rsp_idx;
fsif_response_t *rsp;
int64_t length;
req_id = req->id;
length = req->u.ftruncate.length;
FS_DEBUG("File truncate issued for FD=%d, length=%"PRId64"\n", req->u.ftruncate.fd, length);
if (req->u.ftruncate.fd < MAX_FDS)
fd = mount->fds[req->u.ftruncate.fd];
else
fd = -1;
/* We can advance the request consumer index, from here on, the request
* should not be used (it may be overrinden by a response) */
mount->ring.req_cons++;
/* Stat, and create the response */
ret = ftruncate(fd, length);
/* Get a response from the ring */
rsp_idx = mount->ring.rsp_prod_pvt++;
FS_DEBUG("Writing response at: idx=%d, id=%d\n", rsp_idx, req_id);
rsp = RING_GET_RESPONSE(&mount->ring, rsp_idx);
rsp->id = req_id;
rsp->u.ret_val = (uint64_t)ret;
}
static void dispatch_remove(struct fs_mount *mount, struct fsif_request *req)
{
char *file_name;
int ret;
RING_IDX rsp_idx;
fsif_response_t *rsp;
uint16_t req_id;
FS_DEBUG("Dispatching remove operation (gref=%d).\n", req->u.fremove.gref);
/* Read the request, and open file */
file_name = xc_gnttab_map_grant_ref(mount->gnth,
mount->dom_id,
req->u.fremove.gref,
PROT_READ);
req_id = req->id;
FS_DEBUG("File remove issued for %s\n", file_name);
if (check_export_path(mount->export->export_path, file_name) < 0) {
FS_DEBUG("Filename check failed\n");
ret = -1;
} else {
ret = remove(file_name);
}
FS_DEBUG("Got ret: %d\n", ret);
if (xc_gnttab_munmap(mount->gnth, file_name, 1) != 0) {
FS_DEBUG("ERROR: xc_gnttab_munmap failed errno=%d\n", errno);
terminate_mount_request(mount);
}
/* We can advance the request consumer index, from here on, the request
* should not be used (it may be overrinden by a response) */
mount->ring.req_cons++;
/* Get a response from the ring */
rsp_idx = mount->ring.rsp_prod_pvt++;
FS_DEBUG("Writing response at: idx=%d, id=%d\n", rsp_idx, req_id);
rsp = RING_GET_RESPONSE(&mount->ring, rsp_idx);
rsp->id = req_id;
rsp->u.ret_val = (uint64_t)ret;
}
static void dispatch_rename(struct fs_mount *mount, struct fsif_request *req)
{
char *buf, *old_file_name, *new_file_name;
int ret;
RING_IDX rsp_idx;
fsif_response_t *rsp;
uint16_t req_id;
FS_DEBUG("Dispatching rename operation (gref=%d).\n", req->u.fremove.gref);
/* Read the request, and open file */
buf = xc_gnttab_map_grant_ref(mount->gnth,
mount->dom_id,
req->u.frename.gref,
PROT_READ);
req_id = req->id;
old_file_name = buf + req->u.frename.old_name_offset;
new_file_name = buf + req->u.frename.new_name_offset;
FS_DEBUG("File rename issued for %s -> %s (buf=%s)\n",
old_file_name, new_file_name, buf);
if (check_export_path(mount->export->export_path, old_file_name) < 0 ||
check_export_path(mount->export->export_path, new_file_name) < 0) {
FS_DEBUG("Filename check failed\n");
ret = -1;
} else {
ret = rename(old_file_name, new_file_name);
}
FS_DEBUG("Got ret: %d\n", ret);
if (xc_gnttab_munmap(mount->gnth, buf, 1) != 0) {
FS_DEBUG("ERROR: xc_gnttab_munmap failed errno=%d\n", errno);
terminate_mount_request(mount);
}
/* We can advance the request consumer index, from here on, the request
* should not be used (it may be overrinden by a response) */
mount->ring.req_cons++;
/* Get a response from the ring */
rsp_idx = mount->ring.rsp_prod_pvt++;
FS_DEBUG("Writing response at: idx=%d, id=%d\n", rsp_idx, req_id);
rsp = RING_GET_RESPONSE(&mount->ring, rsp_idx);
rsp->id = req_id;
rsp->u.ret_val = (uint64_t)ret;
}
static void dispatch_create(struct fs_mount *mount, struct fsif_request *req)
{
char *file_name;
int ret;
int8_t directory;
int32_t mode;
RING_IDX rsp_idx;
fsif_response_t *rsp;
uint16_t req_id;
FS_DEBUG("Dispatching file create operation (gref=%d).\n", req->u.fcreate.gref);
/* Read the request, and create file/directory */
mode = req->u.fcreate.mode;
directory = req->u.fcreate.directory;
file_name = xc_gnttab_map_grant_ref(mount->gnth,
mount->dom_id,
req->u.fcreate.gref,
PROT_READ);
req_id = req->id;
if (check_export_path(mount->export->export_path, file_name) < 0) {
FS_DEBUG("Filename check failed\n");
ret = -1;
goto out;
}
/* We can advance the request consumer index, from here on, the request
* should not be used (it may be overrinden by a response) */
mount->ring.req_cons++;
if(directory)
{
FS_DEBUG("Issuing create for directory: %s\n", file_name);
ret = mkdir(file_name, mode);
}
else
{
FS_DEBUG("Issuing create for file: %s\n", file_name);
ret = get_fd(mount);
if (ret >= 0) {
int real_fd = creat(file_name, mode);
if (real_fd < 0)
ret = -1;
else
{
mount->fds[ret] = real_fd;
FS_DEBUG("Got FD: %d for real %d\n", ret, real_fd);
}
}
}
out:
if (xc_gnttab_munmap(mount->gnth, file_name, 1) != 0) {
FS_DEBUG("ERROR: xc_gnttab_munmap failed errno=%d\n", errno);
terminate_mount_request(mount);
}
FS_DEBUG("Got ret %d (errno=%d)\n", ret, errno);
/* Get a response from the ring */
rsp_idx = mount->ring.rsp_prod_pvt++;
FS_DEBUG("Writing response at: idx=%d, id=%d\n", rsp_idx, req_id);
rsp = RING_GET_RESPONSE(&mount->ring, rsp_idx);
rsp->id = req_id;
rsp->u.ret_val = (uint64_t)ret;
}
static void dispatch_list(struct fs_mount *mount, struct fsif_request *req)
{
char *file_name, *buf;
uint32_t offset = 0, nr_files = 0, error_code = 0;
uint64_t ret_val;
RING_IDX rsp_idx;
fsif_response_t *rsp;
uint16_t req_id;
DIR *dir;
struct dirent *dirent = NULL;
FS_DEBUG("Dispatching list operation (gref=%d).\n", req->u.flist.gref);
/* Read the request, and list directory */
offset = req->u.flist.offset;
buf = file_name = xc_gnttab_map_grant_ref(mount->gnth,
mount->dom_id,
req->u.flist.gref,
PROT_READ | PROT_WRITE);
req_id = req->id;
FS_DEBUG("Dir list issued for %s\n", file_name);
if (check_export_path(mount->export->export_path, file_name) < 0) {
FS_DEBUG("Filename check failed\n");
error_code = 1;
goto error_out;
}
/* We can advance the request consumer index, from here on, the request
* should not be used (it may be overrinden by a response) */
mount->ring.req_cons++;
ret_val = 0;
nr_files = 0;
dir = opendir(file_name);
if(dir == NULL)
{
error_code = errno;
goto error_out;
}
/* Skip offset dirs */
dirent = readdir(dir);
while(offset-- > 0 && dirent != NULL)
dirent = readdir(dir);
/* If there was any error with reading the directory, errno will be set */
error_code = errno;
/* Copy file names of the remaining non-NULL dirents into buf */
if (NAME_MAX >= XC_PAGE_SIZE >> 1)
goto error_out;
while(dirent != NULL &&
(XC_PAGE_SIZE - ((unsigned long)buf & XC_PAGE_MASK) > NAME_MAX))
{
int curr_length = strlen(dirent->d_name) + 1;
memcpy(buf, dirent->d_name, curr_length);
buf += curr_length;
dirent = readdir(dir);
error_code = errno;
nr_files++;
}
error_out:
ret_val = ((nr_files << NR_FILES_SHIFT) & NR_FILES_MASK) |
((error_code << ERROR_SHIFT) & ERROR_MASK) |
(dirent != NULL ? HAS_MORE_FLAG : 0);
if (xc_gnttab_munmap(mount->gnth, file_name, 1) != 0) {
FS_DEBUG("ERROR: xc_gnttab_munmap failed errno=%d\n", errno);
terminate_mount_request(mount);
}
/* Get a response from the ring */
rsp_idx = mount->ring.rsp_prod_pvt++;
FS_DEBUG("Writing response at: idx=%d, id=%d\n", rsp_idx, req_id);
rsp = RING_GET_RESPONSE(&mount->ring, rsp_idx);
rsp->id = req_id;
rsp->u.ret_val = ret_val;
}
static void dispatch_chmod(struct fs_mount *mount, struct fsif_request *req)
{
int fd, ret;
RING_IDX rsp_idx;
fsif_response_t *rsp;
uint16_t req_id;
int32_t mode;
FS_DEBUG("Dispatching file chmod operation (fd=%d, mode=%o).\n",
req->u.fchmod.fd, req->u.fchmod.mode);
req_id = req->id;
if (req->u.fchmod.fd < MAX_FDS)
fd = mount->fds[req->u.fchmod.fd];
else
fd = -1;
mode = req->u.fchmod.mode;
/* We can advance the request consumer index, from here on, the request
* should not be used (it may be overrinden by a response) */
mount->ring.req_cons++;
ret = fchmod(fd, mode);
/* Get a response from the ring */
rsp_idx = mount->ring.rsp_prod_pvt++;
FS_DEBUG("Writing response at: idx=%d, id=%d\n", rsp_idx, req_id);
rsp = RING_GET_RESPONSE(&mount->ring, rsp_idx);
rsp->id = req_id;
rsp->u.ret_val = (uint64_t)ret;
}
static void dispatch_fs_space(struct fs_mount *mount, struct fsif_request *req)
{
char *file_name;
RING_IDX rsp_idx;
fsif_response_t *rsp;
uint16_t req_id;
struct statvfs stat;
int64_t ret;
FS_DEBUG("Dispatching fs space operation (gref=%d).\n", req->u.fspace.gref);
/* Read the request, and open file */
file_name = xc_gnttab_map_grant_ref(mount->gnth,
mount->dom_id,
req->u.fspace.gref,
PROT_READ);
req_id = req->id;
FS_DEBUG("Fs space issued for %s\n", file_name);
if (check_export_path(mount->export->export_path, file_name) < 0) {
FS_DEBUG("Filename check failed\n");
ret = -1;
} else {
ret = statvfs(file_name, &stat);
}
if(ret >= 0)
ret = stat.f_bsize * stat.f_bfree;
if (xc_gnttab_munmap(mount->gnth, file_name, 1) != 0) {
FS_DEBUG("ERROR: xc_gnttab_munmap failed errno=%d\n", errno);
terminate_mount_request(mount);
}
/* We can advance the request consumer index, from here on, the request
* should not be used (it may be overrinden by a response) */
mount->ring.req_cons++;
/* Get a response from the ring */
rsp_idx = mount->ring.rsp_prod_pvt++;
FS_DEBUG("Writing response at: idx=%d, id=%d\n", rsp_idx, req_id);
rsp = RING_GET_RESPONSE(&mount->ring, rsp_idx);
rsp->id = req_id;
rsp->u.ret_val = (uint64_t)ret;
}
static void dispatch_file_sync(struct fs_mount *mount, struct fsif_request *req)
{
int fd;
uint16_t req_id;
unsigned short priv_id;
struct fs_request *priv_req;
req_id = req->id;
if (req->u.fsync.fd < MAX_FDS)
fd = mount->fds[req->u.fsync.fd];
else
fd = -1;
FS_DEBUG("File sync issued for FD=%d\n", req->u.fsync.fd);
priv_id = get_request(mount, req);
FS_DEBUG("Private id is: %d\n", priv_id);
priv_req = &mount->requests[priv_id];
priv_req->id = priv_id;
/* Dispatch AIO read request */
bzero(&priv_req->aiocb, sizeof(struct aiocb));
priv_req->aiocb.aio_fildes = fd;
priv_req->aiocb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
priv_req->aiocb.aio_sigevent.sigev_signo = SIGUSR2;
priv_req->aiocb.aio_sigevent.sigev_value.sival_ptr = priv_req;
if (aio_fsync(O_SYNC, &priv_req->aiocb) < 0) {
FS_DEBUG("ERROR: aio_fsync failed errno=%d\n", errno);
terminate_mount_request(mount);
}
/* We can advance the request consumer index, from here on, the request
* should not be used (it may be overrinden by a response) */
mount->ring.req_cons++;
}
static void end_file_sync(struct fs_mount *mount, struct fs_request *priv_req)
{
RING_IDX rsp_idx;
fsif_response_t *rsp;
uint16_t req_id;
/* Get a response from the ring */
rsp_idx = mount->ring.rsp_prod_pvt++;
req_id = priv_req->req_shadow.id;
FS_DEBUG("Writing response at: idx=%d, id=%d\n", rsp_idx, req_id);
rsp = RING_GET_RESPONSE(&mount->ring, rsp_idx);
rsp->id = req_id;
rsp->u.ret_val = (uint64_t)aio_return(&priv_req->aiocb);
}
struct fs_op fopen_op = {.type = REQ_FILE_OPEN,
.dispatch_handler = dispatch_file_open,
.response_handler = NULL};
struct fs_op fclose_op = {.type = REQ_FILE_CLOSE,
.dispatch_handler = dispatch_file_close,
.response_handler = NULL};
struct fs_op fread_op = {.type = REQ_FILE_READ,
.dispatch_handler = dispatch_file_read,
.response_handler = end_file_read};
struct fs_op fwrite_op = {.type = REQ_FILE_WRITE,
.dispatch_handler = dispatch_file_write,
.response_handler = end_file_write};
struct fs_op fstat_op = {.type = REQ_STAT,
.dispatch_handler = dispatch_stat,
.response_handler = NULL};
struct fs_op ftruncate_op = {.type = REQ_FILE_TRUNCATE,
.dispatch_handler = dispatch_truncate,
.response_handler = NULL};
struct fs_op fremove_op = {.type = REQ_REMOVE,
.dispatch_handler = dispatch_remove,
.response_handler = NULL};
struct fs_op frename_op = {.type = REQ_RENAME,
.dispatch_handler = dispatch_rename,
.response_handler = NULL};
struct fs_op fcreate_op = {.type = REQ_CREATE,
.dispatch_handler = dispatch_create,
.response_handler = NULL};
struct fs_op flist_op = {.type = REQ_DIR_LIST,
.dispatch_handler = dispatch_list,
.response_handler = NULL};
struct fs_op fchmod_op = {.type = REQ_CHMOD,
.dispatch_handler = dispatch_chmod,
.response_handler = NULL};
struct fs_op fspace_op = {.type = REQ_FS_SPACE,
.dispatch_handler = dispatch_fs_space,
.response_handler = NULL};
struct fs_op fsync_op = {.type = REQ_FILE_SYNC,
.dispatch_handler = dispatch_file_sync,
.response_handler = end_file_sync};
struct fs_op *fsops[] = {&fopen_op,
&fclose_op,
&fread_op,
&fwrite_op,
&fstat_op,
&ftruncate_op,
&fremove_op,
&frename_op,
&fcreate_op,
&flist_op,
&fchmod_op,
&fspace_op,
&fsync_op,
NULL};