blob: a1c9beddd2e78c193a88d20c5ce3f72dc724e839 [file] [log] [blame]
M. Mohan Kumar10925bf2011-12-14 13:49:06 +05301/*
Wei Liu2209bd02015-11-30 16:14:29 +00002 * 9p backend
M. Mohan Kumar10925bf2011-12-14 13:49:06 +05303 *
4 * Copyright IBM, Corp. 2010
5 *
6 * Authors:
7 * Anthony Liguori <aliguori@us.ibm.com>
8 *
9 * This work is licensed under the terms of the GNU GPL, version 2. See
10 * the COPYING file in the top-level directory.
11 *
12 */
13
Peter Maydellfbc04122016-01-26 18:17:10 +000014#include "qemu/osdep.h"
M. Mohan Kumar10925bf2011-12-14 13:49:06 +053015#include <glib/gprintf.h>
M. Mohan Kumar10925bf2011-12-14 13:49:06 +053016#include <utime.h>
M. Mohan Kumar10925bf2011-12-14 13:49:06 +053017
Wei Liu2209bd02015-11-30 16:14:29 +000018#include "9p-iov-marshal.h"
Paolo Bonzini1de7afc2012-12-17 18:20:00 +010019#include "qemu/bswap.h"
M. Mohan Kumar10925bf2011-12-14 13:49:06 +053020
M. Mohan Kumarddca7f82011-12-14 13:49:13 +053021static ssize_t v9fs_packunpack(void *addr, struct iovec *sg, int sg_count,
22 size_t offset, size_t size, int pack)
M. Mohan Kumar10925bf2011-12-14 13:49:06 +053023{
24 int i = 0;
25 size_t copied = 0;
M. Mohan Kumarddca7f82011-12-14 13:49:13 +053026 size_t req_size = size;
27
M. Mohan Kumar10925bf2011-12-14 13:49:06 +053028
29 for (i = 0; size && i < sg_count; i++) {
30 size_t len;
31 if (offset >= sg[i].iov_len) {
32 /* skip this sg */
33 offset -= sg[i].iov_len;
34 continue;
35 } else {
36 len = MIN(sg[i].iov_len - offset, size);
37 if (pack) {
38 memcpy(sg[i].iov_base + offset, addr, len);
39 } else {
40 memcpy(addr, sg[i].iov_base + offset, len);
41 }
42 size -= len;
43 copied += len;
44 addr += len;
45 if (size) {
46 offset = 0;
47 continue;
48 }
49 }
50 }
M. Mohan Kumarddca7f82011-12-14 13:49:13 +053051 if (copied < req_size) {
52 /*
53 * We copied less that requested size. error out
54 */
55 return -ENOBUFS;
56 }
M. Mohan Kumar10925bf2011-12-14 13:49:06 +053057 return copied;
58}
59
M. Mohan Kumarddca7f82011-12-14 13:49:13 +053060static ssize_t v9fs_unpack(void *dst, struct iovec *out_sg, int out_num,
61 size_t offset, size_t size)
M. Mohan Kumar10925bf2011-12-14 13:49:06 +053062{
63 return v9fs_packunpack(dst, out_sg, out_num, offset, size, 0);
64}
65
M. Mohan Kumarddca7f82011-12-14 13:49:13 +053066ssize_t v9fs_pack(struct iovec *in_sg, int in_num, size_t offset,
67 const void *src, size_t size)
M. Mohan Kumar10925bf2011-12-14 13:49:06 +053068{
69 return v9fs_packunpack((void *)src, in_sg, in_num, offset, size, 1);
70}
71
Wei Liu0e2082d2015-12-02 14:22:04 +000072ssize_t v9fs_iov_vunmarshal(struct iovec *out_sg, int out_num, size_t offset,
73 int bswap, const char *fmt, va_list ap)
M. Mohan Kumar10925bf2011-12-14 13:49:06 +053074{
75 int i;
M. Mohan Kumarddca7f82011-12-14 13:49:13 +053076 ssize_t copied = 0;
M. Mohan Kumar10925bf2011-12-14 13:49:06 +053077 size_t old_offset = offset;
78
M. Mohan Kumar10925bf2011-12-14 13:49:06 +053079 for (i = 0; fmt[i]; i++) {
80 switch (fmt[i]) {
81 case 'b': {
82 uint8_t *valp = va_arg(ap, uint8_t *);
M. Mohan Kumarddca7f82011-12-14 13:49:13 +053083 copied = v9fs_unpack(valp, out_sg, out_num, offset, sizeof(*valp));
M. Mohan Kumar10925bf2011-12-14 13:49:06 +053084 break;
85 }
86 case 'w': {
87 uint16_t val, *valp;
88 valp = va_arg(ap, uint16_t *);
M. Mohan Kumarddca7f82011-12-14 13:49:13 +053089 copied = v9fs_unpack(&val, out_sg, out_num, offset, sizeof(val));
M. Mohan Kumar10925bf2011-12-14 13:49:06 +053090 if (bswap) {
91 *valp = le16_to_cpu(val);
92 } else {
93 *valp = val;
94 }
95 break;
96 }
97 case 'd': {
98 uint32_t val, *valp;
99 valp = va_arg(ap, uint32_t *);
M. Mohan Kumarddca7f82011-12-14 13:49:13 +0530100 copied = v9fs_unpack(&val, out_sg, out_num, offset, sizeof(val));
M. Mohan Kumar10925bf2011-12-14 13:49:06 +0530101 if (bswap) {
102 *valp = le32_to_cpu(val);
103 } else {
104 *valp = val;
105 }
106 break;
107 }
108 case 'q': {
109 uint64_t val, *valp;
110 valp = va_arg(ap, uint64_t *);
M. Mohan Kumarddca7f82011-12-14 13:49:13 +0530111 copied = v9fs_unpack(&val, out_sg, out_num, offset, sizeof(val));
M. Mohan Kumar10925bf2011-12-14 13:49:06 +0530112 if (bswap) {
113 *valp = le64_to_cpu(val);
114 } else {
115 *valp = val;
116 }
117 break;
118 }
119 case 's': {
120 V9fsString *str = va_arg(ap, V9fsString *);
Wei Liu2209bd02015-11-30 16:14:29 +0000121 copied = v9fs_iov_unmarshal(out_sg, out_num, offset, bswap,
122 "w", &str->size);
M. Mohan Kumarddca7f82011-12-14 13:49:13 +0530123 if (copied > 0) {
124 offset += copied;
125 str->data = g_malloc(str->size + 1);
126 copied = v9fs_unpack(str->data, out_sg, out_num, offset,
127 str->size);
Li Qiangba42ebb2016-10-17 14:13:58 +0200128 if (copied >= 0) {
M. Mohan Kumarddca7f82011-12-14 13:49:13 +0530129 str->data[str->size] = 0;
130 } else {
131 v9fs_string_free(str);
132 }
133 }
M. Mohan Kumar10925bf2011-12-14 13:49:06 +0530134 break;
135 }
136 case 'Q': {
137 V9fsQID *qidp = va_arg(ap, V9fsQID *);
Wei Liu2209bd02015-11-30 16:14:29 +0000138 copied = v9fs_iov_unmarshal(out_sg, out_num, offset, bswap,
139 "bdq", &qidp->type, &qidp->version,
140 &qidp->path);
M. Mohan Kumar10925bf2011-12-14 13:49:06 +0530141 break;
142 }
143 case 'S': {
144 V9fsStat *statp = va_arg(ap, V9fsStat *);
Wei Liu2209bd02015-11-30 16:14:29 +0000145 copied = v9fs_iov_unmarshal(out_sg, out_num, offset, bswap,
146 "wwdQdddqsssssddd",
147 &statp->size, &statp->type,
148 &statp->dev, &statp->qid,
149 &statp->mode, &statp->atime,
150 &statp->mtime, &statp->length,
151 &statp->name, &statp->uid,
152 &statp->gid, &statp->muid,
153 &statp->extension,
154 &statp->n_uid, &statp->n_gid,
155 &statp->n_muid);
M. Mohan Kumar10925bf2011-12-14 13:49:06 +0530156 break;
157 }
158 case 'I': {
159 V9fsIattr *iattr = va_arg(ap, V9fsIattr *);
Wei Liu2209bd02015-11-30 16:14:29 +0000160 copied = v9fs_iov_unmarshal(out_sg, out_num, offset, bswap,
161 "ddddqqqqq",
162 &iattr->valid, &iattr->mode,
163 &iattr->uid, &iattr->gid,
164 &iattr->size, &iattr->atime_sec,
165 &iattr->atime_nsec,
166 &iattr->mtime_sec,
167 &iattr->mtime_nsec);
M. Mohan Kumar10925bf2011-12-14 13:49:06 +0530168 break;
169 }
170 default:
Greg Kurz57a0aa62017-05-25 10:30:13 +0200171 g_assert_not_reached();
M. Mohan Kumar10925bf2011-12-14 13:49:06 +0530172 }
M. Mohan Kumarddca7f82011-12-14 13:49:13 +0530173 if (copied < 0) {
M. Mohan Kumarddca7f82011-12-14 13:49:13 +0530174 return copied;
175 }
176 offset += copied;
M. Mohan Kumar10925bf2011-12-14 13:49:06 +0530177 }
M. Mohan Kumar10925bf2011-12-14 13:49:06 +0530178
179 return offset - old_offset;
180}
181
Wei Liu0e2082d2015-12-02 14:22:04 +0000182ssize_t v9fs_iov_unmarshal(struct iovec *out_sg, int out_num, size_t offset,
183 int bswap, const char *fmt, ...)
184{
185 ssize_t ret;
186 va_list ap;
187
188 va_start(ap, fmt);
189 ret = v9fs_iov_vunmarshal(out_sg, out_num, offset, bswap, fmt, ap);
190 va_end(ap);
191
192 return ret;
193}
194
195ssize_t v9fs_iov_vmarshal(struct iovec *in_sg, int in_num, size_t offset,
196 int bswap, const char *fmt, va_list ap)
M. Mohan Kumar10925bf2011-12-14 13:49:06 +0530197{
198 int i;
M. Mohan Kumarddca7f82011-12-14 13:49:13 +0530199 ssize_t copied = 0;
M. Mohan Kumar10925bf2011-12-14 13:49:06 +0530200 size_t old_offset = offset;
201
M. Mohan Kumar10925bf2011-12-14 13:49:06 +0530202 for (i = 0; fmt[i]; i++) {
203 switch (fmt[i]) {
204 case 'b': {
205 uint8_t val = va_arg(ap, int);
M. Mohan Kumarddca7f82011-12-14 13:49:13 +0530206 copied = v9fs_pack(in_sg, in_num, offset, &val, sizeof(val));
M. Mohan Kumar10925bf2011-12-14 13:49:06 +0530207 break;
208 }
209 case 'w': {
Peter Maydellb4426422016-07-07 17:20:56 +0100210 uint16_t val = va_arg(ap, int);
M. Mohan Kumar10925bf2011-12-14 13:49:06 +0530211 if (bswap) {
Peter Maydellb4426422016-07-07 17:20:56 +0100212 val = cpu_to_le16(val);
M. Mohan Kumar10925bf2011-12-14 13:49:06 +0530213 }
M. Mohan Kumarddca7f82011-12-14 13:49:13 +0530214 copied = v9fs_pack(in_sg, in_num, offset, &val, sizeof(val));
M. Mohan Kumar10925bf2011-12-14 13:49:06 +0530215 break;
216 }
217 case 'd': {
Peter Maydellb4426422016-07-07 17:20:56 +0100218 uint32_t val = va_arg(ap, uint32_t);
M. Mohan Kumar10925bf2011-12-14 13:49:06 +0530219 if (bswap) {
Peter Maydellb4426422016-07-07 17:20:56 +0100220 val = cpu_to_le32(val);
M. Mohan Kumar10925bf2011-12-14 13:49:06 +0530221 }
M. Mohan Kumarddca7f82011-12-14 13:49:13 +0530222 copied = v9fs_pack(in_sg, in_num, offset, &val, sizeof(val));
M. Mohan Kumar10925bf2011-12-14 13:49:06 +0530223 break;
224 }
225 case 'q': {
Peter Maydellb4426422016-07-07 17:20:56 +0100226 uint64_t val = va_arg(ap, uint64_t);
M. Mohan Kumar10925bf2011-12-14 13:49:06 +0530227 if (bswap) {
Peter Maydellb4426422016-07-07 17:20:56 +0100228 val = cpu_to_le64(val);
M. Mohan Kumar10925bf2011-12-14 13:49:06 +0530229 }
M. Mohan Kumarddca7f82011-12-14 13:49:13 +0530230 copied = v9fs_pack(in_sg, in_num, offset, &val, sizeof(val));
M. Mohan Kumar10925bf2011-12-14 13:49:06 +0530231 break;
232 }
233 case 's': {
234 V9fsString *str = va_arg(ap, V9fsString *);
Wei Liu2209bd02015-11-30 16:14:29 +0000235 copied = v9fs_iov_marshal(in_sg, in_num, offset, bswap,
236 "w", str->size);
M. Mohan Kumarddca7f82011-12-14 13:49:13 +0530237 if (copied > 0) {
238 offset += copied;
239 copied = v9fs_pack(in_sg, in_num, offset, str->data, str->size);
240 }
M. Mohan Kumar10925bf2011-12-14 13:49:06 +0530241 break;
242 }
243 case 'Q': {
244 V9fsQID *qidp = va_arg(ap, V9fsQID *);
Wei Liu2209bd02015-11-30 16:14:29 +0000245 copied = v9fs_iov_marshal(in_sg, in_num, offset, bswap, "bdq",
246 qidp->type, qidp->version,
247 qidp->path);
M. Mohan Kumar10925bf2011-12-14 13:49:06 +0530248 break;
249 }
250 case 'S': {
251 V9fsStat *statp = va_arg(ap, V9fsStat *);
Wei Liu2209bd02015-11-30 16:14:29 +0000252 copied = v9fs_iov_marshal(in_sg, in_num, offset, bswap,
253 "wwdQdddqsssssddd",
254 statp->size, statp->type, statp->dev,
255 &statp->qid, statp->mode, statp->atime,
256 statp->mtime, statp->length,
257 &statp->name,
258 &statp->uid, &statp->gid, &statp->muid,
259 &statp->extension, statp->n_uid,
260 statp->n_gid, statp->n_muid);
M. Mohan Kumar10925bf2011-12-14 13:49:06 +0530261 break;
262 }
263 case 'A': {
264 V9fsStatDotl *statp = va_arg(ap, V9fsStatDotl *);
Wei Liu2209bd02015-11-30 16:14:29 +0000265 copied = v9fs_iov_marshal(in_sg, in_num, offset, bswap,
266 "qQdddqqqqqqqqqqqqqqq",
267 statp->st_result_mask,
268 &statp->qid, statp->st_mode,
269 statp->st_uid, statp->st_gid,
270 statp->st_nlink, statp->st_rdev,
271 statp->st_size, statp->st_blksize,
272 statp->st_blocks, statp->st_atime_sec,
273 statp->st_atime_nsec,
274 statp->st_mtime_sec,
275 statp->st_mtime_nsec,
276 statp->st_ctime_sec,
277 statp->st_ctime_nsec,
278 statp->st_btime_sec,
279 statp->st_btime_nsec, statp->st_gen,
280 statp->st_data_version);
M. Mohan Kumar10925bf2011-12-14 13:49:06 +0530281 break;
282 }
283 default:
Greg Kurz57a0aa62017-05-25 10:30:13 +0200284 g_assert_not_reached();
M. Mohan Kumar10925bf2011-12-14 13:49:06 +0530285 }
M. Mohan Kumarddca7f82011-12-14 13:49:13 +0530286 if (copied < 0) {
M. Mohan Kumarddca7f82011-12-14 13:49:13 +0530287 return copied;
288 }
289 offset += copied;
M. Mohan Kumar10925bf2011-12-14 13:49:06 +0530290 }
M. Mohan Kumar10925bf2011-12-14 13:49:06 +0530291
292 return offset - old_offset;
293}
Wei Liu0e2082d2015-12-02 14:22:04 +0000294
295ssize_t v9fs_iov_marshal(struct iovec *in_sg, int in_num, size_t offset,
296 int bswap, const char *fmt, ...)
297{
298 ssize_t ret;
299 va_list ap;
300
301 va_start(ap, fmt);
302 ret = v9fs_iov_vmarshal(in_sg, in_num, offset, bswap, fmt, ap);
303 va_end(ap);
304
305 return ret;
306}