Revision f141eafe posix-aio-compat.c

b/posix-aio-compat.c
20 20
#include <stdlib.h>
21 21
#include <stdio.h>
22 22
#include "osdep.h"
23
#include "qemu-common.h"
23 24

  
24 25
#include "posix-aio-compat.h"
25 26

  
......
76 77
    if (ret) die2(ret, "pthread_create");
77 78
}
78 79

  
79
static size_t handle_aiocb_readwrite(struct qemu_paiocb *aiocb)
80
static size_t handle_aiocb_ioctl(struct qemu_paiocb *aiocb)
81
{
82
	int ret;
83

  
84
	ret = ioctl(aiocb->aio_fildes, aiocb->aio_ioctl_cmd, aiocb->aio_ioctl_buf);
85
	if (ret == -1)
86
		return -errno;
87
	return ret;
88
}
89

  
90
/*
91
 * Check if we need to copy the data in the aiocb into a new
92
 * properly aligned buffer.
93
 */
94
static int aiocb_needs_copy(struct qemu_paiocb *aiocb)
95
{
96
    if (aiocb->aio_flags & QEMU_AIO_SECTOR_ALIGNED) {
97
        int i;
98

  
99
        for (i = 0; i < aiocb->aio_niov; i++)
100
            if ((uintptr_t) aiocb->aio_iov[i].iov_base % 512)
101
                return 1;
102
    }
103

  
104
    return 0;
105
}
106

  
107
static size_t handle_aiocb_rw_linear(struct qemu_paiocb *aiocb, char *buf)
80 108
{
81 109
    size_t offset = 0;
82
    ssize_t len;
110
    size_t len;
83 111

  
84 112
    while (offset < aiocb->aio_nbytes) {
85
        if (aiocb->aio_type == QEMU_PAIO_WRITE)
86
            len = pwrite(aiocb->aio_fildes,
87
                         (const char *)aiocb->aio_buf + offset,
113
         if (aiocb->aio_type == QEMU_PAIO_WRITE)
114
             len = pwrite(aiocb->aio_fildes,
115
                          (const char *)buf + offset,
116
                          aiocb->aio_nbytes - offset,
117
                          aiocb->aio_offset + offset);
118
         else
119
             len = pread(aiocb->aio_fildes,
120
                         buf + offset,
88 121
                         aiocb->aio_nbytes - offset,
89 122
                         aiocb->aio_offset + offset);
90
        else
91
            len = pread(aiocb->aio_fildes,
92
                        (char *)aiocb->aio_buf + offset,
93
                        aiocb->aio_nbytes - offset,
94
                        aiocb->aio_offset + offset);
95

  
96
        if (len == -1 && errno == EINTR)
97
            continue;
98
        else if (len == -1) {
99
            offset = -errno;
100
            break;
101
        } else if (len == 0)
102
            break;
103 123

  
104
        offset += len;
124
         if (len == -1 && errno == EINTR)
125
             continue;
126
         else if (len == -1) {
127
             offset = -errno;
128
             break;
129
         } else if (len == 0)
130
             break;
131

  
132
         offset += len;
105 133
    }
106 134

  
107 135
    return offset;
108 136
}
109 137

  
110
static size_t handle_aiocb_ioctl(struct qemu_paiocb *aiocb)
138
static size_t handle_aiocb_rw(struct qemu_paiocb *aiocb)
111 139
{
112
	int ret;
140
    size_t nbytes;
141
    char *buf;
142

  
143
    if (!aiocb_needs_copy(aiocb) && aiocb->aio_niov == 1) {
144
        /*
145
         * If there is just a single buffer, and it is properly aligned
146
         * we can just use plain pread/pwrite without any problems.
147
         */
148
        return handle_aiocb_rw_linear(aiocb, aiocb->aio_iov->iov_base);
149
    }
113 150

  
114
	ret = ioctl(aiocb->aio_fildes, aiocb->aio_ioctl_cmd, aiocb->aio_buf);
115
	if (ret == -1)
116
		return -errno;
117
	return ret;
151
    /*
152
     * Ok, we have to do it the hard way, copy all segments into
153
     * a single aligned buffer.
154
     */
155
    buf = qemu_memalign(512, aiocb->aio_nbytes);
156
    if (aiocb->aio_type == QEMU_PAIO_WRITE) {
157
        char *p = buf;
158
        int i;
159

  
160
        for (i = 0; i < aiocb->aio_niov; ++i) {
161
            memcpy(p, aiocb->aio_iov[i].iov_base, aiocb->aio_iov[i].iov_len);
162
            p += aiocb->aio_iov[i].iov_len;
163
        }
164
    }
165

  
166
    nbytes = handle_aiocb_rw_linear(aiocb, buf);
167
    if (aiocb->aio_type != QEMU_PAIO_WRITE) {
168
        char *p = buf;
169
        size_t count = aiocb->aio_nbytes, copy;
170
        int i;
171

  
172
        for (i = 0; i < aiocb->aio_niov && count; ++i) {
173
            copy = count;
174
            if (copy > aiocb->aio_iov[i].iov_len)
175
                copy = aiocb->aio_iov[i].iov_len;
176
            memcpy(aiocb->aio_iov[i].iov_base, p, copy);
177
            p     += copy;
178
            count -= copy;
179
        }
180
    }
181
    qemu_vfree(buf);
182

  
183
    return nbytes;
118 184
}
119 185

  
120 186
static void *aio_thread(void *unused)
......
157 223
        switch (aiocb->aio_type) {
158 224
        case QEMU_PAIO_READ:
159 225
        case QEMU_PAIO_WRITE:
160
		ret = handle_aiocb_readwrite(aiocb);
226
		ret = handle_aiocb_rw(aiocb);
161 227
		break;
162 228
        case QEMU_PAIO_IOCTL:
163 229
		ret = handle_aiocb_ioctl(aiocb);

Also available in: Unified diff