blob: 15b3f4d3853d8a81da003a5ad04401322cd34970 [file] [log] [blame]
Anthony Liguori9f107512010-04-29 17:44:44 +05301/*
2 * Virtio 9p backend
3 *
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
Christian Schoenebeck6f569082021-05-06 15:12:23 +020014/*
15 * Not so fast! You might want to read the 9p developer docs first:
16 * https://wiki.qemu.org/Documentation/9p
17 */
18
Peter Maydellfbc04122016-01-26 18:17:10 +000019#include "qemu/osdep.h"
Greg Kurze3e83f22016-09-16 08:56:15 +020020#include <glib/gprintf.h>
Paolo Bonzini0d09e412013-02-05 17:06:20 +010021#include "hw/virtio/virtio.h"
Markus Armbrusterda34e652016-03-14 09:01:28 +010022#include "qapi/error.h"
Markus Armbrusterd49b6832015-03-17 18:29:20 +010023#include "qemu/error-report.h"
Michael S. Tsirkincd4bfbb2015-07-23 20:57:53 +030024#include "qemu/iov.h"
Markus Armbrusterdb725812019-08-12 07:23:50 +020025#include "qemu/main-loop.h"
Paolo Bonzini1de7afc2012-12-17 18:20:00 +010026#include "qemu/sockets.h"
Anthony Liguori9f107512010-04-29 17:44:44 +053027#include "virtio-9p.h"
28#include "fsdev/qemu-fsdev.h"
Wei Liu267ae092015-11-18 18:31:52 +000029#include "9p-xattr.h"
Wei Liufe528402015-11-18 17:57:30 +000030#include "coth.h"
Harsh Prateek Borac572f232011-10-12 19:11:25 +053031#include "trace.h"
Juan Quintela795c40b2017-04-06 12:00:28 +020032#include "migration/blocker.h"
Antonios Motakis1a6ed332019-10-10 11:36:05 +020033#include "qemu/xxhash.h"
Christian Schoenebeck6b6aa822019-10-07 17:02:45 +020034#include <math.h>
Dan Robertson03556ea2020-05-25 10:38:03 +020035#include <linux/limits.h>
Anthony Liguori9f107512010-04-29 17:44:44 +053036
Aneesh Kumar K.V7a462742011-05-18 15:40:57 +053037int open_fd_hw;
38int total_open_fd;
39static int open_fd_rc;
Anthony Liguori9f107512010-04-29 17:44:44 +053040
Venkateswararao Jujjuri (JV)fac4f112010-06-01 13:30:51 -070041enum {
42 Oread = 0x00,
43 Owrite = 0x01,
44 Ordwr = 0x02,
45 Oexec = 0x03,
46 Oexcl = 0x04,
47 Otrunc = 0x10,
48 Orexec = 0x20,
49 Orclose = 0x40,
50 Oappend = 0x80,
51};
52
Christian Schoenebeckcc82fde2021-10-01 16:27:46 +020053P9ARRAY_DEFINE_TYPE(V9fsPath, v9fs_path_free);
54
Greg Kurz75673592018-01-08 11:18:22 +010055static ssize_t pdu_marshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
Wei Liu0e2082d2015-12-02 14:22:04 +000056{
57 ssize_t ret;
58 va_list ap;
59
60 va_start(ap, fmt);
Stefano Stabelliniea834412017-01-03 17:28:44 +010061 ret = pdu->s->transport->pdu_vmarshal(pdu, offset, fmt, ap);
Wei Liu0e2082d2015-12-02 14:22:04 +000062 va_end(ap);
63
64 return ret;
65}
66
Greg Kurz75673592018-01-08 11:18:22 +010067static ssize_t pdu_unmarshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
Wei Liu0e2082d2015-12-02 14:22:04 +000068{
69 ssize_t ret;
70 va_list ap;
71
72 va_start(ap, fmt);
Stefano Stabelliniea834412017-01-03 17:28:44 +010073 ret = pdu->s->transport->pdu_vunmarshal(pdu, offset, fmt, ap);
Wei Liu0e2082d2015-12-02 14:22:04 +000074 va_end(ap);
75
76 return ret;
77}
78
Venkateswararao Jujjuri (JV)fac4f112010-06-01 13:30:51 -070079static int omode_to_uflags(int8_t mode)
80{
81 int ret = 0;
82
83 switch (mode & 3) {
84 case Oread:
85 ret = O_RDONLY;
86 break;
87 case Ordwr:
88 ret = O_RDWR;
89 break;
90 case Owrite:
91 ret = O_WRONLY;
92 break;
93 case Oexec:
94 ret = O_RDONLY;
95 break;
96 }
97
98 if (mode & Otrunc) {
99 ret |= O_TRUNC;
100 }
101
102 if (mode & Oappend) {
103 ret |= O_APPEND;
104 }
105
106 if (mode & Oexcl) {
107 ret |= O_EXCL;
108 }
109
110 return ret;
111}
112
Greg Kurz8e71b962018-01-08 11:18:22 +0100113typedef struct DotlOpenflagMap {
M. Mohan Kumar98440812011-10-12 19:11:24 +0530114 int dotl_flag;
115 int open_flag;
Greg Kurz8e71b962018-01-08 11:18:22 +0100116} DotlOpenflagMap;
M. Mohan Kumar98440812011-10-12 19:11:24 +0530117
118static int dotl_to_open_flags(int flags)
119{
120 int i;
121 /*
122 * We have same bits for P9_DOTL_READONLY, P9_DOTL_WRONLY
123 * and P9_DOTL_NOACCESS
124 */
125 int oflags = flags & O_ACCMODE;
126
Greg Kurz8e71b962018-01-08 11:18:22 +0100127 DotlOpenflagMap dotl_oflag_map[] = {
M. Mohan Kumar98440812011-10-12 19:11:24 +0530128 { P9_DOTL_CREATE, O_CREAT },
129 { P9_DOTL_EXCL, O_EXCL },
130 { P9_DOTL_NOCTTY , O_NOCTTY },
131 { P9_DOTL_TRUNC, O_TRUNC },
132 { P9_DOTL_APPEND, O_APPEND },
133 { P9_DOTL_NONBLOCK, O_NONBLOCK } ,
134 { P9_DOTL_DSYNC, O_DSYNC },
135 { P9_DOTL_FASYNC, FASYNC },
136 { P9_DOTL_DIRECT, O_DIRECT },
137 { P9_DOTL_LARGEFILE, O_LARGEFILE },
138 { P9_DOTL_DIRECTORY, O_DIRECTORY },
139 { P9_DOTL_NOFOLLOW, O_NOFOLLOW },
140 { P9_DOTL_NOATIME, O_NOATIME },
141 { P9_DOTL_SYNC, O_SYNC },
142 };
143
144 for (i = 0; i < ARRAY_SIZE(dotl_oflag_map); i++) {
145 if (flags & dotl_oflag_map[i].dotl_flag) {
146 oflags |= dotl_oflag_map[i].open_flag;
147 }
148 }
149
150 return oflags;
151}
152
Venkateswararao Jujjuri (JV)758e8e32010-06-14 13:34:41 -0700153void cred_init(FsCred *credp)
154{
155 credp->fc_uid = -1;
156 credp->fc_gid = -1;
157 credp->fc_mode = -1;
158 credp->fc_rdev = -1;
159}
160
Aneesh Kumar K.Vd3ab98e2011-10-12 19:11:23 +0530161static int get_dotl_openflags(V9fsState *s, int oflags)
162{
163 int flags;
164 /*
165 * Filter the client open flags
166 */
M. Mohan Kumar98440812011-10-12 19:11:24 +0530167 flags = dotl_to_open_flags(oflags);
168 flags &= ~(O_NOCTTY | O_ASYNC | O_CREAT);
Aneesh Kumar K.Vd3ab98e2011-10-12 19:11:23 +0530169 /*
170 * Ignore direct disk access hint until the server supports it.
171 */
172 flags &= ~O_DIRECT;
173 return flags;
174}
175
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +0530176void v9fs_path_init(V9fsPath *path)
177{
178 path->data = NULL;
179 path->size = 0;
180}
181
182void v9fs_path_free(V9fsPath *path)
183{
184 g_free(path->data);
185 path->data = NULL;
186 path->size = 0;
187}
188
Greg Kurze3e83f22016-09-16 08:56:15 +0200189
190void GCC_FMT_ATTR(2, 3)
191v9fs_path_sprintf(V9fsPath *path, const char *fmt, ...)
192{
193 va_list ap;
194
195 v9fs_path_free(path);
196
197 va_start(ap, fmt);
198 /* Bump the size for including terminating NULL */
199 path->size = g_vasprintf(&path->data, fmt, ap) + 1;
200 va_end(ap);
201}
202
Marc-André Lureaue446a1e2018-02-19 18:27:15 +0100203void v9fs_path_copy(V9fsPath *dst, const V9fsPath *src)
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +0530204{
Marc-André Lureaue446a1e2018-02-19 18:27:15 +0100205 v9fs_path_free(dst);
206 dst->size = src->size;
207 dst->data = g_memdup(src->data, src->size);
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +0530208}
209
210int v9fs_name_to_path(V9fsState *s, V9fsPath *dirpath,
211 const char *name, V9fsPath *path)
212{
213 int err;
214 err = s->ops->name_to_path(&s->ctx, dirpath, name, path);
215 if (err < 0) {
216 err = -errno;
217 }
218 return err;
219}
220
Malahal Naineni936532a2011-06-01 12:35:11 +0530221/*
222 * Return TRUE if s1 is an ancestor of s2.
223 *
224 * E.g. "a/b" is an ancestor of "a/b/c" but not of "a/bc/d".
225 * As a special case, We treat s1 as ancestor of s2 if they are same!
226 */
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +0530227static int v9fs_path_is_ancestor(V9fsPath *s1, V9fsPath *s2)
Malahal Naineni936532a2011-06-01 12:35:11 +0530228{
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +0530229 if (!strncmp(s1->data, s2->data, s1->size - 1)) {
230 if (s2->data[s1->size - 1] == '\0' || s2->data[s1->size - 1] == '/') {
Malahal Naineni936532a2011-06-01 12:35:11 +0530231 return 1;
232 }
233 }
234 return 0;
235}
236
Anthony Liguoria03f7872010-04-29 17:44:46 +0530237static size_t v9fs_string_size(V9fsString *str)
238{
239 return str->size;
240}
241
Aneesh Kumar K.Vb9cb88b2011-08-02 11:36:24 +0530242/*
243 * returns 0 if fid got re-opened, 1 if not, < 0 on error */
Greg Kurz8440e222016-10-17 14:13:58 +0200244static int coroutine_fn v9fs_reopen_fid(V9fsPDU *pdu, V9fsFidState *f)
Aneesh Kumar K.Vb9cb88b2011-08-02 11:36:24 +0530245{
246 int err = 1;
247 if (f->fid_type == P9_FID_FILE) {
248 if (f->fs.fd == -1) {
249 do {
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +0530250 err = v9fs_co_open(pdu, f, f->open_flags);
251 } while (err == -EINTR && !pdu->cancelled);
Aneesh Kumar K.Vb9cb88b2011-08-02 11:36:24 +0530252 }
253 } else if (f->fid_type == P9_FID_DIR) {
Greg Kurzf314ea42016-06-06 11:52:34 +0200254 if (f->fs.dir.stream == NULL) {
Aneesh Kumar K.Vb9cb88b2011-08-02 11:36:24 +0530255 do {
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +0530256 err = v9fs_co_opendir(pdu, f);
257 } while (err == -EINTR && !pdu->cancelled);
Aneesh Kumar K.Vb9cb88b2011-08-02 11:36:24 +0530258 }
259 }
260 return err;
261}
262
Greg Kurz8440e222016-10-17 14:13:58 +0200263static V9fsFidState *coroutine_fn get_fid(V9fsPDU *pdu, int32_t fid)
Anthony Liguori286d5652010-04-29 17:44:48 +0530264{
Aneesh Kumar K.V7a462742011-05-18 15:40:57 +0530265 int err;
Anthony Liguori286d5652010-04-29 17:44:48 +0530266 V9fsFidState *f;
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +0530267 V9fsState *s = pdu->s;
Anthony Liguori286d5652010-04-29 17:44:48 +0530268
Greg Kurzfeabd6c2021-01-18 15:22:59 +0100269 QSIMPLEQ_FOREACH(f, &s->fid_list, next) {
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +0530270 BUG_ON(f->clunked);
Anthony Liguori286d5652010-04-29 17:44:48 +0530271 if (f->fid == fid) {
Aneesh Kumar K.V7a462742011-05-18 15:40:57 +0530272 /*
273 * Update the fid ref upfront so that
274 * we don't get reclaimed when we yield
275 * in open later.
276 */
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +0530277 f->ref++;
Aneesh Kumar K.V7a462742011-05-18 15:40:57 +0530278 /*
279 * check whether we need to reopen the
280 * file. We might have closed the fd
281 * while trying to free up some file
282 * descriptors.
283 */
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +0530284 err = v9fs_reopen_fid(pdu, f);
Aneesh Kumar K.Vb9cb88b2011-08-02 11:36:24 +0530285 if (err < 0) {
286 f->ref--;
287 return NULL;
288 }
Aneesh Kumar K.V7a462742011-05-18 15:40:57 +0530289 /*
290 * Mark the fid as referenced so that the LRU
291 * reclaim won't close the file descriptor
292 */
293 f->flags |= FID_REFERENCED;
Anthony Liguori286d5652010-04-29 17:44:48 +0530294 return f;
295 }
296 }
Anthony Liguori286d5652010-04-29 17:44:48 +0530297 return NULL;
298}
299
300static V9fsFidState *alloc_fid(V9fsState *s, int32_t fid)
301{
302 V9fsFidState *f;
303
Greg Kurzfeabd6c2021-01-18 15:22:59 +0100304 QSIMPLEQ_FOREACH(f, &s->fid_list, next) {
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +0530305 /* If fid is already there return NULL */
306 BUG_ON(f->clunked);
307 if (f->fid == fid) {
308 return NULL;
309 }
Anthony Liguori286d5652010-04-29 17:44:48 +0530310 }
Anthony Liguori7267c092011-08-20 22:09:37 -0500311 f = g_malloc0(sizeof(V9fsFidState));
Anthony Liguori286d5652010-04-29 17:44:48 +0530312 f->fid = fid;
Aneesh Kumar K.Vd62dbb52010-09-02 11:09:06 +0530313 f->fid_type = P9_FID_NONE;
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +0530314 f->ref = 1;
Aneesh Kumar K.V7a462742011-05-18 15:40:57 +0530315 /*
316 * Mark the fid as referenced so that the LRU
317 * reclaim won't close the file descriptor
318 */
319 f->flags |= FID_REFERENCED;
Greg Kurz20b7f452021-01-21 19:15:10 +0100320 QSIMPLEQ_INSERT_TAIL(&s->fid_list, f, next);
Anthony Liguori286d5652010-04-29 17:44:48 +0530321
Christian Schoenebeckd2c5cf72020-07-29 10:39:12 +0200322 v9fs_readdir_init(s->proto_version, &f->fs.dir);
323 v9fs_readdir_init(s->proto_version, &f->fs_reclaim.dir);
Greg Kurz7cde47d2016-06-06 11:52:34 +0200324
Anthony Liguori286d5652010-04-29 17:44:48 +0530325 return f;
326}
327
Greg Kurz8440e222016-10-17 14:13:58 +0200328static int coroutine_fn v9fs_xattr_fid_clunk(V9fsPDU *pdu, V9fsFidState *fidp)
Aneesh Kumar K.V10b468b2010-09-02 11:09:07 +0530329{
330 int retval = 0;
331
Li Qiangdd28fbb2016-11-01 12:00:40 +0100332 if (fidp->fs.xattr.xattrwalk_fid) {
Aneesh Kumar K.V10b468b2010-09-02 11:09:07 +0530333 /* getxattr/listxattr fid */
334 goto free_value;
335 }
336 /*
337 * if this is fid for setxattr. clunk should
338 * result in setxattr localcall
339 */
340 if (fidp->fs.xattr.len != fidp->fs.xattr.copied_len) {
341 /* clunk after partial write */
342 retval = -EINVAL;
343 goto free_out;
344 }
Aneesh Kumar K.V9ed3ef22010-08-26 11:15:23 +0530345 if (fidp->fs.xattr.len) {
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +0530346 retval = v9fs_co_lsetxattr(pdu, &fidp->path, &fidp->fs.xattr.name,
Aneesh Kumar K.V9ed3ef22010-08-26 11:15:23 +0530347 fidp->fs.xattr.value,
348 fidp->fs.xattr.len,
349 fidp->fs.xattr.flags);
350 } else {
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +0530351 retval = v9fs_co_lremovexattr(pdu, &fidp->path, &fidp->fs.xattr.name);
Aneesh Kumar K.V9ed3ef22010-08-26 11:15:23 +0530352 }
Aneesh Kumar K.V10b468b2010-09-02 11:09:07 +0530353free_out:
354 v9fs_string_free(&fidp->fs.xattr.name);
355free_value:
Markus Armbruster9e288402014-06-06 18:43:29 +0200356 g_free(fidp->fs.xattr.value);
Aneesh Kumar K.V10b468b2010-09-02 11:09:07 +0530357 return retval;
358}
359
Greg Kurz8440e222016-10-17 14:13:58 +0200360static int coroutine_fn free_fid(V9fsPDU *pdu, V9fsFidState *fidp)
Anthony Liguori286d5652010-04-29 17:44:48 +0530361{
Aneesh Kumar K.V10b468b2010-09-02 11:09:07 +0530362 int retval = 0;
Anthony Liguori286d5652010-04-29 17:44:48 +0530363
Aneesh Kumar K.Vd62dbb52010-09-02 11:09:06 +0530364 if (fidp->fid_type == P9_FID_FILE) {
Aneesh Kumar K.V7a462742011-05-18 15:40:57 +0530365 /* If we reclaimed the fd no need to close */
366 if (fidp->fs.fd != -1) {
Aneesh Kumar K.Vcc720dd2011-10-25 12:10:40 +0530367 retval = v9fs_co_close(pdu, &fidp->fs);
Aneesh Kumar K.V7a462742011-05-18 15:40:57 +0530368 }
Aneesh Kumar K.Vd62dbb52010-09-02 11:09:06 +0530369 } else if (fidp->fid_type == P9_FID_DIR) {
Greg Kurzf314ea42016-06-06 11:52:34 +0200370 if (fidp->fs.dir.stream != NULL) {
Aneesh Kumar K.Vcc720dd2011-10-25 12:10:40 +0530371 retval = v9fs_co_closedir(pdu, &fidp->fs);
Aneesh Kumar K.V95f65512011-05-18 17:08:34 +0530372 }
Aneesh Kumar K.Vd62dbb52010-09-02 11:09:06 +0530373 } else if (fidp->fid_type == P9_FID_XATTR) {
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +0530374 retval = v9fs_xattr_fid_clunk(pdu, fidp);
Anthony Liguori286d5652010-04-29 17:44:48 +0530375 }
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +0530376 v9fs_path_free(&fidp->path);
Anthony Liguori7267c092011-08-20 22:09:37 -0500377 g_free(fidp);
Aneesh Kumar K.V10b468b2010-09-02 11:09:07 +0530378 return retval;
Anthony Liguori286d5652010-04-29 17:44:48 +0530379}
380
Greg Kurz8440e222016-10-17 14:13:58 +0200381static int coroutine_fn put_fid(V9fsPDU *pdu, V9fsFidState *fidp)
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +0530382{
383 BUG_ON(!fidp->ref);
384 fidp->ref--;
Aneesh Kumar K.V7a462742011-05-18 15:40:57 +0530385 /*
386 * Don't free the fid if it is in reclaim list
387 */
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +0530388 if (!fidp->ref && fidp->clunked) {
Aneesh Kumar K.Ve9a01522011-12-04 22:35:28 +0530389 if (fidp->fid == pdu->s->root_fid) {
390 /*
391 * if the clunked fid is root fid then we
392 * have unmounted the fs on the client side.
393 * delete the migration blocker. Ideally, this
394 * should be hooked to transport close notification
395 */
396 if (pdu->s->migration_blocker) {
397 migrate_del_blocker(pdu->s->migration_blocker);
398 error_free(pdu->s->migration_blocker);
399 pdu->s->migration_blocker = NULL;
400 }
401 }
Aneesh Kumar K.Va911a182013-02-05 11:27:46 +0530402 return free_fid(pdu, fidp);
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +0530403 }
Aneesh Kumar K.Va911a182013-02-05 11:27:46 +0530404 return 0;
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +0530405}
406
Aneesh Kumar K.Vce421a12011-08-02 11:36:24 +0530407static V9fsFidState *clunk_fid(V9fsState *s, int32_t fid)
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +0530408{
Greg Kurzfeabd6c2021-01-18 15:22:59 +0100409 V9fsFidState *fidp;
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +0530410
Greg Kurzfeabd6c2021-01-18 15:22:59 +0100411 QSIMPLEQ_FOREACH(fidp, &s->fid_list, next) {
412 if (fidp->fid == fid) {
413 QSIMPLEQ_REMOVE(&s->fid_list, fidp, V9fsFidState, next);
414 fidp->clunked = true;
415 return fidp;
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +0530416 }
417 }
Greg Kurzfeabd6c2021-01-18 15:22:59 +0100418 return NULL;
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +0530419}
420
Greg Kurz8440e222016-10-17 14:13:58 +0200421void coroutine_fn v9fs_reclaim_fd(V9fsPDU *pdu)
Aneesh Kumar K.V7a462742011-05-18 15:40:57 +0530422{
423 int reclaim_count = 0;
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +0530424 V9fsState *s = pdu->s;
Greg Kurz81f97662021-01-22 15:35:14 +0100425 V9fsFidState *f;
426 QSLIST_HEAD(, V9fsFidState) reclaim_list =
427 QSLIST_HEAD_INITIALIZER(reclaim_list);
Aneesh Kumar K.V7a462742011-05-18 15:40:57 +0530428
Greg Kurzfeabd6c2021-01-18 15:22:59 +0100429 QSIMPLEQ_FOREACH(f, &s->fid_list, next) {
Aneesh Kumar K.V7a462742011-05-18 15:40:57 +0530430 /*
431 * Unlink fids cannot be reclaimed. Check
432 * for them and skip them. Also skip fids
433 * currently being operated on.
434 */
435 if (f->ref || f->flags & FID_NON_RECLAIMABLE) {
436 continue;
437 }
438 /*
439 * if it is a recently referenced fid
440 * we leave the fid untouched and clear the
441 * reference bit. We come back to it later
442 * in the next iteration. (a simple LRU without
443 * moving list elements around)
444 */
445 if (f->flags & FID_REFERENCED) {
446 f->flags &= ~FID_REFERENCED;
447 continue;
448 }
449 /*
450 * Add fids to reclaim list.
451 */
452 if (f->fid_type == P9_FID_FILE) {
453 if (f->fs.fd != -1) {
454 /*
455 * Up the reference count so that
456 * a clunk request won't free this fid
457 */
458 f->ref++;
Greg Kurz81f97662021-01-22 15:35:14 +0100459 QSLIST_INSERT_HEAD(&reclaim_list, f, reclaim_next);
Aneesh Kumar K.V7a462742011-05-18 15:40:57 +0530460 f->fs_reclaim.fd = f->fs.fd;
461 f->fs.fd = -1;
462 reclaim_count++;
463 }
Aneesh Kumar K.V95f65512011-05-18 17:08:34 +0530464 } else if (f->fid_type == P9_FID_DIR) {
Greg Kurzf314ea42016-06-06 11:52:34 +0200465 if (f->fs.dir.stream != NULL) {
Aneesh Kumar K.V95f65512011-05-18 17:08:34 +0530466 /*
467 * Up the reference count so that
468 * a clunk request won't free this fid
469 */
470 f->ref++;
Greg Kurz81f97662021-01-22 15:35:14 +0100471 QSLIST_INSERT_HEAD(&reclaim_list, f, reclaim_next);
Greg Kurzf314ea42016-06-06 11:52:34 +0200472 f->fs_reclaim.dir.stream = f->fs.dir.stream;
473 f->fs.dir.stream = NULL;
Aneesh Kumar K.V95f65512011-05-18 17:08:34 +0530474 reclaim_count++;
475 }
Aneesh Kumar K.V7a462742011-05-18 15:40:57 +0530476 }
477 if (reclaim_count >= open_fd_rc) {
478 break;
479 }
480 }
481 /*
482 * Now close the fid in reclaim list. Free them if they
483 * are already clunked.
484 */
Greg Kurz81f97662021-01-22 15:35:14 +0100485 while (!QSLIST_EMPTY(&reclaim_list)) {
486 f = QSLIST_FIRST(&reclaim_list);
487 QSLIST_REMOVE(&reclaim_list, f, V9fsFidState, reclaim_next);
Aneesh Kumar K.V7a462742011-05-18 15:40:57 +0530488 if (f->fid_type == P9_FID_FILE) {
Aneesh Kumar K.Vcc720dd2011-10-25 12:10:40 +0530489 v9fs_co_close(pdu, &f->fs_reclaim);
Aneesh Kumar K.V95f65512011-05-18 17:08:34 +0530490 } else if (f->fid_type == P9_FID_DIR) {
Aneesh Kumar K.Vcc720dd2011-10-25 12:10:40 +0530491 v9fs_co_closedir(pdu, &f->fs_reclaim);
Aneesh Kumar K.V7a462742011-05-18 15:40:57 +0530492 }
Aneesh Kumar K.V7a462742011-05-18 15:40:57 +0530493 /*
494 * Now drop the fid reference, free it
495 * if clunked.
496 */
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +0530497 put_fid(pdu, f);
Aneesh Kumar K.V7a462742011-05-18 15:40:57 +0530498 }
499}
500
Greg Kurz8440e222016-10-17 14:13:58 +0200501static int coroutine_fn v9fs_mark_fids_unreclaim(V9fsPDU *pdu, V9fsPath *path)
Aneesh Kumar K.V7a462742011-05-18 15:40:57 +0530502{
503 int err;
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +0530504 V9fsState *s = pdu->s;
Greg Kurz20b7f452021-01-21 19:15:10 +0100505 V9fsFidState *fidp, *fidp_next;
Aneesh Kumar K.V7a462742011-05-18 15:40:57 +0530506
Greg Kurz20b7f452021-01-21 19:15:10 +0100507 fidp = QSIMPLEQ_FIRST(&s->fid_list);
508 if (!fidp) {
509 return 0;
510 }
511
512 /*
513 * v9fs_reopen_fid() can yield : a reference on the fid must be held
514 * to ensure its pointer remains valid and we can safely pass it to
515 * QSIMPLEQ_NEXT(). The corresponding put_fid() can also yield so
516 * we must keep a reference on the next fid as well. So the logic here
517 * is to get a reference on a fid and only put it back during the next
518 * iteration after we could get a reference on the next fid. Start with
519 * the first one.
520 */
521 for (fidp->ref++; fidp; fidp = fidp_next) {
522 if (fidp->path.size == path->size &&
523 !memcmp(fidp->path.data, path->data, path->size)) {
Aneesh Kumar K.V7a462742011-05-18 15:40:57 +0530524 /* Mark the fid non reclaimable. */
525 fidp->flags |= FID_NON_RECLAIMABLE;
Aneesh Kumar K.Vb9cb88b2011-08-02 11:36:24 +0530526
527 /* reopen the file/dir if already closed */
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +0530528 err = v9fs_reopen_fid(pdu, fidp);
Aneesh Kumar K.Vb9cb88b2011-08-02 11:36:24 +0530529 if (err < 0) {
Greg Kurz20b7f452021-01-21 19:15:10 +0100530 put_fid(pdu, fidp);
Greg Kurz267fcad2017-11-06 18:05:35 +0100531 return err;
Aneesh Kumar K.Vb9cb88b2011-08-02 11:36:24 +0530532 }
Aneesh Kumar K.V7a462742011-05-18 15:40:57 +0530533 }
Greg Kurz20b7f452021-01-21 19:15:10 +0100534
535 fidp_next = QSIMPLEQ_NEXT(fidp, next);
536
537 if (fidp_next) {
538 /*
539 * Ensure the next fid survives a potential clunk request during
540 * put_fid() below and v9fs_reopen_fid() in the next iteration.
541 */
542 fidp_next->ref++;
543 }
544
545 /* We're done with this fid */
546 put_fid(pdu, fidp);
Aneesh Kumar K.V7a462742011-05-18 15:40:57 +0530547 }
Greg Kurz20b7f452021-01-21 19:15:10 +0100548
Aneesh Kumar K.V7a462742011-05-18 15:40:57 +0530549 return 0;
550}
551
Greg Kurz8440e222016-10-17 14:13:58 +0200552static void coroutine_fn virtfs_reset(V9fsPDU *pdu)
Deepak C Shettyb41e2992011-12-04 22:35:28 +0530553{
554 V9fsState *s = pdu->s;
Greg Kurz79decce2016-11-01 12:00:40 +0100555 V9fsFidState *fidp;
Deepak C Shettyb41e2992011-12-04 22:35:28 +0530556
557 /* Free all fids */
Greg Kurzfeabd6c2021-01-18 15:22:59 +0100558 while (!QSIMPLEQ_EMPTY(&s->fid_list)) {
Greg Kurz6d54af02017-04-04 18:06:01 +0200559 /* Get fid */
Greg Kurzfeabd6c2021-01-18 15:22:59 +0100560 fidp = QSIMPLEQ_FIRST(&s->fid_list);
Greg Kurz6d54af02017-04-04 18:06:01 +0200561 fidp->ref++;
Deepak C Shettyb41e2992011-12-04 22:35:28 +0530562
Greg Kurz6d54af02017-04-04 18:06:01 +0200563 /* Clunk fid */
Greg Kurzfeabd6c2021-01-18 15:22:59 +0100564 QSIMPLEQ_REMOVE(&s->fid_list, fidp, V9fsFidState, next);
Greg Kurz2e531602021-01-18 15:22:58 +0100565 fidp->clunked = true;
Greg Kurz6d54af02017-04-04 18:06:01 +0200566
567 put_fid(pdu, fidp);
Deepak C Shettyb41e2992011-12-04 22:35:28 +0530568 }
Deepak C Shettyb41e2992011-12-04 22:35:28 +0530569}
570
Anthony Liguori286d5652010-04-29 17:44:48 +0530571#define P9_QID_TYPE_DIR 0x80
572#define P9_QID_TYPE_SYMLINK 0x02
573
574#define P9_STAT_MODE_DIR 0x80000000
575#define P9_STAT_MODE_APPEND 0x40000000
576#define P9_STAT_MODE_EXCL 0x20000000
577#define P9_STAT_MODE_MOUNT 0x10000000
578#define P9_STAT_MODE_AUTH 0x08000000
579#define P9_STAT_MODE_TMP 0x04000000
580#define P9_STAT_MODE_SYMLINK 0x02000000
581#define P9_STAT_MODE_LINK 0x01000000
582#define P9_STAT_MODE_DEVICE 0x00800000
583#define P9_STAT_MODE_NAMED_PIPE 0x00200000
584#define P9_STAT_MODE_SOCKET 0x00100000
585#define P9_STAT_MODE_SETUID 0x00080000
586#define P9_STAT_MODE_SETGID 0x00040000
587#define P9_STAT_MODE_SETVTX 0x00010000
588
589#define P9_STAT_MODE_TYPE_BITS (P9_STAT_MODE_DIR | \
590 P9_STAT_MODE_SYMLINK | \
591 P9_STAT_MODE_LINK | \
592 P9_STAT_MODE_DEVICE | \
593 P9_STAT_MODE_NAMED_PIPE | \
594 P9_STAT_MODE_SOCKET)
595
Christian Schoenebeck6b6aa822019-10-07 17:02:45 +0200596/* Mirrors all bits of a byte. So e.g. binary 10100000 would become 00000101. */
597static inline uint8_t mirror8bit(uint8_t byte)
598{
599 return (byte * 0x0202020202ULL & 0x010884422010ULL) % 1023;
600}
601
602/* Same as mirror8bit() just for a 64 bit data type instead for a byte. */
603static inline uint64_t mirror64bit(uint64_t value)
604{
605 return ((uint64_t)mirror8bit(value & 0xff) << 56) |
606 ((uint64_t)mirror8bit((value >> 8) & 0xff) << 48) |
607 ((uint64_t)mirror8bit((value >> 16) & 0xff) << 40) |
608 ((uint64_t)mirror8bit((value >> 24) & 0xff) << 32) |
609 ((uint64_t)mirror8bit((value >> 32) & 0xff) << 24) |
610 ((uint64_t)mirror8bit((value >> 40) & 0xff) << 16) |
611 ((uint64_t)mirror8bit((value >> 48) & 0xff) << 8) |
612 ((uint64_t)mirror8bit((value >> 56) & 0xff));
613}
614
615/**
616 * @brief Parameter k for the Exponential Golomb algorihm to be used.
617 *
618 * The smaller this value, the smaller the minimum bit count for the Exp.
619 * Golomb generated affixes will be (at lowest index) however for the
620 * price of having higher maximum bit count of generated affixes (at highest
621 * index). Likewise increasing this parameter yields in smaller maximum bit
622 * count for the price of having higher minimum bit count.
623 *
624 * In practice that means: a good value for k depends on the expected amount
625 * of devices to be exposed by one export. For a small amount of devices k
626 * should be small, for a large amount of devices k might be increased
627 * instead. The default of k=0 should be fine for most users though.
628 *
629 * @b IMPORTANT: In case this ever becomes a runtime parameter; the value of
630 * k should not change as long as guest is still running! Because that would
631 * cause completely different inode numbers to be generated on guest.
632 */
633#define EXP_GOLOMB_K 0
634
635/**
636 * @brief Exponential Golomb algorithm for arbitrary k (including k=0).
637 *
638 * The Exponential Golomb algorithm generates @b prefixes (@b not suffixes!)
639 * with growing length and with the mathematical property of being
640 * "prefix-free". The latter means the generated prefixes can be prepended
641 * in front of arbitrary numbers and the resulting concatenated numbers are
642 * guaranteed to be always unique.
643 *
644 * This is a minor adjustment to the original Exp. Golomb algorithm in the
645 * sense that lowest allowed index (@param n) starts with 1, not with zero.
646 *
647 * @param n - natural number (or index) of the prefix to be generated
648 * (1, 2, 3, ...)
649 * @param k - parameter k of Exp. Golomb algorithm to be used
650 * (see comment on EXP_GOLOMB_K macro for details about k)
651 */
652static VariLenAffix expGolombEncode(uint64_t n, int k)
653{
654 const uint64_t value = n + (1 << k) - 1;
655 const int bits = (int) log2(value) + 1;
656 return (VariLenAffix) {
657 .type = AffixType_Prefix,
658 .value = value,
659 .bits = bits + MAX((bits - 1 - k), 0)
660 };
661}
662
663/**
664 * @brief Converts a suffix into a prefix, or a prefix into a suffix.
665 *
666 * Simply mirror all bits of the affix value, for the purpose to preserve
667 * respectively the mathematical "prefix-free" or "suffix-free" property
668 * after the conversion.
669 *
670 * If a passed prefix is suitable to create unique numbers, then the
671 * returned suffix is suitable to create unique numbers as well (and vice
672 * versa).
673 */
674static VariLenAffix invertAffix(const VariLenAffix *affix)
675{
676 return (VariLenAffix) {
677 .type =
678 (affix->type == AffixType_Suffix) ?
679 AffixType_Prefix : AffixType_Suffix,
680 .value =
681 mirror64bit(affix->value) >>
682 ((sizeof(affix->value) * 8) - affix->bits),
683 .bits = affix->bits
684 };
685}
686
687/**
688 * @brief Generates suffix numbers with "suffix-free" property.
689 *
690 * This is just a wrapper function on top of the Exp. Golomb algorithm.
691 *
692 * Since the Exp. Golomb algorithm generates prefixes, but we need suffixes,
693 * this function converts the Exp. Golomb prefixes into appropriate suffixes
694 * which are still suitable for generating unique numbers.
695 *
696 * @param n - natural number (or index) of the suffix to be generated
697 * (1, 2, 3, ...)
698 */
699static VariLenAffix affixForIndex(uint64_t index)
700{
701 VariLenAffix prefix;
702 prefix = expGolombEncode(index, EXP_GOLOMB_K);
703 return invertAffix(&prefix); /* convert prefix to suffix */
704}
705
Antonios Motakis1a6ed332019-10-10 11:36:05 +0200706/* creative abuse of tb_hash_func7, which is based on xxhash */
707static uint32_t qpp_hash(QppEntry e)
Anthony Liguori286d5652010-04-29 17:44:48 +0530708{
Antonios Motakis1a6ed332019-10-10 11:36:05 +0200709 return qemu_xxhash7(e.ino_prefix, e.dev, 0, 0, 0);
710}
Anthony Liguori286d5652010-04-29 17:44:48 +0530711
Antonios Motakisf3fe4a22019-10-07 17:02:45 +0200712static uint32_t qpf_hash(QpfEntry e)
713{
714 return qemu_xxhash7(e.ino, e.dev, 0, 0, 0);
715}
716
Christian Schoenebeck6b6aa822019-10-07 17:02:45 +0200717static bool qpd_cmp_func(const void *obj, const void *userp)
718{
719 const QpdEntry *e1 = obj, *e2 = userp;
720 return e1->dev == e2->dev;
721}
722
723static bool qpp_cmp_func(const void *obj, const void *userp)
Antonios Motakis1a6ed332019-10-10 11:36:05 +0200724{
725 const QppEntry *e1 = obj, *e2 = userp;
726 return e1->dev == e2->dev && e1->ino_prefix == e2->ino_prefix;
727}
728
Christian Schoenebeck6b6aa822019-10-07 17:02:45 +0200729static bool qpf_cmp_func(const void *obj, const void *userp)
Antonios Motakisf3fe4a22019-10-07 17:02:45 +0200730{
731 const QpfEntry *e1 = obj, *e2 = userp;
732 return e1->dev == e2->dev && e1->ino == e2->ino;
733}
734
735static void qp_table_remove(void *p, uint32_t h, void *up)
Antonios Motakis1a6ed332019-10-10 11:36:05 +0200736{
737 g_free(p);
738}
739
Antonios Motakisf3fe4a22019-10-07 17:02:45 +0200740static void qp_table_destroy(struct qht *ht)
Antonios Motakis1a6ed332019-10-10 11:36:05 +0200741{
742 if (!ht || !ht->map) {
743 return;
744 }
Antonios Motakisf3fe4a22019-10-07 17:02:45 +0200745 qht_iter(ht, qp_table_remove, NULL);
Antonios Motakis1a6ed332019-10-10 11:36:05 +0200746 qht_destroy(ht);
747}
748
Christian Schoenebeck6b6aa822019-10-07 17:02:45 +0200749static void qpd_table_init(struct qht *ht)
750{
751 qht_init(ht, qpd_cmp_func, 1, QHT_MODE_AUTO_RESIZE);
752}
753
Antonios Motakis1a6ed332019-10-10 11:36:05 +0200754static void qpp_table_init(struct qht *ht)
755{
Christian Schoenebeck6b6aa822019-10-07 17:02:45 +0200756 qht_init(ht, qpp_cmp_func, 1, QHT_MODE_AUTO_RESIZE);
Antonios Motakis1a6ed332019-10-10 11:36:05 +0200757}
758
Antonios Motakisf3fe4a22019-10-07 17:02:45 +0200759static void qpf_table_init(struct qht *ht)
760{
Christian Schoenebeck6b6aa822019-10-07 17:02:45 +0200761 qht_init(ht, qpf_cmp_func, 1 << 16, QHT_MODE_AUTO_RESIZE);
Antonios Motakisf3fe4a22019-10-07 17:02:45 +0200762}
763
Christian Schoenebeck6b6aa822019-10-07 17:02:45 +0200764/*
765 * Returns how many (high end) bits of inode numbers of the passed fs
766 * device shall be used (in combination with the device number) to
767 * generate hash values for qpp_table entries.
768 *
769 * This function is required if variable length suffixes are used for inode
770 * number mapping on guest level. Since a device may end up having multiple
771 * entries in qpp_table, each entry most probably with a different suffix
772 * length, we thus need this function in conjunction with qpd_table to
773 * "agree" about a fix amount of bits (per device) to be always used for
774 * generating hash values for the purpose of accessing qpp_table in order
775 * get consistent behaviour when accessing qpp_table.
776 */
777static int qid_inode_prefix_hash_bits(V9fsPDU *pdu, dev_t dev)
778{
779 QpdEntry lookup = {
780 .dev = dev
781 }, *val;
782 uint32_t hash = dev;
783 VariLenAffix affix;
784
785 val = qht_lookup(&pdu->s->qpd_table, &lookup, hash);
786 if (!val) {
787 val = g_malloc0(sizeof(QpdEntry));
788 *val = lookup;
789 affix = affixForIndex(pdu->s->qp_affix_next);
790 val->prefix_bits = affix.bits;
791 qht_insert(&pdu->s->qpd_table, val, hash, NULL);
792 pdu->s->qp_ndevices++;
793 }
794 return val->prefix_bits;
795}
796
797/**
798 * @brief Slow / full mapping host inode nr -> guest inode nr.
799 *
800 * This function performs a slower and much more costly remapping of an
801 * original file inode number on host to an appropriate different inode
802 * number on guest. For every (dev, inode) combination on host a new
803 * sequential number is generated, cached and exposed as inode number on
804 * guest.
805 *
806 * This is just a "last resort" fallback solution if the much faster/cheaper
807 * qid_path_suffixmap() failed. In practice this slow / full mapping is not
808 * expected ever to be used at all though.
809 *
810 * @see qid_path_suffixmap() for details
811 *
812 */
Antonios Motakisf3fe4a22019-10-07 17:02:45 +0200813static int qid_path_fullmap(V9fsPDU *pdu, const struct stat *stbuf,
814 uint64_t *path)
815{
816 QpfEntry lookup = {
817 .dev = stbuf->st_dev,
818 .ino = stbuf->st_ino
819 }, *val;
820 uint32_t hash = qpf_hash(lookup);
Christian Schoenebeck6b6aa822019-10-07 17:02:45 +0200821 VariLenAffix affix;
Antonios Motakisf3fe4a22019-10-07 17:02:45 +0200822
823 val = qht_lookup(&pdu->s->qpf_table, &lookup, hash);
824
825 if (!val) {
826 if (pdu->s->qp_fullpath_next == 0) {
827 /* no more files can be mapped :'( */
828 error_report_once(
829 "9p: No more prefixes available for remapping inodes from "
830 "host to guest."
831 );
832 return -ENFILE;
833 }
834
835 val = g_malloc0(sizeof(QppEntry));
836 *val = lookup;
837
838 /* new unique inode and device combo */
Christian Schoenebeck6b6aa822019-10-07 17:02:45 +0200839 affix = affixForIndex(
840 1ULL << (sizeof(pdu->s->qp_affix_next) * 8)
841 );
842 val->path = (pdu->s->qp_fullpath_next++ << affix.bits) | affix.value;
843 pdu->s->qp_fullpath_next &= ((1ULL << (64 - affix.bits)) - 1);
Antonios Motakisf3fe4a22019-10-07 17:02:45 +0200844 qht_insert(&pdu->s->qpf_table, val, hash, NULL);
845 }
846
847 *path = val->path;
848 return 0;
849}
850
Christian Schoenebeck6b6aa822019-10-07 17:02:45 +0200851/**
852 * @brief Quick mapping host inode nr -> guest inode nr.
Antonios Motakis1a6ed332019-10-10 11:36:05 +0200853 *
Christian Schoenebeck6b6aa822019-10-07 17:02:45 +0200854 * This function performs quick remapping of an original file inode number
855 * on host to an appropriate different inode number on guest. This remapping
856 * of inodes is required to avoid inode nr collisions on guest which would
857 * happen if the 9p export contains more than 1 exported file system (or
858 * more than 1 file system data set), because unlike on host level where the
859 * files would have different device nrs, all files exported by 9p would
860 * share the same device nr on guest (the device nr of the virtual 9p device
861 * that is).
862 *
863 * Inode remapping is performed by chopping off high end bits of the original
864 * inode number from host, shifting the result upwards and then assigning a
865 * generated suffix number for the low end bits, where the same suffix number
866 * will be shared by all inodes with the same device id AND the same high end
867 * bits that have been chopped off. That approach utilizes the fact that inode
868 * numbers very likely share the same high end bits (i.e. due to their common
869 * sequential generation by file systems) and hence we only have to generate
870 * and track a very limited amount of suffixes in practice due to that.
871 *
872 * We generate variable size suffixes for that purpose. The 1st generated
873 * suffix will only have 1 bit and hence we only need to chop off 1 bit from
874 * the original inode number. The subsequent suffixes being generated will
875 * grow in (bit) size subsequently, i.e. the 2nd and 3rd suffix being
876 * generated will have 3 bits and hence we have to chop off 3 bits from their
877 * original inodes, and so on. That approach of using variable length suffixes
878 * (i.e. over fixed size ones) utilizes the fact that in practice only a very
879 * limited amount of devices are shared by the same export (e.g. typically
880 * less than 2 dozen devices per 9p export), so in practice we need to chop
881 * off less bits than with fixed size prefixes and yet are flexible to add
882 * new devices at runtime below host's export directory at any time without
883 * having to reboot guest nor requiring to reconfigure guest for that. And due
884 * to the very limited amount of original high end bits that we chop off that
885 * way, the total amount of suffixes we need to generate is less than by using
886 * fixed size prefixes and hence it also improves performance of the inode
887 * remapping algorithm, and finally has the nice side effect that the inode
888 * numbers on guest will be much smaller & human friendly. ;-)
Antonios Motakis1a6ed332019-10-10 11:36:05 +0200889 */
Christian Schoenebeck6b6aa822019-10-07 17:02:45 +0200890static int qid_path_suffixmap(V9fsPDU *pdu, const struct stat *stbuf,
Antonios Motakis1a6ed332019-10-10 11:36:05 +0200891 uint64_t *path)
892{
Christian Schoenebeck6b6aa822019-10-07 17:02:45 +0200893 const int ino_hash_bits = qid_inode_prefix_hash_bits(pdu, stbuf->st_dev);
Antonios Motakis1a6ed332019-10-10 11:36:05 +0200894 QppEntry lookup = {
895 .dev = stbuf->st_dev,
Christian Schoenebeck6b6aa822019-10-07 17:02:45 +0200896 .ino_prefix = (uint16_t) (stbuf->st_ino >> (64 - ino_hash_bits))
Antonios Motakis1a6ed332019-10-10 11:36:05 +0200897 }, *val;
898 uint32_t hash = qpp_hash(lookup);
899
900 val = qht_lookup(&pdu->s->qpp_table, &lookup, hash);
901
902 if (!val) {
Christian Schoenebeck6b6aa822019-10-07 17:02:45 +0200903 if (pdu->s->qp_affix_next == 0) {
904 /* we ran out of affixes */
Antonios Motakisf3fe4a22019-10-07 17:02:45 +0200905 warn_report_once(
906 "9p: Potential degraded performance of inode remapping"
Antonios Motakis1a6ed332019-10-10 11:36:05 +0200907 );
908 return -ENFILE;
909 }
910
911 val = g_malloc0(sizeof(QppEntry));
912 *val = lookup;
913
Christian Schoenebeck6b6aa822019-10-07 17:02:45 +0200914 /* new unique inode affix and device combo */
915 val->qp_affix_index = pdu->s->qp_affix_next++;
916 val->qp_affix = affixForIndex(val->qp_affix_index);
Antonios Motakis1a6ed332019-10-10 11:36:05 +0200917 qht_insert(&pdu->s->qpp_table, val, hash, NULL);
Antonios Motakis3b5ee9e2019-10-10 11:36:05 +0200918 }
Christian Schoenebeck6b6aa822019-10-07 17:02:45 +0200919 /* assuming generated affix to be suffix type, not prefix */
920 *path = (stbuf->st_ino << val->qp_affix.bits) | val->qp_affix.value;
Antonios Motakis1a6ed332019-10-10 11:36:05 +0200921 return 0;
922}
923
924static int stat_to_qid(V9fsPDU *pdu, const struct stat *stbuf, V9fsQID *qidp)
925{
926 int err;
927 size_t size;
928
929 if (pdu->s->ctx.export_flags & V9FS_REMAP_INODES) {
930 /* map inode+device to qid path (fast path) */
Christian Schoenebeck6b6aa822019-10-07 17:02:45 +0200931 err = qid_path_suffixmap(pdu, stbuf, &qidp->path);
Antonios Motakisf3fe4a22019-10-07 17:02:45 +0200932 if (err == -ENFILE) {
933 /* fast path didn't work, fall back to full map */
934 err = qid_path_fullmap(pdu, stbuf, &qidp->path);
935 }
Antonios Motakis1a6ed332019-10-10 11:36:05 +0200936 if (err) {
937 return err;
938 }
939 } else {
940 if (pdu->s->dev_id != stbuf->st_dev) {
941 if (pdu->s->ctx.export_flags & V9FS_FORBID_MULTIDEVS) {
942 error_report_once(
943 "9p: Multiple devices detected in same VirtFS export. "
944 "Access of guest to additional devices is (partly) "
945 "denied due to virtfs option 'multidevs=forbid' being "
946 "effective."
947 );
948 return -ENODEV;
949 } else {
950 warn_report_once(
951 "9p: Multiple devices detected in same VirtFS export, "
952 "which might lead to file ID collisions and severe "
953 "misbehaviours on guest! You should either use a "
954 "separate export for each device shared from host or "
955 "use virtfs option 'multidevs=remap'!"
956 );
957 }
958 }
959 memset(&qidp->path, 0, sizeof(qidp->path));
960 size = MIN(sizeof(stbuf->st_ino), sizeof(qidp->path));
961 memcpy(&qidp->path, &stbuf->st_ino, size);
962 }
963
Anthony Liguori286d5652010-04-29 17:44:48 +0530964 qidp->version = stbuf->st_mtime ^ (stbuf->st_size << 8);
965 qidp->type = 0;
966 if (S_ISDIR(stbuf->st_mode)) {
967 qidp->type |= P9_QID_TYPE_DIR;
968 }
969 if (S_ISLNK(stbuf->st_mode)) {
970 qidp->type |= P9_QID_TYPE_SYMLINK;
971 }
Antonios Motakis3b5ee9e2019-10-10 11:36:05 +0200972
973 return 0;
Anthony Liguori286d5652010-04-29 17:44:48 +0530974}
975
Wei Liu4b311c52016-01-07 18:35:12 +0000976V9fsPDU *pdu_alloc(V9fsState *s)
Anthony Liguori9f107512010-04-29 17:44:44 +0530977{
978 V9fsPDU *pdu = NULL;
979
980 if (!QLIST_EMPTY(&s->free_list)) {
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +0530981 pdu = QLIST_FIRST(&s->free_list);
982 QLIST_REMOVE(pdu, next);
983 QLIST_INSERT_HEAD(&s->active_list, pdu, next);
Anthony Liguori9f107512010-04-29 17:44:44 +0530984 }
985 return pdu;
986}
987
Wei Liu4b311c52016-01-07 18:35:12 +0000988void pdu_free(V9fsPDU *pdu)
Anthony Liguori9f107512010-04-29 17:44:44 +0530989{
Greg Kurz6868a422016-10-17 14:13:58 +0200990 V9fsState *s = pdu->s;
Greg Kurzf74e27b2016-10-17 14:13:58 +0200991
992 g_assert(!pdu->cancelled);
993 QLIST_REMOVE(pdu, next);
994 QLIST_INSERT_HEAD(&s->free_list, pdu, next);
Anthony Liguori9f107512010-04-29 17:44:44 +0530995}
996
Greg Kurz8440e222016-10-17 14:13:58 +0200997static void coroutine_fn pdu_complete(V9fsPDU *pdu, ssize_t len)
Anthony Liguori405a5492010-04-29 17:44:45 +0530998{
999 int8_t id = pdu->id + 1; /* Response */
Wei Liuad38ce92015-12-02 12:06:28 +00001000 V9fsState *s = pdu->s;
Greg Kurz06a37db2017-06-29 15:11:51 +02001001 int ret;
Anthony Liguori405a5492010-04-29 17:44:45 +05301002
Keno Fischerfc78d5e2018-02-01 21:21:27 +01001003 /*
1004 * The 9p spec requires that successfully cancelled pdus receive no reply.
1005 * Sending a reply would confuse clients because they would
1006 * assume that any EINTR is the actual result of the operation,
1007 * rather than a consequence of the cancellation. However, if
1008 * the operation completed (succesfully or with an error other
1009 * than caused be cancellation), we do send out that reply, both
1010 * for efficiency and to avoid confusing the rest of the state machine
1011 * that assumes passing a non-error here will mean a successful
1012 * transmission of the reply.
1013 */
1014 bool discard = pdu->cancelled && len == -EINTR;
1015 if (discard) {
1016 trace_v9fs_rcancel(pdu->tag, pdu->id);
1017 pdu->size = 0;
1018 goto out_notify;
1019 }
1020
Anthony Liguori405a5492010-04-29 17:44:45 +05301021 if (len < 0) {
Anthony Liguori405a5492010-04-29 17:44:45 +05301022 int err = -len;
Anthony Liguori405a5492010-04-29 17:44:45 +05301023 len = 7;
Arun R Bharadwaj8f4d1ca2010-07-28 14:10:22 +05301024
1025 if (s->proto_version != V9FS_PROTO_2000L) {
1026 V9fsString str;
1027
1028 str.data = strerror(err);
1029 str.size = strlen(str.data);
1030
Greg Kurz06a37db2017-06-29 15:11:51 +02001031 ret = pdu_marshal(pdu, len, "s", &str);
1032 if (ret < 0) {
1033 goto out_notify;
1034 }
1035 len += ret;
Arun R Bharadwaj8f4d1ca2010-07-28 14:10:22 +05301036 id = P9_RERROR;
1037 }
1038
Greg Kurz06a37db2017-06-29 15:11:51 +02001039 ret = pdu_marshal(pdu, len, "d", err);
1040 if (ret < 0) {
1041 goto out_notify;
1042 }
1043 len += ret;
Anthony Liguori405a5492010-04-29 17:44:45 +05301044
Arun R Bharadwaj8f4d1ca2010-07-28 14:10:22 +05301045 if (s->proto_version == V9FS_PROTO_2000L) {
1046 id = P9_RLERROR;
1047 }
Aneesh Kumar K.V7999f7e2011-10-24 15:09:49 +05301048 trace_v9fs_rerror(pdu->tag, pdu->id, err); /* Trace ERROR */
Anthony Liguori405a5492010-04-29 17:44:45 +05301049 }
1050
1051 /* fill out the header */
Greg Kurz06a37db2017-06-29 15:11:51 +02001052 if (pdu_marshal(pdu, 0, "dbw", (int32_t)len, id, pdu->tag) < 0) {
1053 goto out_notify;
1054 }
Anthony Liguori405a5492010-04-29 17:44:45 +05301055
1056 /* keep these in sync */
1057 pdu->size = len;
1058 pdu->id = id;
1059
Greg Kurz06a37db2017-06-29 15:11:51 +02001060out_notify:
Greg Kurza17d8652017-05-25 10:30:13 +02001061 pdu->s->transport->push_and_notify(pdu);
Anthony Liguori405a5492010-04-29 17:44:45 +05301062
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05301063 /* Now wakeup anybody waiting in flush for this request */
Greg Kurzf74e27b2016-10-17 14:13:58 +02001064 if (!qemu_co_queue_next(&pdu->complete)) {
1065 pdu_free(pdu);
1066 }
Anthony Liguori405a5492010-04-29 17:44:45 +05301067}
1068
Anthony Liguoribb9e3212010-04-29 17:44:49 +05301069static mode_t v9mode_to_mode(uint32_t mode, V9fsString *extension)
1070{
1071 mode_t ret;
1072
1073 ret = mode & 0777;
1074 if (mode & P9_STAT_MODE_DIR) {
1075 ret |= S_IFDIR;
1076 }
1077
Arun R Bharadwajcf03eb22010-07-28 13:55:05 +05301078 if (mode & P9_STAT_MODE_SYMLINK) {
1079 ret |= S_IFLNK;
1080 }
1081 if (mode & P9_STAT_MODE_SOCKET) {
1082 ret |= S_IFSOCK;
1083 }
1084 if (mode & P9_STAT_MODE_NAMED_PIPE) {
1085 ret |= S_IFIFO;
1086 }
1087 if (mode & P9_STAT_MODE_DEVICE) {
Aneesh Kumar K.Vc7e587b2013-05-20 11:29:52 +05301088 if (extension->size && extension->data[0] == 'c') {
Arun R Bharadwajcf03eb22010-07-28 13:55:05 +05301089 ret |= S_IFCHR;
1090 } else {
1091 ret |= S_IFBLK;
Anthony Liguoribb9e3212010-04-29 17:44:49 +05301092 }
1093 }
1094
Xinhao Zhang01011732020-10-30 12:35:13 +08001095 if (!(ret & ~0777)) {
Anthony Liguoribb9e3212010-04-29 17:44:49 +05301096 ret |= S_IFREG;
1097 }
1098
1099 if (mode & P9_STAT_MODE_SETUID) {
1100 ret |= S_ISUID;
1101 }
1102 if (mode & P9_STAT_MODE_SETGID) {
1103 ret |= S_ISGID;
1104 }
1105 if (mode & P9_STAT_MODE_SETVTX) {
1106 ret |= S_ISVTX;
1107 }
1108
1109 return ret;
1110}
1111
1112static int donttouch_stat(V9fsStat *stat)
1113{
1114 if (stat->type == -1 &&
1115 stat->dev == -1 &&
Antonios Motakis87032832019-10-10 11:36:04 +02001116 stat->qid.type == 0xff &&
1117 stat->qid.version == (uint32_t) -1 &&
1118 stat->qid.path == (uint64_t) -1 &&
Anthony Liguoribb9e3212010-04-29 17:44:49 +05301119 stat->mode == -1 &&
1120 stat->atime == -1 &&
1121 stat->mtime == -1 &&
1122 stat->length == -1 &&
1123 !stat->name.size &&
1124 !stat->uid.size &&
1125 !stat->gid.size &&
1126 !stat->muid.size &&
1127 stat->n_uid == -1 &&
1128 stat->n_gid == -1 &&
1129 stat->n_muid == -1) {
1130 return 1;
1131 }
1132
1133 return 0;
1134}
1135
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05301136static void v9fs_stat_init(V9fsStat *stat)
1137{
1138 v9fs_string_init(&stat->name);
1139 v9fs_string_init(&stat->uid);
1140 v9fs_string_init(&stat->gid);
1141 v9fs_string_init(&stat->muid);
1142 v9fs_string_init(&stat->extension);
1143}
1144
Anthony Liguoribb9e3212010-04-29 17:44:49 +05301145static void v9fs_stat_free(V9fsStat *stat)
1146{
1147 v9fs_string_free(&stat->name);
1148 v9fs_string_free(&stat->uid);
1149 v9fs_string_free(&stat->gid);
1150 v9fs_string_free(&stat->muid);
1151 v9fs_string_free(&stat->extension);
1152}
1153
1154static uint32_t stat_to_v9mode(const struct stat *stbuf)
1155{
1156 uint32_t mode;
1157
1158 mode = stbuf->st_mode & 0777;
1159 if (S_ISDIR(stbuf->st_mode)) {
1160 mode |= P9_STAT_MODE_DIR;
1161 }
1162
Arun R Bharadwajcf03eb22010-07-28 13:55:05 +05301163 if (S_ISLNK(stbuf->st_mode)) {
1164 mode |= P9_STAT_MODE_SYMLINK;
1165 }
Anthony Liguoribb9e3212010-04-29 17:44:49 +05301166
Arun R Bharadwajcf03eb22010-07-28 13:55:05 +05301167 if (S_ISSOCK(stbuf->st_mode)) {
1168 mode |= P9_STAT_MODE_SOCKET;
1169 }
Anthony Liguoribb9e3212010-04-29 17:44:49 +05301170
Arun R Bharadwajcf03eb22010-07-28 13:55:05 +05301171 if (S_ISFIFO(stbuf->st_mode)) {
1172 mode |= P9_STAT_MODE_NAMED_PIPE;
1173 }
Anthony Liguoribb9e3212010-04-29 17:44:49 +05301174
Arun R Bharadwajcf03eb22010-07-28 13:55:05 +05301175 if (S_ISBLK(stbuf->st_mode) || S_ISCHR(stbuf->st_mode)) {
1176 mode |= P9_STAT_MODE_DEVICE;
1177 }
Anthony Liguoribb9e3212010-04-29 17:44:49 +05301178
Arun R Bharadwajcf03eb22010-07-28 13:55:05 +05301179 if (stbuf->st_mode & S_ISUID) {
1180 mode |= P9_STAT_MODE_SETUID;
1181 }
Anthony Liguoribb9e3212010-04-29 17:44:49 +05301182
Arun R Bharadwajcf03eb22010-07-28 13:55:05 +05301183 if (stbuf->st_mode & S_ISGID) {
1184 mode |= P9_STAT_MODE_SETGID;
1185 }
Anthony Liguoribb9e3212010-04-29 17:44:49 +05301186
Arun R Bharadwajcf03eb22010-07-28 13:55:05 +05301187 if (stbuf->st_mode & S_ISVTX) {
1188 mode |= P9_STAT_MODE_SETVTX;
Anthony Liguoribb9e3212010-04-29 17:44:49 +05301189 }
1190
1191 return mode;
1192}
1193
Jan Dakinevich60695372017-09-20 08:48:51 +02001194static int coroutine_fn stat_to_v9stat(V9fsPDU *pdu, V9fsPath *path,
1195 const char *basename,
Greg Kurz8440e222016-10-17 14:13:58 +02001196 const struct stat *stbuf,
1197 V9fsStat *v9stat)
Anthony Liguoribb9e3212010-04-29 17:44:49 +05301198{
1199 int err;
Anthony Liguoribb9e3212010-04-29 17:44:49 +05301200
1201 memset(v9stat, 0, sizeof(*v9stat));
1202
Antonios Motakis3b5ee9e2019-10-10 11:36:05 +02001203 err = stat_to_qid(pdu, stbuf, &v9stat->qid);
1204 if (err < 0) {
1205 return err;
1206 }
Anthony Liguoribb9e3212010-04-29 17:44:49 +05301207 v9stat->mode = stat_to_v9mode(stbuf);
1208 v9stat->atime = stbuf->st_atime;
1209 v9stat->mtime = stbuf->st_mtime;
1210 v9stat->length = stbuf->st_size;
1211
Greg Kurzabdf0082016-09-16 08:56:15 +02001212 v9fs_string_free(&v9stat->uid);
1213 v9fs_string_free(&v9stat->gid);
1214 v9fs_string_free(&v9stat->muid);
Anthony Liguoribb9e3212010-04-29 17:44:49 +05301215
Arun R Bharadwajcf03eb22010-07-28 13:55:05 +05301216 v9stat->n_uid = stbuf->st_uid;
1217 v9stat->n_gid = stbuf->st_gid;
1218 v9stat->n_muid = 0;
Anthony Liguoribb9e3212010-04-29 17:44:49 +05301219
Greg Kurzabdf0082016-09-16 08:56:15 +02001220 v9fs_string_free(&v9stat->extension);
Anthony Liguoribb9e3212010-04-29 17:44:49 +05301221
Arun R Bharadwajcf03eb22010-07-28 13:55:05 +05301222 if (v9stat->mode & P9_STAT_MODE_SYMLINK) {
Jan Dakinevich60695372017-09-20 08:48:51 +02001223 err = v9fs_co_readlink(pdu, path, &v9stat->extension);
Venkateswararao Jujjuri7a5ca312011-08-08 23:36:41 +05301224 if (err < 0) {
Arun R Bharadwajcf03eb22010-07-28 13:55:05 +05301225 return err;
Anthony Liguoribb9e3212010-04-29 17:44:49 +05301226 }
Arun R Bharadwajcf03eb22010-07-28 13:55:05 +05301227 } else if (v9stat->mode & P9_STAT_MODE_DEVICE) {
1228 v9fs_string_sprintf(&v9stat->extension, "%c %u %u",
1229 S_ISCHR(stbuf->st_mode) ? 'c' : 'b',
1230 major(stbuf->st_rdev), minor(stbuf->st_rdev));
1231 } else if (S_ISDIR(stbuf->st_mode) || S_ISREG(stbuf->st_mode)) {
Stefan Weilc9ba47d2010-09-27 18:45:47 +02001232 v9fs_string_sprintf(&v9stat->extension, "%s %lu",
1233 "HARDLINKCOUNT", (unsigned long)stbuf->st_nlink);
Anthony Liguoribb9e3212010-04-29 17:44:49 +05301234 }
1235
Jan Dakinevich60695372017-09-20 08:48:51 +02001236 v9fs_string_sprintf(&v9stat->name, "%s", basename);
Anthony Liguoribb9e3212010-04-29 17:44:49 +05301237
1238 v9stat->size = 61 +
1239 v9fs_string_size(&v9stat->name) +
1240 v9fs_string_size(&v9stat->uid) +
1241 v9fs_string_size(&v9stat->gid) +
1242 v9fs_string_size(&v9stat->muid) +
1243 v9fs_string_size(&v9stat->extension);
1244 return 0;
1245}
1246
Sripathi Kodi00ede4c2010-07-20 11:44:41 +05301247#define P9_STATS_MODE 0x00000001ULL
1248#define P9_STATS_NLINK 0x00000002ULL
1249#define P9_STATS_UID 0x00000004ULL
1250#define P9_STATS_GID 0x00000008ULL
1251#define P9_STATS_RDEV 0x00000010ULL
1252#define P9_STATS_ATIME 0x00000020ULL
1253#define P9_STATS_MTIME 0x00000040ULL
1254#define P9_STATS_CTIME 0x00000080ULL
1255#define P9_STATS_INO 0x00000100ULL
1256#define P9_STATS_SIZE 0x00000200ULL
1257#define P9_STATS_BLOCKS 0x00000400ULL
1258
1259#define P9_STATS_BTIME 0x00000800ULL
1260#define P9_STATS_GEN 0x00001000ULL
1261#define P9_STATS_DATA_VERSION 0x00002000ULL
1262
1263#define P9_STATS_BASIC 0x000007ffULL /* Mask for fields up to BLOCKS */
1264#define P9_STATS_ALL 0x00003fffULL /* Mask for All fields above */
1265
1266
Christian Schoenebeckb565bcc2021-09-27 17:45:00 +02001267/**
1268 * Convert host filesystem's block size into an appropriate block size for
1269 * 9p client (guest OS side). The value returned suggests an "optimum" block
1270 * size for 9p I/O, i.e. to maximize performance.
1271 *
1272 * @pdu: 9p client request
1273 * @blksize: host filesystem's block size
1274 */
1275static int32_t blksize_to_iounit(const V9fsPDU *pdu, int32_t blksize)
Christian Schoenebeck669ced02021-09-22 15:13:31 +02001276{
1277 int32_t iounit = 0;
1278 V9fsState *s = pdu->s;
1279
1280 /*
Christian Schoenebeckb565bcc2021-09-27 17:45:00 +02001281 * iounit should be multiples of blksize (host filesystem block size)
Christian Schoenebeck669ced02021-09-22 15:13:31 +02001282 * as well as less than (client msize - P9_IOHDRSZ)
1283 */
Christian Schoenebeckb565bcc2021-09-27 17:45:00 +02001284 if (blksize) {
Christian Schoenebeck04a7f9e2021-09-27 17:50:36 +02001285 iounit = QEMU_ALIGN_DOWN(s->msize - P9_IOHDRSZ, blksize);
Christian Schoenebeck669ced02021-09-22 15:13:31 +02001286 }
1287 if (!iounit) {
1288 iounit = s->msize - P9_IOHDRSZ;
1289 }
1290 return iounit;
1291}
1292
Christian Schoenebeckb565bcc2021-09-27 17:45:00 +02001293static int32_t stat_to_iounit(const V9fsPDU *pdu, const struct stat *stbuf)
1294{
1295 return blksize_to_iounit(pdu, stbuf->st_blksize);
1296}
1297
Antonios Motakis3b5ee9e2019-10-10 11:36:05 +02001298static int stat_to_v9stat_dotl(V9fsPDU *pdu, const struct stat *stbuf,
Aneesh Kumar K.V8db21ce2011-05-18 16:04:33 -07001299 V9fsStatDotl *v9lstat)
Sripathi Kodi00ede4c2010-07-20 11:44:41 +05301300{
1301 memset(v9lstat, 0, sizeof(*v9lstat));
1302
1303 v9lstat->st_mode = stbuf->st_mode;
1304 v9lstat->st_nlink = stbuf->st_nlink;
1305 v9lstat->st_uid = stbuf->st_uid;
1306 v9lstat->st_gid = stbuf->st_gid;
1307 v9lstat->st_rdev = stbuf->st_rdev;
1308 v9lstat->st_size = stbuf->st_size;
Christian Schoenebeck669ced02021-09-22 15:13:31 +02001309 v9lstat->st_blksize = stat_to_iounit(pdu, stbuf);
Sripathi Kodi00ede4c2010-07-20 11:44:41 +05301310 v9lstat->st_blocks = stbuf->st_blocks;
1311 v9lstat->st_atime_sec = stbuf->st_atime;
1312 v9lstat->st_atime_nsec = stbuf->st_atim.tv_nsec;
1313 v9lstat->st_mtime_sec = stbuf->st_mtime;
1314 v9lstat->st_mtime_nsec = stbuf->st_mtim.tv_nsec;
1315 v9lstat->st_ctime_sec = stbuf->st_ctime;
1316 v9lstat->st_ctime_nsec = stbuf->st_ctim.tv_nsec;
1317 /* Currently we only support BASIC fields in stat */
1318 v9lstat->st_result_mask = P9_STATS_BASIC;
1319
Antonios Motakis3b5ee9e2019-10-10 11:36:05 +02001320 return stat_to_qid(pdu, stbuf, &v9lstat->qid);
Sripathi Kodi00ede4c2010-07-20 11:44:41 +05301321}
1322
Anthony Liguori1f5a89b2010-04-29 17:44:50 +05301323static void print_sg(struct iovec *sg, int cnt)
1324{
1325 int i;
1326
1327 printf("sg[%d]: {", cnt);
1328 for (i = 0; i < cnt; i++) {
1329 if (i) {
1330 printf(", ");
1331 }
1332 printf("(%p, %zd)", sg[i].iov_base, sg[i].iov_len);
1333 }
1334 printf("}\n");
1335}
1336
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +05301337/* Will call this only for path name based fid */
1338static void v9fs_fix_path(V9fsPath *dst, V9fsPath *src, int len)
Anthony Liguori8cf89e02010-04-29 17:45:00 +05301339{
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +05301340 V9fsPath str;
1341 v9fs_path_init(&str);
1342 v9fs_path_copy(&str, dst);
Greg Kurze3e83f22016-09-16 08:56:15 +02001343 v9fs_path_sprintf(dst, "%s%s", src->data, str.data + len);
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +05301344 v9fs_path_free(&str);
Anthony Liguori8cf89e02010-04-29 17:45:00 +05301345}
1346
M. Mohan Kumar2c74c2c2011-10-25 12:10:39 +05301347static inline bool is_ro_export(FsContext *ctx)
1348{
1349 return ctx->export_flags & V9FS_RDONLY;
1350}
1351
Greg Kurz8440e222016-10-17 14:13:58 +02001352static void coroutine_fn v9fs_version(void *opaque)
Anthony Liguori9f107512010-04-29 17:44:44 +05301353{
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05301354 ssize_t err;
Venkateswararao Jujjuri (JV)ff060302011-05-18 14:18:05 -07001355 V9fsPDU *pdu = opaque;
1356 V9fsState *s = pdu->s;
Anthony Liguori92c1ad02010-04-29 17:44:51 +05301357 V9fsString version;
1358 size_t offset = 7;
1359
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05301360 v9fs_string_init(&version);
1361 err = pdu_unmarshal(pdu, offset, "ds", &s->msize, &version);
1362 if (err < 0) {
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05301363 goto out;
1364 }
Harsh Prateek Borac572f232011-10-12 19:11:25 +05301365 trace_v9fs_version(pdu->tag, pdu->id, s->msize, version.data);
Anthony Liguori92c1ad02010-04-29 17:44:51 +05301366
Deepak C Shettyb41e2992011-12-04 22:35:28 +05301367 virtfs_reset(pdu);
1368
M. Mohan Kumar84151512010-05-27 13:57:29 +05301369 if (!strcmp(version.data, "9P2000.u")) {
1370 s->proto_version = V9FS_PROTO_2000U;
1371 } else if (!strcmp(version.data, "9P2000.L")) {
1372 s->proto_version = V9FS_PROTO_2000L;
1373 } else {
Anthony Liguori92c1ad02010-04-29 17:44:51 +05301374 v9fs_string_sprintf(&version, "unknown");
Christian Schoenebecke16453a2020-02-08 09:24:19 +01001375 /* skip min. msize check, reporting invalid version has priority */
1376 goto marshal;
Anthony Liguori9f107512010-04-29 17:44:44 +05301377 }
Anthony Liguori92c1ad02010-04-29 17:44:51 +05301378
Christian Schoenebecke16453a2020-02-08 09:24:19 +01001379 if (s->msize < P9_MIN_MSIZE) {
1380 err = -EMSGSIZE;
1381 error_report(
1382 "9pfs: Client requested msize < minimum msize ("
1383 stringify(P9_MIN_MSIZE) ") supported by this server."
1384 );
1385 goto out;
1386 }
1387
Christian Schoenebeck62777d82020-09-03 16:20:21 +02001388 /* 8192 is the default msize of Linux clients */
Christian Schoenebeckc418f932020-09-06 18:50:32 +02001389 if (s->msize <= 8192 && !(s->ctx.export_flags & V9FS_NO_PERF_WARN)) {
Christian Schoenebeck62777d82020-09-03 16:20:21 +02001390 warn_report_once(
1391 "9p: degraded performance: a reasonable high msize should be "
1392 "chosen on client/guest side (chosen msize is <= 8192). See "
1393 "https://wiki.qemu.org/Documentation/9psetup#msize for details."
1394 );
1395 }
1396
Christian Schoenebecke16453a2020-02-08 09:24:19 +01001397marshal:
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05301398 err = pdu_marshal(pdu, offset, "ds", s->msize, &version);
1399 if (err < 0) {
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05301400 goto out;
1401 }
Philippe Mathieu-Daudé403a9052017-08-09 16:32:46 +02001402 err += offset;
Harsh Prateek Borac572f232011-10-12 19:11:25 +05301403 trace_v9fs_version_return(pdu->tag, pdu->id, s->msize, version.data);
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05301404out:
Philippe Mathieu-Daudé403a9052017-08-09 16:32:46 +02001405 pdu_complete(pdu, err);
Anthony Liguori92c1ad02010-04-29 17:44:51 +05301406 v9fs_string_free(&version);
Anthony Liguori9f107512010-04-29 17:44:44 +05301407}
1408
Greg Kurz8440e222016-10-17 14:13:58 +02001409static void coroutine_fn v9fs_attach(void *opaque)
Anthony Liguori9f107512010-04-29 17:44:44 +05301410{
Venkateswararao Jujjuri (JV)ff060302011-05-18 14:18:05 -07001411 V9fsPDU *pdu = opaque;
1412 V9fsState *s = pdu->s;
Anthony Liguori955efc42010-04-29 17:44:52 +05301413 int32_t fid, afid, n_uname;
1414 V9fsString uname, aname;
1415 V9fsFidState *fidp;
Anthony Liguori955efc42010-04-29 17:44:52 +05301416 size_t offset = 7;
Aneesh Kumar K.V8c158562011-05-08 13:15:29 +05301417 V9fsQID qid;
Anthony Liguori955efc42010-04-29 17:44:52 +05301418 ssize_t err;
Christian Schoenebeck11024372021-06-04 19:52:18 +02001419 struct stat stbuf;
Anthony Liguori955efc42010-04-29 17:44:52 +05301420
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05301421 v9fs_string_init(&uname);
1422 v9fs_string_init(&aname);
1423 err = pdu_unmarshal(pdu, offset, "ddssd", &fid,
1424 &afid, &uname, &aname, &n_uname);
1425 if (err < 0) {
1426 goto out_nofid;
1427 }
Harsh Prateek Borac572f232011-10-12 19:11:25 +05301428 trace_v9fs_attach(pdu->tag, pdu->id, fid, afid, uname.data, aname.data);
Anthony Liguori955efc42010-04-29 17:44:52 +05301429
1430 fidp = alloc_fid(s, fid);
1431 if (fidp == NULL) {
1432 err = -EINVAL;
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05301433 goto out_nofid;
Anthony Liguori9f107512010-04-29 17:44:44 +05301434 }
Anthony Liguori955efc42010-04-29 17:44:52 +05301435 fidp->uid = n_uname;
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05301436 err = v9fs_co_name_to_path(pdu, NULL, "/", &fidp->path);
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +05301437 if (err < 0) {
1438 err = -EINVAL;
1439 clunk_fid(s, fid);
1440 goto out;
1441 }
Christian Schoenebeck11024372021-06-04 19:52:18 +02001442 err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
1443 if (err < 0) {
1444 err = -EINVAL;
1445 clunk_fid(s, fid);
1446 goto out;
1447 }
1448 err = stat_to_qid(pdu, &stbuf, &qid);
Aneesh Kumar K.V8c158562011-05-08 13:15:29 +05301449 if (err < 0) {
Anthony Liguori955efc42010-04-29 17:44:52 +05301450 err = -EINVAL;
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05301451 clunk_fid(s, fid);
Anthony Liguori955efc42010-04-29 17:44:52 +05301452 goto out;
1453 }
Ashijeet Acharyafe44dc92017-01-16 17:01:53 +05301454
1455 /*
1456 * disable migration if we haven't done already.
1457 * attach could get called multiple times for the same export.
1458 */
1459 if (!s->migration_blocker) {
1460 error_setg(&s->migration_blocker,
1461 "Migration is disabled when VirtFS export path '%s' is mounted in the guest using mount_tag '%s'",
1462 s->ctx.fs_root ? s->ctx.fs_root : "NULL", s->tag);
Markus Armbruster9261ef52020-06-30 11:03:28 +02001463 err = migrate_add_blocker(s->migration_blocker, NULL);
1464 if (err < 0) {
Ashijeet Acharyafe44dc92017-01-16 17:01:53 +05301465 error_free(s->migration_blocker);
1466 s->migration_blocker = NULL;
1467 clunk_fid(s, fid);
1468 goto out;
1469 }
1470 s->root_fid = fid;
1471 }
1472
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05301473 err = pdu_marshal(pdu, offset, "Q", &qid);
1474 if (err < 0) {
1475 clunk_fid(s, fid);
1476 goto out;
1477 }
1478 err += offset;
Ashijeet Acharyafe44dc92017-01-16 17:01:53 +05301479
Christian Schoenebeck11024372021-06-04 19:52:18 +02001480 memcpy(&s->root_st, &stbuf, sizeof(stbuf));
Aneesh Kumar K.V7999f7e2011-10-24 15:09:49 +05301481 trace_v9fs_attach_return(pdu->tag, pdu->id,
1482 qid.type, qid.version, qid.path);
Anthony Liguori955efc42010-04-29 17:44:52 +05301483out:
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05301484 put_fid(pdu, fidp);
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05301485out_nofid:
Wei Liudc295f82015-12-02 15:00:14 +00001486 pdu_complete(pdu, err);
Anthony Liguori955efc42010-04-29 17:44:52 +05301487 v9fs_string_free(&uname);
1488 v9fs_string_free(&aname);
Anthony Liguori9f107512010-04-29 17:44:44 +05301489}
1490
Greg Kurz8440e222016-10-17 14:13:58 +02001491static void coroutine_fn v9fs_stat(void *opaque)
Anthony Liguori9f107512010-04-29 17:44:44 +05301492{
Aneesh Kumar K.Vd8e0c292011-05-07 18:29:24 +05301493 int32_t fid;
1494 V9fsStat v9stat;
1495 ssize_t err = 0;
1496 size_t offset = 7;
1497 struct stat stbuf;
1498 V9fsFidState *fidp;
Venkateswararao Jujjuri (JV)ff060302011-05-18 14:18:05 -07001499 V9fsPDU *pdu = opaque;
Jan Dakinevich60695372017-09-20 08:48:51 +02001500 char *basename;
Anthony Liguori4da7d3f2010-04-29 17:44:53 +05301501
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05301502 err = pdu_unmarshal(pdu, offset, "d", &fid);
1503 if (err < 0) {
1504 goto out_nofid;
1505 }
Harsh Prateek Borac572f232011-10-12 19:11:25 +05301506 trace_v9fs_stat(pdu->tag, pdu->id, fid);
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05301507
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05301508 fidp = get_fid(pdu, fid);
Aneesh Kumar K.Vd8e0c292011-05-07 18:29:24 +05301509 if (fidp == NULL) {
Anthony Liguori4da7d3f2010-04-29 17:44:53 +05301510 err = -ENOENT;
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05301511 goto out_nofid;
Anthony Liguori9f107512010-04-29 17:44:44 +05301512 }
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05301513 err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
Aneesh Kumar K.Vd8e0c292011-05-07 18:29:24 +05301514 if (err < 0) {
1515 goto out;
1516 }
Jan Dakinevich60695372017-09-20 08:48:51 +02001517 basename = g_path_get_basename(fidp->path.data);
1518 err = stat_to_v9stat(pdu, &fidp->path, basename, &stbuf, &v9stat);
1519 g_free(basename);
Aneesh Kumar K.Vd8e0c292011-05-07 18:29:24 +05301520 if (err < 0) {
1521 goto out;
1522 }
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05301523 err = pdu_marshal(pdu, offset, "wS", 0, &v9stat);
1524 if (err < 0) {
1525 v9fs_stat_free(&v9stat);
1526 goto out;
1527 }
Aneesh Kumar K.V7999f7e2011-10-24 15:09:49 +05301528 trace_v9fs_stat_return(pdu->tag, pdu->id, v9stat.mode,
1529 v9stat.atime, v9stat.mtime, v9stat.length);
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05301530 err += offset;
Aneesh Kumar K.Vd8e0c292011-05-07 18:29:24 +05301531 v9fs_stat_free(&v9stat);
Anthony Liguori4da7d3f2010-04-29 17:44:53 +05301532out:
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05301533 put_fid(pdu, fidp);
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05301534out_nofid:
Wei Liudc295f82015-12-02 15:00:14 +00001535 pdu_complete(pdu, err);
Anthony Liguori9f107512010-04-29 17:44:44 +05301536}
1537
Greg Kurz8440e222016-10-17 14:13:58 +02001538static void coroutine_fn v9fs_getattr(void *opaque)
Sripathi Kodi00ede4c2010-07-20 11:44:41 +05301539{
1540 int32_t fid;
Aneesh Kumar K.V8db21ce2011-05-18 16:04:33 -07001541 size_t offset = 7;
1542 ssize_t retval = 0;
1543 struct stat stbuf;
Sripathi Kodi00ede4c2010-07-20 11:44:41 +05301544 V9fsFidState *fidp;
1545 uint64_t request_mask;
Aneesh Kumar K.V8db21ce2011-05-18 16:04:33 -07001546 V9fsStatDotl v9stat_dotl;
1547 V9fsPDU *pdu = opaque;
Sripathi Kodi00ede4c2010-07-20 11:44:41 +05301548
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05301549 retval = pdu_unmarshal(pdu, offset, "dq", &fid, &request_mask);
1550 if (retval < 0) {
1551 goto out_nofid;
1552 }
Harsh Prateek Borac572f232011-10-12 19:11:25 +05301553 trace_v9fs_getattr(pdu->tag, pdu->id, fid, request_mask);
Sripathi Kodi00ede4c2010-07-20 11:44:41 +05301554
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05301555 fidp = get_fid(pdu, fid);
Sripathi Kodi00ede4c2010-07-20 11:44:41 +05301556 if (fidp == NULL) {
Aneesh Kumar K.V8db21ce2011-05-18 16:04:33 -07001557 retval = -ENOENT;
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05301558 goto out_nofid;
Sripathi Kodi00ede4c2010-07-20 11:44:41 +05301559 }
Aneesh Kumar K.V8db21ce2011-05-18 16:04:33 -07001560 /*
1561 * Currently we only support BASIC fields in stat, so there is no
Sripathi Kodi00ede4c2010-07-20 11:44:41 +05301562 * need to look at request_mask.
1563 */
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05301564 retval = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
Aneesh Kumar K.V8db21ce2011-05-18 16:04:33 -07001565 if (retval < 0) {
1566 goto out;
1567 }
Antonios Motakis3b5ee9e2019-10-10 11:36:05 +02001568 retval = stat_to_v9stat_dotl(pdu, &stbuf, &v9stat_dotl);
1569 if (retval < 0) {
1570 goto out;
1571 }
Harsh Prateek Borae06a7652011-10-12 19:11:25 +05301572
1573 /* fill st_gen if requested and supported by underlying fs */
1574 if (request_mask & P9_STATS_GEN) {
1575 retval = v9fs_co_st_gen(pdu, &fidp->path, stbuf.st_mode, &v9stat_dotl);
Kirill A. Shutemovf8b7ee32014-01-28 17:08:27 +02001576 switch (retval) {
1577 case 0:
1578 /* we have valid st_gen: update result mask */
1579 v9stat_dotl.st_result_mask |= P9_STATS_GEN;
1580 break;
1581 case -EINTR:
1582 /* request cancelled, e.g. by Tflush */
Harsh Prateek Borae06a7652011-10-12 19:11:25 +05301583 goto out;
Kirill A. Shutemovf8b7ee32014-01-28 17:08:27 +02001584 default:
1585 /* failed to get st_gen: not fatal, ignore */
1586 break;
Harsh Prateek Borae06a7652011-10-12 19:11:25 +05301587 }
Harsh Prateek Borae06a7652011-10-12 19:11:25 +05301588 }
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05301589 retval = pdu_marshal(pdu, offset, "A", &v9stat_dotl);
1590 if (retval < 0) {
1591 goto out;
1592 }
1593 retval += offset;
Harsh Prateek Borac572f232011-10-12 19:11:25 +05301594 trace_v9fs_getattr_return(pdu->tag, pdu->id, v9stat_dotl.st_result_mask,
1595 v9stat_dotl.st_mode, v9stat_dotl.st_uid,
1596 v9stat_dotl.st_gid);
Aneesh Kumar K.V7999f7e2011-10-24 15:09:49 +05301597out:
1598 put_fid(pdu, fidp);
1599out_nofid:
Wei Liudc295f82015-12-02 15:00:14 +00001600 pdu_complete(pdu, retval);
Sripathi Kodi00ede4c2010-07-20 11:44:41 +05301601}
1602
Aneesh Kumar K.Ve4027ca2011-12-21 12:37:23 +05301603/* Attribute flags */
1604#define P9_ATTR_MODE (1 << 0)
1605#define P9_ATTR_UID (1 << 1)
1606#define P9_ATTR_GID (1 << 2)
1607#define P9_ATTR_SIZE (1 << 3)
1608#define P9_ATTR_ATIME (1 << 4)
1609#define P9_ATTR_MTIME (1 << 5)
1610#define P9_ATTR_CTIME (1 << 6)
1611#define P9_ATTR_ATIME_SET (1 << 7)
1612#define P9_ATTR_MTIME_SET (1 << 8)
1613
1614#define P9_ATTR_MASK 127
Sripathi Kodic79ce732010-06-17 18:18:47 +05301615
Greg Kurz8440e222016-10-17 14:13:58 +02001616static void coroutine_fn v9fs_setattr(void *opaque)
Sripathi Kodic79ce732010-06-17 18:18:47 +05301617{
Aneesh Kumar K.V65c05f92011-05-18 16:05:10 -07001618 int err = 0;
1619 int32_t fid;
1620 V9fsFidState *fidp;
1621 size_t offset = 7;
1622 V9fsIattr v9iattr;
1623 V9fsPDU *pdu = opaque;
Aneesh Kumar K.V65c05f92011-05-18 16:05:10 -07001624
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05301625 err = pdu_unmarshal(pdu, offset, "dI", &fid, &v9iattr);
1626 if (err < 0) {
1627 goto out_nofid;
1628 }
Aneesh Kumar K.V65c05f92011-05-18 16:05:10 -07001629
Greg Kurz8f9c64b2018-05-02 08:59:24 +02001630 trace_v9fs_setattr(pdu->tag, pdu->id, fid,
1631 v9iattr.valid, v9iattr.mode, v9iattr.uid, v9iattr.gid,
1632 v9iattr.size, v9iattr.atime_sec, v9iattr.mtime_sec);
1633
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05301634 fidp = get_fid(pdu, fid);
Aneesh Kumar K.V65c05f92011-05-18 16:05:10 -07001635 if (fidp == NULL) {
1636 err = -EINVAL;
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05301637 goto out_nofid;
Sripathi Kodic79ce732010-06-17 18:18:47 +05301638 }
Aneesh Kumar K.Ve4027ca2011-12-21 12:37:23 +05301639 if (v9iattr.valid & P9_ATTR_MODE) {
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05301640 err = v9fs_co_chmod(pdu, &fidp->path, v9iattr.mode);
Aneesh Kumar K.V65c05f92011-05-18 16:05:10 -07001641 if (err < 0) {
1642 goto out;
Sripathi Kodic79ce732010-06-17 18:18:47 +05301643 }
Sripathi Kodic79ce732010-06-17 18:18:47 +05301644 }
Aneesh Kumar K.Ve4027ca2011-12-21 12:37:23 +05301645 if (v9iattr.valid & (P9_ATTR_ATIME | P9_ATTR_MTIME)) {
Sripathi Kodic79ce732010-06-17 18:18:47 +05301646 struct timespec times[2];
Aneesh Kumar K.Ve4027ca2011-12-21 12:37:23 +05301647 if (v9iattr.valid & P9_ATTR_ATIME) {
1648 if (v9iattr.valid & P9_ATTR_ATIME_SET) {
Aneesh Kumar K.V65c05f92011-05-18 16:05:10 -07001649 times[0].tv_sec = v9iattr.atime_sec;
1650 times[0].tv_nsec = v9iattr.atime_nsec;
Sripathi Kodic79ce732010-06-17 18:18:47 +05301651 } else {
1652 times[0].tv_nsec = UTIME_NOW;
1653 }
1654 } else {
1655 times[0].tv_nsec = UTIME_OMIT;
1656 }
Aneesh Kumar K.Ve4027ca2011-12-21 12:37:23 +05301657 if (v9iattr.valid & P9_ATTR_MTIME) {
1658 if (v9iattr.valid & P9_ATTR_MTIME_SET) {
Aneesh Kumar K.V65c05f92011-05-18 16:05:10 -07001659 times[1].tv_sec = v9iattr.mtime_sec;
1660 times[1].tv_nsec = v9iattr.mtime_nsec;
Sripathi Kodic79ce732010-06-17 18:18:47 +05301661 } else {
1662 times[1].tv_nsec = UTIME_NOW;
1663 }
1664 } else {
1665 times[1].tv_nsec = UTIME_OMIT;
1666 }
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05301667 err = v9fs_co_utimensat(pdu, &fidp->path, times);
Aneesh Kumar K.V65c05f92011-05-18 16:05:10 -07001668 if (err < 0) {
1669 goto out;
1670 }
Sripathi Kodic79ce732010-06-17 18:18:47 +05301671 }
Aneesh Kumar K.V65c05f92011-05-18 16:05:10 -07001672 /*
1673 * If the only valid entry in iattr is ctime we can call
1674 * chown(-1,-1) to update the ctime of the file
1675 */
Aneesh Kumar K.Ve4027ca2011-12-21 12:37:23 +05301676 if ((v9iattr.valid & (P9_ATTR_UID | P9_ATTR_GID)) ||
1677 ((v9iattr.valid & P9_ATTR_CTIME)
1678 && !((v9iattr.valid & P9_ATTR_MASK) & ~P9_ATTR_CTIME))) {
1679 if (!(v9iattr.valid & P9_ATTR_UID)) {
Aneesh Kumar K.V65c05f92011-05-18 16:05:10 -07001680 v9iattr.uid = -1;
1681 }
Aneesh Kumar K.Ve4027ca2011-12-21 12:37:23 +05301682 if (!(v9iattr.valid & P9_ATTR_GID)) {
Aneesh Kumar K.V65c05f92011-05-18 16:05:10 -07001683 v9iattr.gid = -1;
1684 }
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05301685 err = v9fs_co_chown(pdu, &fidp->path, v9iattr.uid,
Aneesh Kumar K.V65c05f92011-05-18 16:05:10 -07001686 v9iattr.gid);
1687 if (err < 0) {
1688 goto out;
1689 }
1690 }
Aneesh Kumar K.Ve4027ca2011-12-21 12:37:23 +05301691 if (v9iattr.valid & (P9_ATTR_SIZE)) {
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05301692 err = v9fs_co_truncate(pdu, &fidp->path, v9iattr.size);
Aneesh Kumar K.V65c05f92011-05-18 16:05:10 -07001693 if (err < 0) {
1694 goto out;
1695 }
1696 }
1697 err = offset;
Greg Kurz8f9c64b2018-05-02 08:59:24 +02001698 trace_v9fs_setattr_return(pdu->tag, pdu->id);
Sripathi Kodic79ce732010-06-17 18:18:47 +05301699out:
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05301700 put_fid(pdu, fidp);
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05301701out_nofid:
Wei Liudc295f82015-12-02 15:00:14 +00001702 pdu_complete(pdu, err);
Sripathi Kodic79ce732010-06-17 18:18:47 +05301703}
1704
Aneesh Kumar K.V3cc19c02011-05-07 19:41:55 +05301705static int v9fs_walk_marshal(V9fsPDU *pdu, uint16_t nwnames, V9fsQID *qids)
Anthony Liguoriff5e54c2010-04-29 17:44:54 +05301706{
1707 int i;
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05301708 ssize_t err;
Aneesh Kumar K.V3cc19c02011-05-07 19:41:55 +05301709 size_t offset = 7;
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05301710
1711 err = pdu_marshal(pdu, offset, "w", nwnames);
1712 if (err < 0) {
1713 return err;
1714 }
1715 offset += err;
Aneesh Kumar K.V3cc19c02011-05-07 19:41:55 +05301716 for (i = 0; i < nwnames; i++) {
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05301717 err = pdu_marshal(pdu, offset, "Q", &qids[i]);
1718 if (err < 0) {
1719 return err;
1720 }
1721 offset += err;
Anthony Liguoriff5e54c2010-04-29 17:44:54 +05301722 }
Aneesh Kumar K.V3cc19c02011-05-07 19:41:55 +05301723 return offset;
Anthony Liguoriff5e54c2010-04-29 17:44:54 +05301724}
1725
Greg Kurzfff39a72016-08-30 19:11:05 +02001726static bool name_is_illegal(const char *name)
1727{
1728 return !*name || strchr(name, '/') != NULL;
1729}
1730
Christian Schoenebeckf22cad42021-06-04 19:57:21 +02001731static bool same_stat_id(const struct stat *a, const struct stat *b)
Greg Kurz56f101e2016-08-30 17:02:27 +02001732{
Christian Schoenebeckf22cad42021-06-04 19:57:21 +02001733 return a->st_dev == b->st_dev && a->st_ino == b->st_ino;
Greg Kurz56f101e2016-08-30 17:02:27 +02001734}
1735
Greg Kurz8440e222016-10-17 14:13:58 +02001736static void coroutine_fn v9fs_walk(void *opaque)
Anthony Liguori9f107512010-04-29 17:44:44 +05301737{
Aneesh Kumar K.V3cc19c02011-05-07 19:41:55 +05301738 int name_idx;
Christian Schoenebeck869605b2021-08-17 15:46:50 +02001739 g_autofree V9fsQID *qids = NULL;
Aneesh Kumar K.V3cc19c02011-05-07 19:41:55 +05301740 int i, err = 0;
Christian Schoenebeck7e985782021-10-01 16:27:59 +02001741 V9fsPath dpath, path;
1742 P9ARRAY_REF(V9fsPath) pathes = NULL;
Aneesh Kumar K.V3cc19c02011-05-07 19:41:55 +05301743 uint16_t nwnames;
Christian Schoenebeck869605b2021-08-17 15:46:50 +02001744 struct stat stbuf, fidst;
1745 g_autofree struct stat *stbufs = NULL;
Aneesh Kumar K.V3cc19c02011-05-07 19:41:55 +05301746 size_t offset = 7;
1747 int32_t fid, newfid;
Christian Schoenebeck7e985782021-10-01 16:27:59 +02001748 P9ARRAY_REF(V9fsString) wnames = NULL;
Aneesh Kumar K.V3cc19c02011-05-07 19:41:55 +05301749 V9fsFidState *fidp;
Dong Xu Wang3a931132011-11-29 16:52:38 +08001750 V9fsFidState *newfidp = NULL;
Venkateswararao Jujjuri (JV)ff060302011-05-18 14:18:05 -07001751 V9fsPDU *pdu = opaque;
1752 V9fsState *s = pdu->s;
Greg Kurz56f101e2016-08-30 17:02:27 +02001753 V9fsQID qid;
Anthony Liguoriff5e54c2010-04-29 17:44:54 +05301754
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05301755 err = pdu_unmarshal(pdu, offset, "ddw", &fid, &newfid, &nwnames);
1756 if (err < 0) {
Wei Liudc295f82015-12-02 15:00:14 +00001757 pdu_complete(pdu, err);
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05301758 return ;
1759 }
1760 offset += err;
Anthony Liguoriff5e54c2010-04-29 17:44:54 +05301761
Harsh Prateek Borac572f232011-10-12 19:11:25 +05301762 trace_v9fs_walk(pdu->tag, pdu->id, fid, newfid, nwnames);
1763
Christian Schoenebeck232a4d22021-05-16 17:55:34 +02001764 if (nwnames > P9_MAXWELEM) {
1765 err = -EINVAL;
1766 goto out_nofid;
1767 }
1768 if (nwnames) {
Christian Schoenebeck7e985782021-10-01 16:27:59 +02001769 P9ARRAY_NEW(V9fsString, wnames, nwnames);
Greg Kurz19239232018-12-12 14:18:10 +01001770 qids = g_new0(V9fsQID, nwnames);
Christian Schoenebeck8d6cb102021-07-02 17:16:32 +02001771 stbufs = g_new0(struct stat, nwnames);
Christian Schoenebeck7e985782021-10-01 16:27:59 +02001772 P9ARRAY_NEW(V9fsPath, pathes, nwnames);
Aneesh Kumar K.V3cc19c02011-05-07 19:41:55 +05301773 for (i = 0; i < nwnames; i++) {
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05301774 err = pdu_unmarshal(pdu, offset, "s", &wnames[i]);
1775 if (err < 0) {
1776 goto out_nofid;
1777 }
Greg Kurzfff39a72016-08-30 19:11:05 +02001778 if (name_is_illegal(wnames[i].data)) {
1779 err = -ENOENT;
1780 goto out_nofid;
1781 }
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05301782 offset += err;
Anthony Liguoriff5e54c2010-04-29 17:44:54 +05301783 }
Anthony Liguori9f107512010-04-29 17:44:44 +05301784 }
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05301785 fidp = get_fid(pdu, fid);
Aneesh Kumar K.V3cc19c02011-05-07 19:41:55 +05301786 if (fidp == NULL) {
Anthony Liguoriff5e54c2010-04-29 17:44:54 +05301787 err = -ENOENT;
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05301788 goto out_nofid;
Anthony Liguoriff5e54c2010-04-29 17:44:54 +05301789 }
Greg Kurz56f101e2016-08-30 17:02:27 +02001790
Greg Kurz13fd08e2016-09-16 11:44:49 +02001791 v9fs_path_init(&dpath);
1792 v9fs_path_init(&path);
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +05301793 /*
Christian Schoenebeck8d6cb102021-07-02 17:16:32 +02001794 * Both dpath and path initially point to fidp.
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +05301795 * Needed to handle request with nwnames == 0
1796 */
1797 v9fs_path_copy(&dpath, &fidp->path);
1798 v9fs_path_copy(&path, &fidp->path);
Christian Schoenebeck8d6cb102021-07-02 17:16:32 +02001799
1800 /*
1801 * To keep latency (i.e. overall execution time for processing this
1802 * Twalk client request) as small as possible, run all the required fs
1803 * driver code altogether inside the following block.
1804 */
1805 v9fs_co_run_in_worker({
1806 if (v9fs_request_cancelled(pdu)) {
1807 err = -EINTR;
1808 break;
1809 }
1810 err = s->ops->lstat(&s->ctx, &dpath, &fidst);
1811 if (err < 0) {
1812 err = -errno;
1813 break;
1814 }
1815 stbuf = fidst;
1816 for (name_idx = 0; name_idx < nwnames; name_idx++) {
1817 if (v9fs_request_cancelled(pdu)) {
1818 err = -EINTR;
1819 break;
1820 }
1821 if (!same_stat_id(&pdu->s->root_st, &stbuf) ||
1822 strcmp("..", wnames[name_idx].data))
1823 {
1824 err = s->ops->name_to_path(&s->ctx, &dpath,
Christian Schoenebeck97b1d8f2021-08-17 14:38:24 +02001825 wnames[name_idx].data,
1826 &pathes[name_idx]);
Christian Schoenebeck8d6cb102021-07-02 17:16:32 +02001827 if (err < 0) {
1828 err = -errno;
1829 break;
1830 }
1831 if (v9fs_request_cancelled(pdu)) {
1832 err = -EINTR;
1833 break;
1834 }
Christian Schoenebeck97b1d8f2021-08-17 14:38:24 +02001835 err = s->ops->lstat(&s->ctx, &pathes[name_idx], &stbuf);
Christian Schoenebeck8d6cb102021-07-02 17:16:32 +02001836 if (err < 0) {
1837 err = -errno;
1838 break;
1839 }
1840 stbufs[name_idx] = stbuf;
Christian Schoenebeck97b1d8f2021-08-17 14:38:24 +02001841 v9fs_path_copy(&dpath, &pathes[name_idx]);
Christian Schoenebeck8d6cb102021-07-02 17:16:32 +02001842 }
1843 }
1844 });
1845 /*
1846 * Handle all the rest of this Twalk request on main thread ...
1847 */
1848 if (err < 0) {
1849 goto out;
1850 }
1851
1852 err = stat_to_qid(pdu, &fidst, &qid);
1853 if (err < 0) {
1854 goto out;
1855 }
1856 stbuf = fidst;
1857
1858 /* reset dpath and path */
1859 v9fs_path_copy(&dpath, &fidp->path);
1860 v9fs_path_copy(&path, &fidp->path);
1861
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +05301862 for (name_idx = 0; name_idx < nwnames; name_idx++) {
Christian Schoenebeckf22cad42021-06-04 19:57:21 +02001863 if (!same_stat_id(&pdu->s->root_st, &stbuf) ||
Christian Schoenebeck8d6cb102021-07-02 17:16:32 +02001864 strcmp("..", wnames[name_idx].data))
1865 {
1866 stbuf = stbufs[name_idx];
Antonios Motakis3b5ee9e2019-10-10 11:36:05 +02001867 err = stat_to_qid(pdu, &stbuf, &qid);
1868 if (err < 0) {
1869 goto out;
1870 }
Christian Schoenebeck8d6cb102021-07-02 17:16:32 +02001871 v9fs_path_copy(&path, &pathes[name_idx]);
Greg Kurz56f101e2016-08-30 17:02:27 +02001872 v9fs_path_copy(&dpath, &path);
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +05301873 }
Greg Kurz56f101e2016-08-30 17:02:27 +02001874 memcpy(&qids[name_idx], &qid, sizeof(qid));
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +05301875 }
Anthony Liguoriff5e54c2010-04-29 17:44:54 +05301876 if (fid == newfid) {
Greg Kurz49dd9462016-11-01 12:00:40 +01001877 if (fidp->fid_type != P9_FID_NONE) {
1878 err = -EINVAL;
1879 goto out;
1880 }
Greg Kurz5b3c77a2018-11-20 13:00:35 +01001881 v9fs_path_write_lock(s);
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +05301882 v9fs_path_copy(&fidp->path, &path);
Greg Kurz5b3c77a2018-11-20 13:00:35 +01001883 v9fs_path_unlock(s);
Anthony Liguoriff5e54c2010-04-29 17:44:54 +05301884 } else {
Aneesh Kumar K.V3cc19c02011-05-07 19:41:55 +05301885 newfidp = alloc_fid(s, newfid);
1886 if (newfidp == NULL) {
Anthony Liguoriff5e54c2010-04-29 17:44:54 +05301887 err = -EINVAL;
1888 goto out;
1889 }
Aneesh Kumar K.V3cc19c02011-05-07 19:41:55 +05301890 newfidp->uid = fidp->uid;
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +05301891 v9fs_path_copy(&newfidp->path, &path);
Anthony Liguoriff5e54c2010-04-29 17:44:54 +05301892 }
Aneesh Kumar K.V3cc19c02011-05-07 19:41:55 +05301893 err = v9fs_walk_marshal(pdu, nwnames, qids);
Aneesh Kumar K.V7999f7e2011-10-24 15:09:49 +05301894 trace_v9fs_walk_return(pdu->tag, pdu->id, nwnames, qids);
Anthony Liguoriff5e54c2010-04-29 17:44:54 +05301895out:
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05301896 put_fid(pdu, fidp);
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05301897 if (newfidp) {
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05301898 put_fid(pdu, newfidp);
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05301899 }
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +05301900 v9fs_path_free(&dpath);
1901 v9fs_path_free(&path);
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05301902out_nofid:
Wei Liudc295f82015-12-02 15:00:14 +00001903 pdu_complete(pdu, err);
Anthony Liguori9f107512010-04-29 17:44:44 +05301904}
1905
Greg Kurz8440e222016-10-17 14:13:58 +02001906static int32_t coroutine_fn get_iounit(V9fsPDU *pdu, V9fsPath *path)
M. Mohan Kumar5e94c102010-06-09 19:14:28 +05301907{
1908 struct statfs stbuf;
Christian Schoenebeckb565bcc2021-09-27 17:45:00 +02001909 int err = v9fs_co_statfs(pdu, path, &stbuf);
M. Mohan Kumar5e94c102010-06-09 19:14:28 +05301910
Christian Schoenebeckb565bcc2021-09-27 17:45:00 +02001911 return blksize_to_iounit(pdu, (err >= 0) ? stbuf.f_bsize : 0);
M. Mohan Kumar5e94c102010-06-09 19:14:28 +05301912}
1913
Greg Kurz8440e222016-10-17 14:13:58 +02001914static void coroutine_fn v9fs_open(void *opaque)
Anthony Liguoria6568fe2010-04-29 17:44:55 +05301915{
M. Mohan Kumar771e9d42010-06-22 19:47:04 +05301916 int flags;
Aneesh Kumar K.V857bc152011-05-07 17:36:36 +05301917 int32_t fid;
1918 int32_t mode;
1919 V9fsQID qid;
Aneesh Kumar K.V7999f7e2011-10-24 15:09:49 +05301920 int iounit = 0;
Aneesh Kumar K.V857bc152011-05-07 17:36:36 +05301921 ssize_t err = 0;
1922 size_t offset = 7;
1923 struct stat stbuf;
1924 V9fsFidState *fidp;
1925 V9fsPDU *pdu = opaque;
1926 V9fsState *s = pdu->s;
M. Mohan Kumar771e9d42010-06-22 19:47:04 +05301927
Aneesh Kumar K.V857bc152011-05-07 17:36:36 +05301928 if (s->proto_version == V9FS_PROTO_2000L) {
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05301929 err = pdu_unmarshal(pdu, offset, "dd", &fid, &mode);
Aneesh Kumar K.V857bc152011-05-07 17:36:36 +05301930 } else {
Benjamin Herrenschmidt67d6fa52012-02-24 11:23:30 +11001931 uint8_t modebyte;
1932 err = pdu_unmarshal(pdu, offset, "db", &fid, &modebyte);
1933 mode = modebyte;
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05301934 }
1935 if (err < 0) {
1936 goto out_nofid;
Aneesh Kumar K.V857bc152011-05-07 17:36:36 +05301937 }
Harsh Prateek Borac572f232011-10-12 19:11:25 +05301938 trace_v9fs_open(pdu->tag, pdu->id, fid, mode);
1939
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05301940 fidp = get_fid(pdu, fid);
Aneesh Kumar K.V857bc152011-05-07 17:36:36 +05301941 if (fidp == NULL) {
1942 err = -ENOENT;
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05301943 goto out_nofid;
Anthony Liguoria6568fe2010-04-29 17:44:55 +05301944 }
Greg Kurz49dd9462016-11-01 12:00:40 +01001945 if (fidp->fid_type != P9_FID_NONE) {
1946 err = -EINVAL;
1947 goto out;
1948 }
Anthony Liguoria6568fe2010-04-29 17:44:55 +05301949
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05301950 err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
Aneesh Kumar K.V857bc152011-05-07 17:36:36 +05301951 if (err < 0) {
1952 goto out;
1953 }
Antonios Motakis3b5ee9e2019-10-10 11:36:05 +02001954 err = stat_to_qid(pdu, &stbuf, &qid);
1955 if (err < 0) {
1956 goto out;
1957 }
Aneesh Kumar K.V857bc152011-05-07 17:36:36 +05301958 if (S_ISDIR(stbuf.st_mode)) {
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05301959 err = v9fs_co_opendir(pdu, fidp);
Aneesh Kumar K.V857bc152011-05-07 17:36:36 +05301960 if (err < 0) {
1961 goto out;
1962 }
1963 fidp->fid_type = P9_FID_DIR;
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05301964 err = pdu_marshal(pdu, offset, "Qd", &qid, 0);
1965 if (err < 0) {
1966 goto out;
1967 }
1968 err += offset;
Anthony Liguoria6568fe2010-04-29 17:44:55 +05301969 } else {
M. Mohan Kumar771e9d42010-06-22 19:47:04 +05301970 if (s->proto_version == V9FS_PROTO_2000L) {
Aneesh Kumar K.Vd3ab98e2011-10-12 19:11:23 +05301971 flags = get_dotl_openflags(s, mode);
M. Mohan Kumar771e9d42010-06-22 19:47:04 +05301972 } else {
Aneesh Kumar K.V857bc152011-05-07 17:36:36 +05301973 flags = omode_to_uflags(mode);
M. Mohan Kumar771e9d42010-06-22 19:47:04 +05301974 }
M. Mohan Kumar2c74c2c2011-10-25 12:10:39 +05301975 if (is_ro_export(&s->ctx)) {
1976 if (mode & O_WRONLY || mode & O_RDWR ||
1977 mode & O_APPEND || mode & O_TRUNC) {
1978 err = -EROFS;
1979 goto out;
1980 }
M. Mohan Kumar2c74c2c2011-10-25 12:10:39 +05301981 }
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05301982 err = v9fs_co_open(pdu, fidp, flags);
Aneesh Kumar K.V857bc152011-05-07 17:36:36 +05301983 if (err < 0) {
1984 goto out;
1985 }
1986 fidp->fid_type = P9_FID_FILE;
Aneesh Kumar K.V7a462742011-05-18 15:40:57 +05301987 fidp->open_flags = flags;
1988 if (flags & O_EXCL) {
1989 /*
1990 * We let the host file system do O_EXCL check
1991 * We should not reclaim such fd
1992 */
1993 fidp->flags |= FID_NON_RECLAIMABLE;
1994 }
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05301995 iounit = get_iounit(pdu, &fidp->path);
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05301996 err = pdu_marshal(pdu, offset, "Qd", &qid, iounit);
1997 if (err < 0) {
1998 goto out;
1999 }
2000 err += offset;
Anthony Liguoria6568fe2010-04-29 17:44:55 +05302001 }
Aneesh Kumar K.V7999f7e2011-10-24 15:09:49 +05302002 trace_v9fs_open_return(pdu->tag, pdu->id,
2003 qid.type, qid.version, qid.path, iounit);
Anthony Liguoria6568fe2010-04-29 17:44:55 +05302004out:
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05302005 put_fid(pdu, fidp);
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05302006out_nofid:
Wei Liudc295f82015-12-02 15:00:14 +00002007 pdu_complete(pdu, err);
Anthony Liguoria6568fe2010-04-29 17:44:55 +05302008}
2009
Greg Kurz8440e222016-10-17 14:13:58 +02002010static void coroutine_fn v9fs_lcreate(void *opaque)
Venkateswararao Jujjuri (JV)c1568af2010-06-17 18:27:24 -07002011{
2012 int32_t dfid, flags, mode;
2013 gid_t gid;
Venkateswararao Jujjuri (JV)c1568af2010-06-17 18:27:24 -07002014 ssize_t err = 0;
Venkateswararao Jujjuri36f89812011-08-08 23:54:08 +05302015 ssize_t offset = 7;
Venkateswararao Jujjuri36f89812011-08-08 23:54:08 +05302016 V9fsString name;
2017 V9fsFidState *fidp;
2018 struct stat stbuf;
2019 V9fsQID qid;
2020 int32_t iounit;
2021 V9fsPDU *pdu = opaque;
Venkateswararao Jujjuri (JV)c1568af2010-06-17 18:27:24 -07002022
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05302023 v9fs_string_init(&name);
2024 err = pdu_unmarshal(pdu, offset, "dsddd", &dfid,
2025 &name, &flags, &mode, &gid);
2026 if (err < 0) {
2027 goto out_nofid;
2028 }
Harsh Prateek Borac572f232011-10-12 19:11:25 +05302029 trace_v9fs_lcreate(pdu->tag, pdu->id, dfid, flags, mode, gid);
Venkateswararao Jujjuri (JV)c1568af2010-06-17 18:27:24 -07002030
Greg Kurzfff39a72016-08-30 19:11:05 +02002031 if (name_is_illegal(name.data)) {
2032 err = -ENOENT;
2033 goto out_nofid;
2034 }
2035
Greg Kurz805b5d92016-08-30 19:13:11 +02002036 if (!strcmp(".", name.data) || !strcmp("..", name.data)) {
2037 err = -EEXIST;
2038 goto out_nofid;
2039 }
2040
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05302041 fidp = get_fid(pdu, dfid);
Venkateswararao Jujjuri36f89812011-08-08 23:54:08 +05302042 if (fidp == NULL) {
Venkateswararao Jujjuri (JV)c1568af2010-06-17 18:27:24 -07002043 err = -ENOENT;
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05302044 goto out_nofid;
Venkateswararao Jujjuri (JV)c1568af2010-06-17 18:27:24 -07002045 }
Li Qiangd63fb192017-03-27 21:13:19 +02002046 if (fidp->fid_type != P9_FID_NONE) {
2047 err = -EINVAL;
2048 goto out;
2049 }
Venkateswararao Jujjuri (JV)c1568af2010-06-17 18:27:24 -07002050
Aneesh Kumar K.Vd3ab98e2011-10-12 19:11:23 +05302051 flags = get_dotl_openflags(pdu->s, flags);
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05302052 err = v9fs_co_open2(pdu, fidp, &name, gid,
Aneesh Kumar K.V02cb7f32011-05-24 15:10:56 +05302053 flags | O_CREAT, mode, &stbuf);
Venkateswararao Jujjuri36f89812011-08-08 23:54:08 +05302054 if (err < 0) {
2055 goto out;
2056 }
2057 fidp->fid_type = P9_FID_FILE;
Aneesh Kumar K.V7a462742011-05-18 15:40:57 +05302058 fidp->open_flags = flags;
2059 if (flags & O_EXCL) {
2060 /*
2061 * We let the host file system do O_EXCL check
2062 * We should not reclaim such fd
2063 */
2064 fidp->flags |= FID_NON_RECLAIMABLE;
2065 }
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05302066 iounit = get_iounit(pdu, &fidp->path);
Antonios Motakis3b5ee9e2019-10-10 11:36:05 +02002067 err = stat_to_qid(pdu, &stbuf, &qid);
2068 if (err < 0) {
2069 goto out;
2070 }
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05302071 err = pdu_marshal(pdu, offset, "Qd", &qid, iounit);
2072 if (err < 0) {
2073 goto out;
2074 }
2075 err += offset;
Aneesh Kumar K.V7999f7e2011-10-24 15:09:49 +05302076 trace_v9fs_lcreate_return(pdu->tag, pdu->id,
2077 qid.type, qid.version, qid.path, iounit);
Venkateswararao Jujjuri (JV)c1568af2010-06-17 18:27:24 -07002078out:
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05302079 put_fid(pdu, fidp);
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05302080out_nofid:
Wei Liudc295f82015-12-02 15:00:14 +00002081 pdu_complete(pdu, err);
Venkateswararao Jujjuri36f89812011-08-08 23:54:08 +05302082 v9fs_string_free(&name);
Venkateswararao Jujjuri (JV)c1568af2010-06-17 18:27:24 -07002083}
2084
Greg Kurza1bf8b72016-11-25 12:54:21 +01002085static void coroutine_fn v9fs_fsync(void *opaque)
Venkateswararao Jujjuri (JV)b41e95d2010-09-22 17:18:33 -07002086{
Aneesh Kumar K.V4e9ad442011-05-07 21:25:51 +05302087 int err;
Venkateswararao Jujjuri (JV)b41e95d2010-09-22 17:18:33 -07002088 int32_t fid;
Aneesh Kumar K.V4e9ad442011-05-07 21:25:51 +05302089 int datasync;
Venkateswararao Jujjuri (JV)b41e95d2010-09-22 17:18:33 -07002090 size_t offset = 7;
2091 V9fsFidState *fidp;
Aneesh Kumar K.V4e9ad442011-05-07 21:25:51 +05302092 V9fsPDU *pdu = opaque;
Venkateswararao Jujjuri (JV)b41e95d2010-09-22 17:18:33 -07002093
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05302094 err = pdu_unmarshal(pdu, offset, "dd", &fid, &datasync);
2095 if (err < 0) {
2096 goto out_nofid;
2097 }
Harsh Prateek Borac572f232011-10-12 19:11:25 +05302098 trace_v9fs_fsync(pdu->tag, pdu->id, fid, datasync);
2099
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05302100 fidp = get_fid(pdu, fid);
Venkateswararao Jujjuri (JV)b41e95d2010-09-22 17:18:33 -07002101 if (fidp == NULL) {
2102 err = -ENOENT;
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05302103 goto out_nofid;
Venkateswararao Jujjuri (JV)b41e95d2010-09-22 17:18:33 -07002104 }
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05302105 err = v9fs_co_fsync(pdu, fidp, datasync);
Aneesh Kumar K.V4e9ad442011-05-07 21:25:51 +05302106 if (!err) {
2107 err = offset;
2108 }
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05302109 put_fid(pdu, fidp);
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05302110out_nofid:
Wei Liudc295f82015-12-02 15:00:14 +00002111 pdu_complete(pdu, err);
Venkateswararao Jujjuri (JV)b41e95d2010-09-22 17:18:33 -07002112}
2113
Greg Kurz8440e222016-10-17 14:13:58 +02002114static void coroutine_fn v9fs_clunk(void *opaque)
Anthony Liguori9f107512010-04-29 17:44:44 +05302115{
Aneesh Kumar K.Vc540ee52011-05-07 20:36:38 +05302116 int err;
Anthony Liguoribbd56972010-04-29 17:44:57 +05302117 int32_t fid;
2118 size_t offset = 7;
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05302119 V9fsFidState *fidp;
Aneesh Kumar K.Vc540ee52011-05-07 20:36:38 +05302120 V9fsPDU *pdu = opaque;
2121 V9fsState *s = pdu->s;
Anthony Liguoribbd56972010-04-29 17:44:57 +05302122
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05302123 err = pdu_unmarshal(pdu, offset, "d", &fid);
2124 if (err < 0) {
2125 goto out_nofid;
2126 }
Harsh Prateek Borac572f232011-10-12 19:11:25 +05302127 trace_v9fs_clunk(pdu->tag, pdu->id, fid);
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05302128
Aneesh Kumar K.Vce421a12011-08-02 11:36:24 +05302129 fidp = clunk_fid(s, fid);
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05302130 if (fidp == NULL) {
2131 err = -ENOENT;
2132 goto out_nofid;
2133 }
Aneesh Kumar K.Vce421a12011-08-02 11:36:24 +05302134 /*
2135 * Bump the ref so that put_fid will
2136 * free the fid.
2137 */
2138 fidp->ref++;
Aneesh Kumar K.Va911a182013-02-05 11:27:46 +05302139 err = put_fid(pdu, fidp);
2140 if (!err) {
2141 err = offset;
2142 }
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05302143out_nofid:
Wei Liudc295f82015-12-02 15:00:14 +00002144 pdu_complete(pdu, err);
Anthony Liguori9f107512010-04-29 17:44:44 +05302145}
2146
Stefano Stabellinibcb89982017-01-03 17:28:44 +01002147/*
2148 * Create a QEMUIOVector for a sub-region of PDU iovecs
2149 *
2150 * @qiov: uninitialized QEMUIOVector
2151 * @skip: number of bytes to skip from beginning of PDU
2152 * @size: number of bytes to include
2153 * @is_write: true - write, false - read
2154 *
2155 * The resulting QEMUIOVector has heap-allocated iovecs and must be cleaned up
2156 * with qemu_iovec_destroy().
2157 */
2158static void v9fs_init_qiov_from_pdu(QEMUIOVector *qiov, V9fsPDU *pdu,
Stefano Stabellinicf451832020-05-21 12:26:25 -07002159 size_t skip, size_t size,
Stefano Stabellinibcb89982017-01-03 17:28:44 +01002160 bool is_write)
2161{
2162 QEMUIOVector elem;
2163 struct iovec *iov;
2164 unsigned int niov;
2165
Stefano Stabellini88da0b02017-01-03 17:28:44 +01002166 if (is_write) {
Stefano Stabellinicf451832020-05-21 12:26:25 -07002167 pdu->s->transport->init_out_iov_from_pdu(pdu, &iov, &niov, size + skip);
Stefano Stabellini88da0b02017-01-03 17:28:44 +01002168 } else {
Stefano Stabellinicf451832020-05-21 12:26:25 -07002169 pdu->s->transport->init_in_iov_from_pdu(pdu, &iov, &niov, size + skip);
Stefano Stabellini88da0b02017-01-03 17:28:44 +01002170 }
Stefano Stabellinibcb89982017-01-03 17:28:44 +01002171
2172 qemu_iovec_init_external(&elem, iov, niov);
2173 qemu_iovec_init(qiov, niov);
Stefano Stabellinicf451832020-05-21 12:26:25 -07002174 qemu_iovec_concat(qiov, &elem, skip, size);
Stefano Stabellinibcb89982017-01-03 17:28:44 +01002175}
2176
Aneesh Kumar K.V2f008a82011-12-21 12:37:23 +05302177static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp,
2178 uint64_t off, uint32_t max_count)
Anthony Liguoria9231552010-04-29 17:44:56 +05302179{
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05302180 ssize_t err;
Aneesh Kumar K.Vd208a0e2011-05-20 13:46:31 -07002181 size_t offset = 7;
Stefano Stabellinicf451832020-05-21 12:26:25 -07002182 uint64_t read_count;
Stefano Stabellinibcb89982017-01-03 17:28:44 +01002183 QEMUIOVector qiov_full;
Aneesh Kumar K.Vfa32ef82010-09-02 11:09:06 +05302184
Li Qiang7e55d652016-11-01 12:00:40 +01002185 if (fidp->fs.xattr.len < off) {
2186 read_count = 0;
Greg Kurz16724a12020-01-20 15:11:39 +01002187 } else {
Stefano Stabellinicf451832020-05-21 12:26:25 -07002188 read_count = fidp->fs.xattr.len - off;
2189 }
2190 if (read_count > max_count) {
Aneesh Kumar K.Vd208a0e2011-05-20 13:46:31 -07002191 read_count = max_count;
Aneesh Kumar K.Vfa32ef82010-09-02 11:09:06 +05302192 }
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05302193 err = pdu_marshal(pdu, offset, "d", read_count);
2194 if (err < 0) {
2195 return err;
2196 }
2197 offset += err;
Wei Liu00588a02016-01-11 09:29:37 +00002198
Stefano Stabellinicf451832020-05-21 12:26:25 -07002199 v9fs_init_qiov_from_pdu(&qiov_full, pdu, offset, read_count, false);
Greg Kurzfa0eb5c2017-01-25 00:23:49 +01002200 err = v9fs_pack(qiov_full.iov, qiov_full.niov, 0,
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05302201 ((char *)fidp->fs.xattr.value) + off,
2202 read_count);
Stefano Stabellinibcb89982017-01-03 17:28:44 +01002203 qemu_iovec_destroy(&qiov_full);
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05302204 if (err < 0) {
2205 return err;
2206 }
2207 offset += err;
Aneesh Kumar K.Vd208a0e2011-05-20 13:46:31 -07002208 return offset;
2209}
2210
Greg Kurz8440e222016-10-17 14:13:58 +02002211static int coroutine_fn v9fs_do_readdir_with_stat(V9fsPDU *pdu,
2212 V9fsFidState *fidp,
2213 uint32_t max_count)
Aneesh Kumar K.Vd208a0e2011-05-20 13:46:31 -07002214{
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +05302215 V9fsPath path;
Aneesh Kumar K.Vd208a0e2011-05-20 13:46:31 -07002216 V9fsStat v9stat;
2217 int len, err = 0;
2218 int32_t count = 0;
2219 struct stat stbuf;
2220 off_t saved_dir_pos;
Greg Kurz635324e2016-06-06 11:52:34 +02002221 struct dirent *dent;
Aneesh Kumar K.Vd208a0e2011-05-20 13:46:31 -07002222
2223 /* save the directory position */
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05302224 saved_dir_pos = v9fs_co_telldir(pdu, fidp);
Aneesh Kumar K.Vd208a0e2011-05-20 13:46:31 -07002225 if (saved_dir_pos < 0) {
2226 return saved_dir_pos;
2227 }
Harsh Prateek Bora5f524c12011-05-18 17:23:00 +05302228
Aneesh Kumar K.Vd208a0e2011-05-20 13:46:31 -07002229 while (1) {
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +05302230 v9fs_path_init(&path);
Greg Kurz7cde47d2016-06-06 11:52:34 +02002231
2232 v9fs_readdir_lock(&fidp->fs.dir);
2233
Greg Kurz635324e2016-06-06 11:52:34 +02002234 err = v9fs_co_readdir(pdu, fidp, &dent);
2235 if (err || !dent) {
Aneesh Kumar K.Vd208a0e2011-05-20 13:46:31 -07002236 break;
2237 }
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05302238 err = v9fs_co_name_to_path(pdu, &fidp->path, dent->d_name, &path);
Aneesh Kumar K.Vd208a0e2011-05-20 13:46:31 -07002239 if (err < 0) {
Greg Kurz8762a462016-06-06 11:52:34 +02002240 break;
Aneesh Kumar K.Vd208a0e2011-05-20 13:46:31 -07002241 }
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05302242 err = v9fs_co_lstat(pdu, &path, &stbuf);
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +05302243 if (err < 0) {
Greg Kurz8762a462016-06-06 11:52:34 +02002244 break;
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +05302245 }
Jan Dakinevich60695372017-09-20 08:48:51 +02002246 err = stat_to_v9stat(pdu, &path, dent->d_name, &stbuf, &v9stat);
Aneesh Kumar K.Vd208a0e2011-05-20 13:46:31 -07002247 if (err < 0) {
Greg Kurz8762a462016-06-06 11:52:34 +02002248 break;
Aneesh Kumar K.Vd208a0e2011-05-20 13:46:31 -07002249 }
Jan Dakinevich772a7362017-09-20 08:48:52 +02002250 if ((count + v9stat.size + 2) > max_count) {
2251 v9fs_readdir_unlock(&fidp->fs.dir);
Greg Kurz7cde47d2016-06-06 11:52:34 +02002252
Aneesh Kumar K.Vd208a0e2011-05-20 13:46:31 -07002253 /* Ran out of buffer. Set dir back to old position and return */
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05302254 v9fs_co_seekdir(pdu, fidp, saved_dir_pos);
Aneesh Kumar K.Vd208a0e2011-05-20 13:46:31 -07002255 v9fs_stat_free(&v9stat);
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +05302256 v9fs_path_free(&path);
Aneesh Kumar K.Vd208a0e2011-05-20 13:46:31 -07002257 return count;
2258 }
Jan Dakinevich772a7362017-09-20 08:48:52 +02002259
2260 /* 11 = 7 + 4 (7 = start offset, 4 = space for storing count) */
2261 len = pdu_marshal(pdu, 11 + count, "S", &v9stat);
2262
2263 v9fs_readdir_unlock(&fidp->fs.dir);
2264
2265 if (len < 0) {
2266 v9fs_co_seekdir(pdu, fidp, saved_dir_pos);
2267 v9fs_stat_free(&v9stat);
2268 v9fs_path_free(&path);
2269 return len;
2270 }
Aneesh Kumar K.Vd208a0e2011-05-20 13:46:31 -07002271 count += len;
2272 v9fs_stat_free(&v9stat);
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +05302273 v9fs_path_free(&path);
Aneesh Kumar K.Vd208a0e2011-05-20 13:46:31 -07002274 saved_dir_pos = dent->d_off;
2275 }
Greg Kurz8762a462016-06-06 11:52:34 +02002276
Greg Kurz7cde47d2016-06-06 11:52:34 +02002277 v9fs_readdir_unlock(&fidp->fs.dir);
2278
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +05302279 v9fs_path_free(&path);
Aneesh Kumar K.Vd208a0e2011-05-20 13:46:31 -07002280 if (err < 0) {
2281 return err;
2282 }
2283 return count;
Aneesh Kumar K.Vfa32ef82010-09-02 11:09:06 +05302284}
2285
Greg Kurz8440e222016-10-17 14:13:58 +02002286static void coroutine_fn v9fs_read(void *opaque)
Anthony Liguori9f107512010-04-29 17:44:44 +05302287{
Aneesh Kumar K.Vd208a0e2011-05-20 13:46:31 -07002288 int32_t fid;
Aneesh Kumar K.V2f008a82011-12-21 12:37:23 +05302289 uint64_t off;
Aneesh Kumar K.Vd208a0e2011-05-20 13:46:31 -07002290 ssize_t err = 0;
2291 int32_t count = 0;
2292 size_t offset = 7;
Aneesh Kumar K.V2f008a82011-12-21 12:37:23 +05302293 uint32_t max_count;
Aneesh Kumar K.Vd208a0e2011-05-20 13:46:31 -07002294 V9fsFidState *fidp;
Venkateswararao Jujjuri (JV)ff060302011-05-18 14:18:05 -07002295 V9fsPDU *pdu = opaque;
2296 V9fsState *s = pdu->s;
Anthony Liguoria9231552010-04-29 17:44:56 +05302297
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05302298 err = pdu_unmarshal(pdu, offset, "dqd", &fid, &off, &max_count);
2299 if (err < 0) {
2300 goto out_nofid;
2301 }
Harsh Prateek Borac572f232011-10-12 19:11:25 +05302302 trace_v9fs_read(pdu->tag, pdu->id, fid, off, max_count);
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05302303
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05302304 fidp = get_fid(pdu, fid);
Aneesh Kumar K.Vd208a0e2011-05-20 13:46:31 -07002305 if (fidp == NULL) {
Anthony Liguoria9231552010-04-29 17:44:56 +05302306 err = -EINVAL;
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05302307 goto out_nofid;
Anthony Liguori9f107512010-04-29 17:44:44 +05302308 }
Aneesh Kumar K.Vd208a0e2011-05-20 13:46:31 -07002309 if (fidp->fid_type == P9_FID_DIR) {
Christian Schoenebeckd2c5cf72020-07-29 10:39:12 +02002310 if (s->proto_version != V9FS_PROTO_2000U) {
2311 warn_report_once(
2312 "9p: bad client: T_read request on directory only expected "
2313 "with 9P2000.u protocol version"
2314 );
2315 err = -EOPNOTSUPP;
2316 goto out;
2317 }
Aneesh Kumar K.Vd208a0e2011-05-20 13:46:31 -07002318 if (off == 0) {
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05302319 v9fs_co_rewinddir(pdu, fidp);
Anthony Liguoria9231552010-04-29 17:44:56 +05302320 }
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05302321 count = v9fs_do_readdir_with_stat(pdu, fidp, max_count);
Aneesh Kumar K.Vd208a0e2011-05-20 13:46:31 -07002322 if (count < 0) {
2323 err = count;
2324 goto out;
2325 }
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05302326 err = pdu_marshal(pdu, offset, "d", count);
2327 if (err < 0) {
2328 goto out;
2329 }
2330 err += offset + count;
Aneesh Kumar K.Vd208a0e2011-05-20 13:46:31 -07002331 } else if (fidp->fid_type == P9_FID_FILE) {
Stefan Hajnoczi302a0d32011-12-21 12:37:22 +05302332 QEMUIOVector qiov_full;
2333 QEMUIOVector qiov;
Aneesh Kumar K.Vd208a0e2011-05-20 13:46:31 -07002334 int32_t len;
Aneesh Kumar K.Vd208a0e2011-05-20 13:46:31 -07002335
Stefano Stabellinicf451832020-05-21 12:26:25 -07002336 v9fs_init_qiov_from_pdu(&qiov_full, pdu, offset + 4, max_count, false);
Stefan Hajnoczi302a0d32011-12-21 12:37:22 +05302337 qemu_iovec_init(&qiov, qiov_full.niov);
Aneesh Kumar K.Vd208a0e2011-05-20 13:46:31 -07002338 do {
Stefan Hajnoczi302a0d32011-12-21 12:37:22 +05302339 qemu_iovec_reset(&qiov);
Michael Tokarev1b093c42012-03-12 21:28:06 +04002340 qemu_iovec_concat(&qiov, &qiov_full, count, qiov_full.size - count);
Aneesh Kumar K.Vd208a0e2011-05-20 13:46:31 -07002341 if (0) {
Stefan Hajnoczi302a0d32011-12-21 12:37:22 +05302342 print_sg(qiov.iov, qiov.niov);
Sanchit Garg56d15a52010-10-08 11:30:16 +05302343 }
Aneesh Kumar K.Vd208a0e2011-05-20 13:46:31 -07002344 /* Loop in case of EINTR */
2345 do {
Stefan Hajnoczi302a0d32011-12-21 12:37:22 +05302346 len = v9fs_co_preadv(pdu, fidp, qiov.iov, qiov.niov, off);
Aneesh Kumar K.Vd208a0e2011-05-20 13:46:31 -07002347 if (len >= 0) {
2348 off += len;
2349 count += len;
2350 }
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05302351 } while (len == -EINTR && !pdu->cancelled);
Aneesh Kumar K.Vd208a0e2011-05-20 13:46:31 -07002352 if (len < 0) {
2353 /* IO error return the error */
2354 err = len;
Li Qiange95c9a42016-10-17 14:13:58 +02002355 goto out_free_iovec;
Aneesh Kumar K.Vd208a0e2011-05-20 13:46:31 -07002356 }
Aneesh Kumar K.Vd208a0e2011-05-20 13:46:31 -07002357 } while (count < max_count && len > 0);
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05302358 err = pdu_marshal(pdu, offset, "d", count);
2359 if (err < 0) {
Li Qiange95c9a42016-10-17 14:13:58 +02002360 goto out_free_iovec;
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05302361 }
2362 err += offset + count;
Li Qiange95c9a42016-10-17 14:13:58 +02002363out_free_iovec:
Stefan Hajnoczi302a0d32011-12-21 12:37:22 +05302364 qemu_iovec_destroy(&qiov);
2365 qemu_iovec_destroy(&qiov_full);
Aneesh Kumar K.Vd208a0e2011-05-20 13:46:31 -07002366 } else if (fidp->fid_type == P9_FID_XATTR) {
2367 err = v9fs_xattr_read(s, pdu, fidp, off, max_count);
Anthony Liguoria9231552010-04-29 17:44:56 +05302368 } else {
2369 err = -EINVAL;
2370 }
Aneesh Kumar K.V7999f7e2011-10-24 15:09:49 +05302371 trace_v9fs_read_return(pdu->tag, pdu->id, count, err);
Anthony Liguoria9231552010-04-29 17:44:56 +05302372out:
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05302373 put_fid(pdu, fidp);
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05302374out_nofid:
Wei Liudc295f82015-12-02 15:00:14 +00002375 pdu_complete(pdu, err);
Anthony Liguori9f107512010-04-29 17:44:44 +05302376}
2377
Christian Schoenebeck29c9d2c2020-07-29 10:11:15 +02002378/**
2379 * Returns size required in Rreaddir response for the passed dirent @p name.
2380 *
2381 * @param name - directory entry's name (i.e. file name, directory name)
2382 * @returns required size in bytes
2383 */
2384size_t v9fs_readdir_response_size(V9fsString *name)
Sripathi Kodic18e2f92010-06-09 14:57:57 +05302385{
Aneesh Kumar K.V5e4eaa72011-05-18 15:57:17 -07002386 /*
2387 * Size of each dirent on the wire: size of qid (13) + size of offset (8)
2388 * size of type (1) + size of name.size (2) + strlen(name.data)
2389 */
2390 return 24 + v9fs_string_size(name);
Sripathi Kodic18e2f92010-06-09 14:57:57 +05302391}
2392
Christian Schoenebeck0c4356b2020-07-29 10:13:05 +02002393static void v9fs_free_dirents(struct V9fsDirEnt *e)
2394{
2395 struct V9fsDirEnt *next = NULL;
2396
2397 for (; e; e = next) {
2398 next = e->next;
2399 g_free(e->dent);
2400 g_free(e->st);
2401 g_free(e);
2402 }
2403}
2404
Greg Kurz8440e222016-10-17 14:13:58 +02002405static int coroutine_fn v9fs_do_readdir(V9fsPDU *pdu, V9fsFidState *fidp,
Christian Schoenebeck0c4356b2020-07-29 10:13:05 +02002406 off_t offset, int32_t max_count)
Sripathi Kodic18e2f92010-06-09 14:57:57 +05302407{
Sripathi Kodic18e2f92010-06-09 14:57:57 +05302408 size_t size;
Aneesh Kumar K.V5e4eaa72011-05-18 15:57:17 -07002409 V9fsQID qid;
2410 V9fsString name;
2411 int len, err = 0;
2412 int32_t count = 0;
Greg Kurz635324e2016-06-06 11:52:34 +02002413 struct dirent *dent;
Christian Schoenebeck0c4356b2020-07-29 10:13:05 +02002414 struct stat *st;
2415 struct V9fsDirEnt *entries = NULL;
Sripathi Kodic18e2f92010-06-09 14:57:57 +05302416
Christian Schoenebeck0c4356b2020-07-29 10:13:05 +02002417 /*
2418 * inode remapping requires the device id, which in turn might be
2419 * different for different directory entries, so if inode remapping is
2420 * enabled we have to make a full stat for each directory entry
2421 */
2422 const bool dostat = pdu->s->ctx.export_flags & V9FS_REMAP_INODES;
2423
2424 /*
2425 * Fetch all required directory entries altogether on a background IO
2426 * thread from fs driver. We don't want to do that for each entry
2427 * individually, because hopping between threads (this main IO thread
2428 * and background IO driver thread) would sum up to huge latencies.
2429 */
2430 count = v9fs_co_readdir_many(pdu, fidp, &entries, offset, max_count,
2431 dostat);
2432 if (count < 0) {
2433 err = count;
2434 count = 0;
2435 goto out;
Aneesh Kumar K.V5e4eaa72011-05-18 15:57:17 -07002436 }
Christian Schoenebeck0c4356b2020-07-29 10:13:05 +02002437 count = 0;
Harsh Prateek Bora5f524c12011-05-18 17:23:00 +05302438
Christian Schoenebeck0c4356b2020-07-29 10:13:05 +02002439 for (struct V9fsDirEnt *e = entries; e; e = e->next) {
2440 dent = e->dent;
Antonios Motakis1a6ed332019-10-10 11:36:05 +02002441
2442 if (pdu->s->ctx.export_flags & V9FS_REMAP_INODES) {
Christian Schoenebeck0c4356b2020-07-29 10:13:05 +02002443 st = e->st;
2444 /* e->st should never be NULL, but just to be sure */
2445 if (!st) {
2446 err = -1;
2447 break;
2448 }
2449
2450 /* remap inode */
2451 err = stat_to_qid(pdu, st, &qid);
Antonios Motakis1a6ed332019-10-10 11:36:05 +02002452 if (err < 0) {
Christian Schoenebeck0c4356b2020-07-29 10:13:05 +02002453 break;
Antonios Motakis1a6ed332019-10-10 11:36:05 +02002454 }
2455 } else {
2456 /*
2457 * Fill up just the path field of qid because the client uses
2458 * only that. To fill the entire qid structure we will have
2459 * to stat each dirent found, which is expensive. For the
Christian Schoenebeck0c4356b2020-07-29 10:13:05 +02002460 * latter reason we don't call stat_to_qid() here. Only drawback
Antonios Motakis1a6ed332019-10-10 11:36:05 +02002461 * is that no multi-device export detection of stat_to_qid()
2462 * would be done and provided as error to the user here. But
2463 * user would get that error anyway when accessing those
2464 * files/dirs through other ways.
2465 */
2466 size = MIN(sizeof(dent->d_ino), sizeof(qid.path));
2467 memcpy(&qid.path, &dent->d_ino, size);
2468 /* Fill the other fields with dummy values */
2469 qid.type = 0;
2470 qid.version = 0;
2471 }
Sripathi Kodic18e2f92010-06-09 14:57:57 +05302472
Christian Schoenebeck0c4356b2020-07-29 10:13:05 +02002473 v9fs_string_init(&name);
2474 v9fs_string_sprintf(&name, "%s", dent->d_name);
2475
Aneesh Kumar K.V5e4eaa72011-05-18 15:57:17 -07002476 /* 11 = 7 + 4 (7 = start offset, 4 = space for storing count) */
2477 len = pdu_marshal(pdu, 11 + count, "Qqbs",
2478 &qid, dent->d_off,
2479 dent->d_type, &name);
Greg Kurz7cde47d2016-06-06 11:52:34 +02002480
Christian Schoenebeck0c4356b2020-07-29 10:13:05 +02002481 v9fs_string_free(&name);
Greg Kurz7cde47d2016-06-06 11:52:34 +02002482
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05302483 if (len < 0) {
Christian Schoenebeck0c4356b2020-07-29 10:13:05 +02002484 err = len;
2485 break;
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05302486 }
Christian Schoenebeck0c4356b2020-07-29 10:13:05 +02002487
Aneesh Kumar K.V5e4eaa72011-05-18 15:57:17 -07002488 count += len;
Sripathi Kodic18e2f92010-06-09 14:57:57 +05302489 }
Greg Kurz7cde47d2016-06-06 11:52:34 +02002490
Christian Schoenebeck0c4356b2020-07-29 10:13:05 +02002491out:
2492 v9fs_free_dirents(entries);
Aneesh Kumar K.V5e4eaa72011-05-18 15:57:17 -07002493 if (err < 0) {
2494 return err;
2495 }
2496 return count;
Sripathi Kodic18e2f92010-06-09 14:57:57 +05302497}
2498
Greg Kurz8440e222016-10-17 14:13:58 +02002499static void coroutine_fn v9fs_readdir(void *opaque)
Sripathi Kodic18e2f92010-06-09 14:57:57 +05302500{
Aneesh Kumar K.V5e4eaa72011-05-18 15:57:17 -07002501 int32_t fid;
2502 V9fsFidState *fidp;
2503 ssize_t retval = 0;
2504 size_t offset = 7;
Aneesh Kumar K.V2f008a82011-12-21 12:37:23 +05302505 uint64_t initial_offset;
2506 int32_t count;
2507 uint32_t max_count;
Venkateswararao Jujjuri (JV)ff060302011-05-18 14:18:05 -07002508 V9fsPDU *pdu = opaque;
Christian Schoenebeckd36a5c22020-02-08 09:24:19 +01002509 V9fsState *s = pdu->s;
Sripathi Kodic18e2f92010-06-09 14:57:57 +05302510
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05302511 retval = pdu_unmarshal(pdu, offset, "dqd", &fid,
2512 &initial_offset, &max_count);
2513 if (retval < 0) {
2514 goto out_nofid;
2515 }
Harsh Prateek Borac572f232011-10-12 19:11:25 +05302516 trace_v9fs_readdir(pdu->tag, pdu->id, fid, initial_offset, max_count);
2517
Christian Schoenebeckd36a5c22020-02-08 09:24:19 +01002518 /* Enough space for a R_readdir header: size[4] Rreaddir tag[2] count[4] */
2519 if (max_count > s->msize - 11) {
2520 max_count = s->msize - 11;
2521 warn_report_once(
2522 "9p: bad client: T_readdir with count > msize - 11"
2523 );
2524 }
2525
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05302526 fidp = get_fid(pdu, fid);
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05302527 if (fidp == NULL) {
2528 retval = -EINVAL;
2529 goto out_nofid;
2530 }
Greg Kurzf314ea42016-06-06 11:52:34 +02002531 if (!fidp->fs.dir.stream) {
Aneesh Kumar K.V5e4eaa72011-05-18 15:57:17 -07002532 retval = -EINVAL;
Sripathi Kodic18e2f92010-06-09 14:57:57 +05302533 goto out;
2534 }
Christian Schoenebeckd2c5cf72020-07-29 10:39:12 +02002535 if (s->proto_version != V9FS_PROTO_2000L) {
2536 warn_report_once(
2537 "9p: bad client: T_readdir request only expected with 9P2000.L "
2538 "protocol version"
2539 );
2540 retval = -EOPNOTSUPP;
2541 goto out;
2542 }
Christian Schoenebeck0c4356b2020-07-29 10:13:05 +02002543 count = v9fs_do_readdir(pdu, fidp, (off_t) initial_offset, max_count);
Aneesh Kumar K.V5e4eaa72011-05-18 15:57:17 -07002544 if (count < 0) {
2545 retval = count;
2546 goto out;
2547 }
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05302548 retval = pdu_marshal(pdu, offset, "d", count);
2549 if (retval < 0) {
2550 goto out;
2551 }
2552 retval += count + offset;
Aneesh Kumar K.V7999f7e2011-10-24 15:09:49 +05302553 trace_v9fs_readdir_return(pdu->tag, pdu->id, count, retval);
Sripathi Kodic18e2f92010-06-09 14:57:57 +05302554out:
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05302555 put_fid(pdu, fidp);
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05302556out_nofid:
Wei Liudc295f82015-12-02 15:00:14 +00002557 pdu_complete(pdu, retval);
Sripathi Kodic18e2f92010-06-09 14:57:57 +05302558}
2559
Aneesh Kumar K.Vd7a90492011-05-08 12:29:31 +05302560static int v9fs_xattr_write(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp,
Aneesh Kumar K.V2f008a82011-12-21 12:37:23 +05302561 uint64_t off, uint32_t count,
Aneesh Kumar K.Vd7a90492011-05-08 12:29:31 +05302562 struct iovec *sg, int cnt)
Aneesh Kumar K.V10b468b2010-09-02 11:09:07 +05302563{
2564 int i, to_copy;
2565 ssize_t err = 0;
Li Qiang7e55d652016-11-01 12:00:40 +01002566 uint64_t write_count;
Aneesh Kumar K.Vd7a90492011-05-08 12:29:31 +05302567 size_t offset = 7;
Aneesh Kumar K.V10b468b2010-09-02 11:09:07 +05302568
Aneesh Kumar K.Vd7a90492011-05-08 12:29:31 +05302569
Li Qiang7e55d652016-11-01 12:00:40 +01002570 if (fidp->fs.xattr.len < off) {
Daniel Henrique Barbozab858e802020-01-20 15:11:39 +01002571 return -ENOSPC;
Aneesh Kumar K.V10b468b2010-09-02 11:09:07 +05302572 }
Li Qiang7e55d652016-11-01 12:00:40 +01002573 write_count = fidp->fs.xattr.len - off;
2574 if (write_count > count) {
2575 write_count = count;
2576 }
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05302577 err = pdu_marshal(pdu, offset, "d", write_count);
2578 if (err < 0) {
2579 return err;
2580 }
2581 err += offset;
Aneesh Kumar K.Vd7a90492011-05-08 12:29:31 +05302582 fidp->fs.xattr.copied_len += write_count;
Aneesh Kumar K.V10b468b2010-09-02 11:09:07 +05302583 /*
2584 * Now copy the content from sg list
2585 */
Aneesh Kumar K.Vd7a90492011-05-08 12:29:31 +05302586 for (i = 0; i < cnt; i++) {
2587 if (write_count > sg[i].iov_len) {
2588 to_copy = sg[i].iov_len;
Aneesh Kumar K.V10b468b2010-09-02 11:09:07 +05302589 } else {
2590 to_copy = write_count;
2591 }
Aneesh Kumar K.Vd7a90492011-05-08 12:29:31 +05302592 memcpy((char *)fidp->fs.xattr.value + off, sg[i].iov_base, to_copy);
Aneesh Kumar K.V10b468b2010-09-02 11:09:07 +05302593 /* updating vs->off since we are not using below */
Aneesh Kumar K.Vd7a90492011-05-08 12:29:31 +05302594 off += to_copy;
Aneesh Kumar K.V10b468b2010-09-02 11:09:07 +05302595 write_count -= to_copy;
2596 }
Daniel Henrique Barbozab858e802020-01-20 15:11:39 +01002597
Aneesh Kumar K.Vd7a90492011-05-08 12:29:31 +05302598 return err;
Aneesh Kumar K.V10b468b2010-09-02 11:09:07 +05302599}
2600
Greg Kurz8440e222016-10-17 14:13:58 +02002601static void coroutine_fn v9fs_write(void *opaque)
Anthony Liguori9f107512010-04-29 17:44:44 +05302602{
Aneesh Kumar K.Vd7a90492011-05-08 12:29:31 +05302603 ssize_t err;
2604 int32_t fid;
Aneesh Kumar K.V2f008a82011-12-21 12:37:23 +05302605 uint64_t off;
2606 uint32_t count;
Aneesh Kumar K.Vd7a90492011-05-08 12:29:31 +05302607 int32_t len = 0;
2608 int32_t total = 0;
2609 size_t offset = 7;
2610 V9fsFidState *fidp;
Venkateswararao Jujjuri (JV)ff060302011-05-18 14:18:05 -07002611 V9fsPDU *pdu = opaque;
2612 V9fsState *s = pdu->s;
Stefan Hajnoczi302a0d32011-12-21 12:37:22 +05302613 QEMUIOVector qiov_full;
2614 QEMUIOVector qiov;
Anthony Liguori84493602010-04-29 17:44:58 +05302615
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05302616 err = pdu_unmarshal(pdu, offset, "dqd", &fid, &off, &count);
2617 if (err < 0) {
Wei Liudc295f82015-12-02 15:00:14 +00002618 pdu_complete(pdu, err);
Stefan Weil0289a412015-03-08 19:17:54 +01002619 return;
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05302620 }
2621 offset += err;
Stefano Stabellinicf451832020-05-21 12:26:25 -07002622 v9fs_init_qiov_from_pdu(&qiov_full, pdu, offset, count, true);
Stefan Hajnoczi302a0d32011-12-21 12:37:22 +05302623 trace_v9fs_write(pdu->tag, pdu->id, fid, off, count, qiov_full.niov);
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05302624
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05302625 fidp = get_fid(pdu, fid);
Aneesh Kumar K.Vd7a90492011-05-08 12:29:31 +05302626 if (fidp == NULL) {
Anthony Liguori84493602010-04-29 17:44:58 +05302627 err = -EINVAL;
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05302628 goto out_nofid;
Anthony Liguori9f107512010-04-29 17:44:44 +05302629 }
Aneesh Kumar K.Vd7a90492011-05-08 12:29:31 +05302630 if (fidp->fid_type == P9_FID_FILE) {
2631 if (fidp->fs.fd == -1) {
Aneesh Kumar K.V10b468b2010-09-02 11:09:07 +05302632 err = -EINVAL;
2633 goto out;
2634 }
Aneesh Kumar K.Vd7a90492011-05-08 12:29:31 +05302635 } else if (fidp->fid_type == P9_FID_XATTR) {
Aneesh Kumar K.V10b468b2010-09-02 11:09:07 +05302636 /*
2637 * setxattr operation
2638 */
Stefan Hajnoczi302a0d32011-12-21 12:37:22 +05302639 err = v9fs_xattr_write(s, pdu, fidp, off, count,
2640 qiov_full.iov, qiov_full.niov);
Aneesh Kumar K.Vd7a90492011-05-08 12:29:31 +05302641 goto out;
Aneesh Kumar K.V10b468b2010-09-02 11:09:07 +05302642 } else {
Anthony Liguori84493602010-04-29 17:44:58 +05302643 err = -EINVAL;
2644 goto out;
2645 }
Stefan Hajnoczi302a0d32011-12-21 12:37:22 +05302646 qemu_iovec_init(&qiov, qiov_full.niov);
Aneesh Kumar K.Vd7a90492011-05-08 12:29:31 +05302647 do {
Stefan Hajnoczi302a0d32011-12-21 12:37:22 +05302648 qemu_iovec_reset(&qiov);
Michael Tokarev1b093c42012-03-12 21:28:06 +04002649 qemu_iovec_concat(&qiov, &qiov_full, total, qiov_full.size - total);
Aneesh Kumar K.Vd7a90492011-05-08 12:29:31 +05302650 if (0) {
Stefan Hajnoczi302a0d32011-12-21 12:37:22 +05302651 print_sg(qiov.iov, qiov.niov);
Sanchit Garg56d15a52010-10-08 11:30:16 +05302652 }
Aneesh Kumar K.Vd7a90492011-05-08 12:29:31 +05302653 /* Loop in case of EINTR */
2654 do {
Stefan Hajnoczi302a0d32011-12-21 12:37:22 +05302655 len = v9fs_co_pwritev(pdu, fidp, qiov.iov, qiov.niov, off);
Aneesh Kumar K.Vd7a90492011-05-08 12:29:31 +05302656 if (len >= 0) {
2657 off += len;
2658 total += len;
2659 }
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05302660 } while (len == -EINTR && !pdu->cancelled);
Aneesh Kumar K.Vd7a90492011-05-08 12:29:31 +05302661 if (len < 0) {
2662 /* IO error return the error */
2663 err = len;
Stefan Hajnoczi302a0d32011-12-21 12:37:22 +05302664 goto out_qiov;
Aneesh Kumar K.Vd7a90492011-05-08 12:29:31 +05302665 }
Aneesh Kumar K.Vd7a90492011-05-08 12:29:31 +05302666 } while (total < count && len > 0);
Stefan Hajnoczi302a0d32011-12-21 12:37:22 +05302667
2668 offset = 7;
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05302669 err = pdu_marshal(pdu, offset, "d", total);
2670 if (err < 0) {
Li Qiangfdfcc9a2016-10-17 14:13:58 +02002671 goto out_qiov;
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05302672 }
2673 err += offset;
Aneesh Kumar K.V7999f7e2011-10-24 15:09:49 +05302674 trace_v9fs_write_return(pdu->tag, pdu->id, total, err);
Stefan Hajnoczi302a0d32011-12-21 12:37:22 +05302675out_qiov:
2676 qemu_iovec_destroy(&qiov);
Anthony Liguori84493602010-04-29 17:44:58 +05302677out:
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05302678 put_fid(pdu, fidp);
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05302679out_nofid:
Stefan Hajnoczi302a0d32011-12-21 12:37:22 +05302680 qemu_iovec_destroy(&qiov_full);
Wei Liudc295f82015-12-02 15:00:14 +00002681 pdu_complete(pdu, err);
Anthony Liguori9f107512010-04-29 17:44:44 +05302682}
2683
Greg Kurz8440e222016-10-17 14:13:58 +02002684static void coroutine_fn v9fs_create(void *opaque)
M. Mohan Kumar5e94c102010-06-09 19:14:28 +05302685{
Venkateswararao Jujjuribaaa86d2011-08-08 23:56:50 +05302686 int32_t fid;
2687 int err = 0;
2688 size_t offset = 7;
2689 V9fsFidState *fidp;
2690 V9fsQID qid;
2691 int32_t perm;
2692 int8_t mode;
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +05302693 V9fsPath path;
Venkateswararao Jujjuribaaa86d2011-08-08 23:56:50 +05302694 struct stat stbuf;
2695 V9fsString name;
2696 V9fsString extension;
Venkateswararao Jujjuribaaa86d2011-08-08 23:56:50 +05302697 int iounit;
2698 V9fsPDU *pdu = opaque;
Greg Kurz5b3c77a2018-11-20 13:00:35 +01002699 V9fsState *s = pdu->s;
M. Mohan Kumar5e94c102010-06-09 19:14:28 +05302700
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +05302701 v9fs_path_init(&path);
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05302702 v9fs_string_init(&name);
2703 v9fs_string_init(&extension);
2704 err = pdu_unmarshal(pdu, offset, "dsdbs", &fid, &name,
2705 &perm, &mode, &extension);
2706 if (err < 0) {
2707 goto out_nofid;
2708 }
Harsh Prateek Borac572f232011-10-12 19:11:25 +05302709 trace_v9fs_create(pdu->tag, pdu->id, fid, name.data, perm, mode);
2710
Greg Kurzfff39a72016-08-30 19:11:05 +02002711 if (name_is_illegal(name.data)) {
2712 err = -ENOENT;
2713 goto out_nofid;
2714 }
2715
Greg Kurz805b5d92016-08-30 19:13:11 +02002716 if (!strcmp(".", name.data) || !strcmp("..", name.data)) {
2717 err = -EEXIST;
2718 goto out_nofid;
2719 }
2720
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05302721 fidp = get_fid(pdu, fid);
Venkateswararao Jujjuribaaa86d2011-08-08 23:56:50 +05302722 if (fidp == NULL) {
2723 err = -EINVAL;
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05302724 goto out_nofid;
Anthony Liguoric494dd62010-04-29 17:44:59 +05302725 }
Li Qiangd63fb192017-03-27 21:13:19 +02002726 if (fidp->fid_type != P9_FID_NONE) {
2727 err = -EINVAL;
2728 goto out;
2729 }
Venkateswararao Jujjuribaaa86d2011-08-08 23:56:50 +05302730 if (perm & P9_STAT_MODE_DIR) {
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05302731 err = v9fs_co_mkdir(pdu, fidp, &name, perm & 0777,
Aneesh Kumar K.V02cb7f32011-05-24 15:10:56 +05302732 fidp->uid, -1, &stbuf);
Venkateswararao Jujjuribaaa86d2011-08-08 23:56:50 +05302733 if (err < 0) {
2734 goto out;
Anthony Liguoric494dd62010-04-29 17:44:59 +05302735 }
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05302736 err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +05302737 if (err < 0) {
2738 goto out;
2739 }
Greg Kurz5b3c77a2018-11-20 13:00:35 +01002740 v9fs_path_write_lock(s);
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +05302741 v9fs_path_copy(&fidp->path, &path);
Greg Kurz5b3c77a2018-11-20 13:00:35 +01002742 v9fs_path_unlock(s);
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05302743 err = v9fs_co_opendir(pdu, fidp);
Venkateswararao Jujjuribaaa86d2011-08-08 23:56:50 +05302744 if (err < 0) {
2745 goto out;
2746 }
2747 fidp->fid_type = P9_FID_DIR;
2748 } else if (perm & P9_STAT_MODE_SYMLINK) {
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05302749 err = v9fs_co_symlink(pdu, fidp, &name,
Aneesh Kumar K.V02cb7f32011-05-24 15:10:56 +05302750 extension.data, -1 , &stbuf);
Venkateswararao Jujjuribaaa86d2011-08-08 23:56:50 +05302751 if (err < 0) {
Venkateswararao Jujjuribaaa86d2011-08-08 23:56:50 +05302752 goto out;
2753 }
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05302754 err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
Venkateswararao Jujjuribaaa86d2011-08-08 23:56:50 +05302755 if (err < 0) {
Venkateswararao Jujjuribaaa86d2011-08-08 23:56:50 +05302756 goto out;
2757 }
Greg Kurz5b3c77a2018-11-20 13:00:35 +01002758 v9fs_path_write_lock(s);
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +05302759 v9fs_path_copy(&fidp->path, &path);
Greg Kurz5b3c77a2018-11-20 13:00:35 +01002760 v9fs_path_unlock(s);
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +05302761 } else if (perm & P9_STAT_MODE_LINK) {
2762 int32_t ofid = atoi(extension.data);
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05302763 V9fsFidState *ofidp = get_fid(pdu, ofid);
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +05302764 if (ofidp == NULL) {
2765 err = -EINVAL;
2766 goto out;
2767 }
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05302768 err = v9fs_co_link(pdu, ofidp, fidp, &name);
2769 put_fid(pdu, ofidp);
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +05302770 if (err < 0) {
2771 goto out;
2772 }
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05302773 err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +05302774 if (err < 0) {
2775 fidp->fid_type = P9_FID_NONE;
2776 goto out;
2777 }
Greg Kurz5b3c77a2018-11-20 13:00:35 +01002778 v9fs_path_write_lock(s);
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +05302779 v9fs_path_copy(&fidp->path, &path);
Greg Kurz5b3c77a2018-11-20 13:00:35 +01002780 v9fs_path_unlock(s);
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05302781 err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
Aneesh Kumar K.V02cb7f32011-05-24 15:10:56 +05302782 if (err < 0) {
2783 fidp->fid_type = P9_FID_NONE;
2784 goto out;
2785 }
Venkateswararao Jujjuribaaa86d2011-08-08 23:56:50 +05302786 } else if (perm & P9_STAT_MODE_DEVICE) {
Anthony Liguoric494dd62010-04-29 17:44:59 +05302787 char ctype;
2788 uint32_t major, minor;
2789 mode_t nmode = 0;
2790
Venkateswararao Jujjuribaaa86d2011-08-08 23:56:50 +05302791 if (sscanf(extension.data, "%c %u %u", &ctype, &major, &minor) != 3) {
Anthony Liguoric494dd62010-04-29 17:44:59 +05302792 err = -errno;
Venkateswararao Jujjuribaaa86d2011-08-08 23:56:50 +05302793 goto out;
Anthony Liguoric494dd62010-04-29 17:44:59 +05302794 }
2795
2796 switch (ctype) {
2797 case 'c':
2798 nmode = S_IFCHR;
2799 break;
2800 case 'b':
2801 nmode = S_IFBLK;
2802 break;
2803 default:
2804 err = -EIO;
Venkateswararao Jujjuribaaa86d2011-08-08 23:56:50 +05302805 goto out;
Anthony Liguoric494dd62010-04-29 17:44:59 +05302806 }
2807
Venkateswararao Jujjuribaaa86d2011-08-08 23:56:50 +05302808 nmode |= perm & 0777;
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05302809 err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, -1,
Aneesh Kumar K.V02cb7f32011-05-24 15:10:56 +05302810 makedev(major, minor), nmode, &stbuf);
Venkateswararao Jujjuribaaa86d2011-08-08 23:56:50 +05302811 if (err < 0) {
2812 goto out;
2813 }
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05302814 err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +05302815 if (err < 0) {
2816 goto out;
2817 }
Greg Kurz5b3c77a2018-11-20 13:00:35 +01002818 v9fs_path_write_lock(s);
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +05302819 v9fs_path_copy(&fidp->path, &path);
Greg Kurz5b3c77a2018-11-20 13:00:35 +01002820 v9fs_path_unlock(s);
Venkateswararao Jujjuribaaa86d2011-08-08 23:56:50 +05302821 } else if (perm & P9_STAT_MODE_NAMED_PIPE) {
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05302822 err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, -1,
Aneesh Kumar K.V02cb7f32011-05-24 15:10:56 +05302823 0, S_IFIFO | (perm & 0777), &stbuf);
Venkateswararao Jujjuribaaa86d2011-08-08 23:56:50 +05302824 if (err < 0) {
2825 goto out;
2826 }
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05302827 err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +05302828 if (err < 0) {
2829 goto out;
2830 }
Greg Kurz5b3c77a2018-11-20 13:00:35 +01002831 v9fs_path_write_lock(s);
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +05302832 v9fs_path_copy(&fidp->path, &path);
Greg Kurz5b3c77a2018-11-20 13:00:35 +01002833 v9fs_path_unlock(s);
Venkateswararao Jujjuribaaa86d2011-08-08 23:56:50 +05302834 } else if (perm & P9_STAT_MODE_SOCKET) {
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05302835 err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, -1,
Aneesh Kumar K.V02cb7f32011-05-24 15:10:56 +05302836 0, S_IFSOCK | (perm & 0777), &stbuf);
Venkateswararao Jujjuribaaa86d2011-08-08 23:56:50 +05302837 if (err < 0) {
2838 goto out;
2839 }
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05302840 err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +05302841 if (err < 0) {
2842 goto out;
2843 }
Greg Kurz5b3c77a2018-11-20 13:00:35 +01002844 v9fs_path_write_lock(s);
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +05302845 v9fs_path_copy(&fidp->path, &path);
Greg Kurz5b3c77a2018-11-20 13:00:35 +01002846 v9fs_path_unlock(s);
Anthony Liguoric494dd62010-04-29 17:44:59 +05302847 } else {
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05302848 err = v9fs_co_open2(pdu, fidp, &name, -1,
Xinhao Zhang01011732020-10-30 12:35:13 +08002849 omode_to_uflags(mode) | O_CREAT, perm, &stbuf);
Venkateswararao Jujjuribaaa86d2011-08-08 23:56:50 +05302850 if (err < 0) {
2851 goto out;
2852 }
2853 fidp->fid_type = P9_FID_FILE;
Aneesh Kumar K.V7a462742011-05-18 15:40:57 +05302854 fidp->open_flags = omode_to_uflags(mode);
2855 if (fidp->open_flags & O_EXCL) {
2856 /*
2857 * We let the host file system do O_EXCL check
2858 * We should not reclaim such fd
2859 */
2860 fidp->flags |= FID_NON_RECLAIMABLE;
2861 }
Anthony Liguoric494dd62010-04-29 17:44:59 +05302862 }
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05302863 iounit = get_iounit(pdu, &fidp->path);
Antonios Motakis3b5ee9e2019-10-10 11:36:05 +02002864 err = stat_to_qid(pdu, &stbuf, &qid);
2865 if (err < 0) {
2866 goto out;
2867 }
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05302868 err = pdu_marshal(pdu, offset, "Qd", &qid, iounit);
2869 if (err < 0) {
2870 goto out;
2871 }
2872 err += offset;
Aneesh Kumar K.V7999f7e2011-10-24 15:09:49 +05302873 trace_v9fs_create_return(pdu->tag, pdu->id,
2874 qid.type, qid.version, qid.path, iounit);
Anthony Liguoric494dd62010-04-29 17:44:59 +05302875out:
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05302876 put_fid(pdu, fidp);
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05302877out_nofid:
Wei Liudc295f82015-12-02 15:00:14 +00002878 pdu_complete(pdu, err);
Venkateswararao Jujjuribaaa86d2011-08-08 23:56:50 +05302879 v9fs_string_free(&name);
2880 v9fs_string_free(&extension);
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +05302881 v9fs_path_free(&path);
Anthony Liguori9f107512010-04-29 17:44:44 +05302882}
2883
Greg Kurz8440e222016-10-17 14:13:58 +02002884static void coroutine_fn v9fs_symlink(void *opaque)
Venkateswararao Jujjuri (JV)08c60fc2010-06-09 14:02:08 -07002885{
Venkateswararao Jujjuri (JV)ff060302011-05-18 14:18:05 -07002886 V9fsPDU *pdu = opaque;
Venkateswararao Jujjuri3fa2a8d2011-08-09 00:00:01 +05302887 V9fsString name;
2888 V9fsString symname;
Venkateswararao Jujjuri3fa2a8d2011-08-09 00:00:01 +05302889 V9fsFidState *dfidp;
2890 V9fsQID qid;
2891 struct stat stbuf;
Venkateswararao Jujjuri (JV)08c60fc2010-06-09 14:02:08 -07002892 int32_t dfid;
Venkateswararao Jujjuri (JV)08c60fc2010-06-09 14:02:08 -07002893 int err = 0;
2894 gid_t gid;
Venkateswararao Jujjuri3fa2a8d2011-08-09 00:00:01 +05302895 size_t offset = 7;
Venkateswararao Jujjuri (JV)08c60fc2010-06-09 14:02:08 -07002896
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05302897 v9fs_string_init(&name);
2898 v9fs_string_init(&symname);
2899 err = pdu_unmarshal(pdu, offset, "dssd", &dfid, &name, &symname, &gid);
2900 if (err < 0) {
2901 goto out_nofid;
2902 }
Harsh Prateek Borac572f232011-10-12 19:11:25 +05302903 trace_v9fs_symlink(pdu->tag, pdu->id, dfid, name.data, symname.data, gid);
Venkateswararao Jujjuri (JV)08c60fc2010-06-09 14:02:08 -07002904
Greg Kurzfff39a72016-08-30 19:11:05 +02002905 if (name_is_illegal(name.data)) {
2906 err = -ENOENT;
2907 goto out_nofid;
2908 }
2909
Greg Kurz805b5d92016-08-30 19:13:11 +02002910 if (!strcmp(".", name.data) || !strcmp("..", name.data)) {
2911 err = -EEXIST;
2912 goto out_nofid;
2913 }
2914
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05302915 dfidp = get_fid(pdu, dfid);
Venkateswararao Jujjuri3fa2a8d2011-08-09 00:00:01 +05302916 if (dfidp == NULL) {
Venkateswararao Jujjuri (JV)08c60fc2010-06-09 14:02:08 -07002917 err = -EINVAL;
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05302918 goto out_nofid;
Venkateswararao Jujjuri (JV)08c60fc2010-06-09 14:02:08 -07002919 }
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05302920 err = v9fs_co_symlink(pdu, dfidp, &name, symname.data, gid, &stbuf);
Venkateswararao Jujjuri3fa2a8d2011-08-09 00:00:01 +05302921 if (err < 0) {
2922 goto out;
2923 }
Antonios Motakis3b5ee9e2019-10-10 11:36:05 +02002924 err = stat_to_qid(pdu, &stbuf, &qid);
2925 if (err < 0) {
2926 goto out;
2927 }
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05302928 err = pdu_marshal(pdu, offset, "Q", &qid);
2929 if (err < 0) {
2930 goto out;
2931 }
2932 err += offset;
Aneesh Kumar K.V7999f7e2011-10-24 15:09:49 +05302933 trace_v9fs_symlink_return(pdu->tag, pdu->id,
2934 qid.type, qid.version, qid.path);
Venkateswararao Jujjuri (JV)08c60fc2010-06-09 14:02:08 -07002935out:
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05302936 put_fid(pdu, dfidp);
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05302937out_nofid:
Wei Liudc295f82015-12-02 15:00:14 +00002938 pdu_complete(pdu, err);
Venkateswararao Jujjuri3fa2a8d2011-08-09 00:00:01 +05302939 v9fs_string_free(&name);
2940 v9fs_string_free(&symname);
Venkateswararao Jujjuri (JV)08c60fc2010-06-09 14:02:08 -07002941}
2942
Greg Kurza1bf8b72016-11-25 12:54:21 +01002943static void coroutine_fn v9fs_flush(void *opaque)
Anthony Liguori9f107512010-04-29 17:44:44 +05302944{
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05302945 ssize_t err;
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05302946 int16_t tag;
2947 size_t offset = 7;
Greg Kurzd5f2af72017-03-21 09:12:47 +01002948 V9fsPDU *cancel_pdu = NULL;
Venkateswararao Jujjuri (JV)ff060302011-05-18 14:18:05 -07002949 V9fsPDU *pdu = opaque;
2950 V9fsState *s = pdu->s;
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05302951
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05302952 err = pdu_unmarshal(pdu, offset, "w", &tag);
2953 if (err < 0) {
Wei Liudc295f82015-12-02 15:00:14 +00002954 pdu_complete(pdu, err);
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05302955 return;
2956 }
Harsh Prateek Borac572f232011-10-12 19:11:25 +05302957 trace_v9fs_flush(pdu->tag, pdu->id, tag);
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05302958
Greg Kurzd5f2af72017-03-21 09:12:47 +01002959 if (pdu->tag == tag) {
Alistair Francis3dc6f862017-07-12 06:57:41 -07002960 warn_report("the guest sent a self-referencing 9P flush request");
Greg Kurzd5f2af72017-03-21 09:12:47 +01002961 } else {
2962 QLIST_FOREACH(cancel_pdu, &s->active_list, next) {
2963 if (cancel_pdu->tag == tag) {
2964 break;
2965 }
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05302966 }
2967 }
2968 if (cancel_pdu) {
2969 cancel_pdu->cancelled = 1;
2970 /*
2971 * Wait for pdu to complete.
2972 */
Paolo Bonzini1ace7ce2017-02-13 19:12:43 +01002973 qemu_co_queue_wait(&cancel_pdu->complete, NULL);
Greg Kurz18adde82017-04-04 18:06:01 +02002974 if (!qemu_co_queue_next(&cancel_pdu->complete)) {
2975 cancel_pdu->cancelled = 0;
2976 pdu_free(cancel_pdu);
2977 }
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05302978 }
Wei Liudc295f82015-12-02 15:00:14 +00002979 pdu_complete(pdu, 7);
Anthony Liguori9f107512010-04-29 17:44:44 +05302980}
2981
Greg Kurz8440e222016-10-17 14:13:58 +02002982static void coroutine_fn v9fs_link(void *opaque)
Venkateswararao Jujjuri (JV)b2c224b2010-06-09 11:21:15 -07002983{
Venkateswararao Jujjuri (JV)ff060302011-05-18 14:18:05 -07002984 V9fsPDU *pdu = opaque;
Venkateswararao Jujjuri (JV)b2c224b2010-06-09 11:21:15 -07002985 int32_t dfid, oldfid;
2986 V9fsFidState *dfidp, *oldfidp;
Dong Xu Wang3a931132011-11-29 16:52:38 +08002987 V9fsString name;
Venkateswararao Jujjuri (JV)b2c224b2010-06-09 11:21:15 -07002988 size_t offset = 7;
2989 int err = 0;
2990
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05302991 v9fs_string_init(&name);
2992 err = pdu_unmarshal(pdu, offset, "dds", &dfid, &oldfid, &name);
2993 if (err < 0) {
2994 goto out_nofid;
2995 }
Harsh Prateek Borac572f232011-10-12 19:11:25 +05302996 trace_v9fs_link(pdu->tag, pdu->id, dfid, oldfid, name.data);
Venkateswararao Jujjuri (JV)b2c224b2010-06-09 11:21:15 -07002997
Greg Kurzfff39a72016-08-30 19:11:05 +02002998 if (name_is_illegal(name.data)) {
2999 err = -ENOENT;
3000 goto out_nofid;
3001 }
3002
Greg Kurz805b5d92016-08-30 19:13:11 +02003003 if (!strcmp(".", name.data) || !strcmp("..", name.data)) {
3004 err = -EEXIST;
3005 goto out_nofid;
3006 }
3007
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303008 dfidp = get_fid(pdu, dfid);
Venkateswararao Jujjuri (JV)b2c224b2010-06-09 11:21:15 -07003009 if (dfidp == NULL) {
Venkateswararao Jujjuri (JV)ffd66872011-05-09 11:47:28 -07003010 err = -ENOENT;
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05303011 goto out_nofid;
Venkateswararao Jujjuri (JV)b2c224b2010-06-09 11:21:15 -07003012 }
3013
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303014 oldfidp = get_fid(pdu, oldfid);
Venkateswararao Jujjuri (JV)b2c224b2010-06-09 11:21:15 -07003015 if (oldfidp == NULL) {
Venkateswararao Jujjuri (JV)ffd66872011-05-09 11:47:28 -07003016 err = -ENOENT;
Venkateswararao Jujjuri (JV)b2c224b2010-06-09 11:21:15 -07003017 goto out;
3018 }
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303019 err = v9fs_co_link(pdu, oldfidp, dfidp, &name);
Venkateswararao Jujjuri (JV)ffd66872011-05-09 11:47:28 -07003020 if (!err) {
3021 err = offset;
Venkateswararao Jujjuri (JV)b2c224b2010-06-09 11:21:15 -07003022 }
Li Qiang4c158672016-10-17 14:13:58 +02003023 put_fid(pdu, oldfidp);
Venkateswararao Jujjuri (JV)b2c224b2010-06-09 11:21:15 -07003024out:
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303025 put_fid(pdu, dfidp);
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05303026out_nofid:
Venkateswararao Jujjuri (JV)b2c224b2010-06-09 11:21:15 -07003027 v9fs_string_free(&name);
Wei Liudc295f82015-12-02 15:00:14 +00003028 pdu_complete(pdu, err);
Venkateswararao Jujjuri (JV)b2c224b2010-06-09 11:21:15 -07003029}
3030
Aneesh Kumar K.V532decb2011-08-02 11:35:54 +05303031/* Only works with path name based fid */
Greg Kurz8440e222016-10-17 14:13:58 +02003032static void coroutine_fn v9fs_remove(void *opaque)
Anthony Liguori9f107512010-04-29 17:44:44 +05303033{
Anthony Liguori5bae1902010-04-29 17:45:01 +05303034 int32_t fid;
Anthony Liguori5bae1902010-04-29 17:45:01 +05303035 int err = 0;
Venkateswararao Jujjuriae1ef572011-08-08 23:50:20 +05303036 size_t offset = 7;
3037 V9fsFidState *fidp;
3038 V9fsPDU *pdu = opaque;
Anthony Liguori5bae1902010-04-29 17:45:01 +05303039
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05303040 err = pdu_unmarshal(pdu, offset, "d", &fid);
3041 if (err < 0) {
3042 goto out_nofid;
3043 }
Harsh Prateek Borac572f232011-10-12 19:11:25 +05303044 trace_v9fs_remove(pdu->tag, pdu->id, fid);
Anthony Liguori5bae1902010-04-29 17:45:01 +05303045
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303046 fidp = get_fid(pdu, fid);
Venkateswararao Jujjuriae1ef572011-08-08 23:50:20 +05303047 if (fidp == NULL) {
Anthony Liguori5bae1902010-04-29 17:45:01 +05303048 err = -EINVAL;
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05303049 goto out_nofid;
Anthony Liguori9f107512010-04-29 17:44:44 +05303050 }
Aneesh Kumar K.V532decb2011-08-02 11:35:54 +05303051 /* if fs driver is not path based, return EOPNOTSUPP */
Aneesh Kumar K.Vc98f1d42011-10-12 20:59:18 +05303052 if (!(pdu->s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT)) {
Aneesh Kumar K.V532decb2011-08-02 11:35:54 +05303053 err = -EOPNOTSUPP;
3054 goto out_err;
3055 }
Aneesh Kumar K.V7a462742011-05-18 15:40:57 +05303056 /*
3057 * IF the file is unlinked, we cannot reopen
3058 * the file later. So don't reclaim fd
3059 */
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303060 err = v9fs_mark_fids_unreclaim(pdu, &fidp->path);
Aneesh Kumar K.V7a462742011-05-18 15:40:57 +05303061 if (err < 0) {
3062 goto out_err;
3063 }
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303064 err = v9fs_co_remove(pdu, &fidp->path);
Venkateswararao Jujjuriae1ef572011-08-08 23:50:20 +05303065 if (!err) {
3066 err = offset;
3067 }
Aneesh Kumar K.V7a462742011-05-18 15:40:57 +05303068out_err:
Venkateswararao Jujjuriae1ef572011-08-08 23:50:20 +05303069 /* For TREMOVE we need to clunk the fid even on failed remove */
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05303070 clunk_fid(pdu->s, fidp->fid);
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303071 put_fid(pdu, fidp);
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05303072out_nofid:
Wei Liudc295f82015-12-02 15:00:14 +00003073 pdu_complete(pdu, err);
Anthony Liguori9f107512010-04-29 17:44:44 +05303074}
3075
Greg Kurz8440e222016-10-17 14:13:58 +02003076static void coroutine_fn v9fs_unlinkat(void *opaque)
Aneesh Kumar K.V7834cf72011-09-09 15:07:01 +05303077{
3078 int err = 0;
3079 V9fsString name;
Keno Fischer67e87342018-06-07 12:17:22 +02003080 int32_t dfid, flags, rflags = 0;
Aneesh Kumar K.V7834cf72011-09-09 15:07:01 +05303081 size_t offset = 7;
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +05303082 V9fsPath path;
Aneesh Kumar K.V7834cf72011-09-09 15:07:01 +05303083 V9fsFidState *dfidp;
3084 V9fsPDU *pdu = opaque;
Aneesh Kumar K.V7834cf72011-09-09 15:07:01 +05303085
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05303086 v9fs_string_init(&name);
3087 err = pdu_unmarshal(pdu, offset, "dsd", &dfid, &name, &flags);
3088 if (err < 0) {
3089 goto out_nofid;
3090 }
Greg Kurzfff39a72016-08-30 19:11:05 +02003091
3092 if (name_is_illegal(name.data)) {
3093 err = -ENOENT;
3094 goto out_nofid;
3095 }
3096
Greg Kurz805b5d92016-08-30 19:13:11 +02003097 if (!strcmp(".", name.data)) {
3098 err = -EINVAL;
3099 goto out_nofid;
3100 }
3101
3102 if (!strcmp("..", name.data)) {
3103 err = -ENOTEMPTY;
3104 goto out_nofid;
3105 }
3106
Keno Fischer67e87342018-06-07 12:17:22 +02003107 if (flags & ~P9_DOTL_AT_REMOVEDIR) {
3108 err = -EINVAL;
3109 goto out_nofid;
3110 }
3111
3112 if (flags & P9_DOTL_AT_REMOVEDIR) {
3113 rflags |= AT_REMOVEDIR;
3114 }
3115
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303116 dfidp = get_fid(pdu, dfid);
Aneesh Kumar K.V7834cf72011-09-09 15:07:01 +05303117 if (dfidp == NULL) {
3118 err = -EINVAL;
3119 goto out_nofid;
3120 }
Aneesh Kumar K.V7834cf72011-09-09 15:07:01 +05303121 /*
3122 * IF the file is unlinked, we cannot reopen
3123 * the file later. So don't reclaim fd
3124 */
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +05303125 v9fs_path_init(&path);
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303126 err = v9fs_co_name_to_path(pdu, &dfidp->path, name.data, &path);
Aneesh Kumar K.V7834cf72011-09-09 15:07:01 +05303127 if (err < 0) {
3128 goto out_err;
3129 }
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303130 err = v9fs_mark_fids_unreclaim(pdu, &path);
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +05303131 if (err < 0) {
3132 goto out_err;
3133 }
Keno Fischer67e87342018-06-07 12:17:22 +02003134 err = v9fs_co_unlinkat(pdu, &dfidp->path, &name, rflags);
Aneesh Kumar K.V7834cf72011-09-09 15:07:01 +05303135 if (!err) {
3136 err = offset;
3137 }
3138out_err:
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303139 put_fid(pdu, dfidp);
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +05303140 v9fs_path_free(&path);
Aneesh Kumar K.V7834cf72011-09-09 15:07:01 +05303141out_nofid:
Wei Liudc295f82015-12-02 15:00:14 +00003142 pdu_complete(pdu, err);
Aneesh Kumar K.V7834cf72011-09-09 15:07:01 +05303143 v9fs_string_free(&name);
3144}
3145
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +05303146
3147/* Only works with path name based fid */
Greg Kurz8440e222016-10-17 14:13:58 +02003148static int coroutine_fn v9fs_complete_rename(V9fsPDU *pdu, V9fsFidState *fidp,
3149 int32_t newdirfid,
3150 V9fsString *name)
Anthony Liguori8cf89e02010-04-29 17:45:00 +05303151{
M. Mohan Kumarc7b4b0b2010-06-22 12:29:41 +05303152 int err = 0;
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +05303153 V9fsPath new_path;
3154 V9fsFidState *tfidp;
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303155 V9fsState *s = pdu->s;
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05303156 V9fsFidState *dirfidp = NULL;
Anthony Liguori8cf89e02010-04-29 17:45:00 +05303157
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +05303158 v9fs_path_init(&new_path);
Aneesh Kumar K.V930b1e12011-05-07 16:01:33 +05303159 if (newdirfid != -1) {
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303160 dirfidp = get_fid(pdu, newdirfid);
M. Mohan Kumarc7b4b0b2010-06-22 12:29:41 +05303161 if (dirfidp == NULL) {
Daniel Henrique Barbozab858e802020-01-20 15:11:39 +01003162 return -ENOENT;
M. Mohan Kumarc7b4b0b2010-06-22 12:29:41 +05303163 }
Greg Kurz49dd9462016-11-01 12:00:40 +01003164 if (fidp->fid_type != P9_FID_NONE) {
3165 err = -EINVAL;
3166 goto out;
3167 }
Greg Kurz4fa62002017-05-25 10:30:14 +02003168 err = v9fs_co_name_to_path(pdu, &dirfidp->path, name->data, &new_path);
3169 if (err < 0) {
3170 goto out;
3171 }
M. Mohan Kumarc7b4b0b2010-06-22 12:29:41 +05303172 } else {
Jan Dakinevich4d8bc732017-09-20 08:48:52 +02003173 char *dir_name = g_path_get_dirname(fidp->path.data);
3174 V9fsPath dir_path;
3175
3176 v9fs_path_init(&dir_path);
3177 v9fs_path_sprintf(&dir_path, "%s", dir_name);
3178 g_free(dir_name);
3179
3180 err = v9fs_co_name_to_path(pdu, &dir_path, name->data, &new_path);
3181 v9fs_path_free(&dir_path);
Greg Kurz4fa62002017-05-25 10:30:14 +02003182 if (err < 0) {
3183 goto out;
3184 }
M. Mohan Kumarc7b4b0b2010-06-22 12:29:41 +05303185 }
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303186 err = v9fs_co_rename(pdu, &fidp->path, &new_path);
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +05303187 if (err < 0) {
3188 goto out;
3189 }
3190 /*
3191 * Fixup fid's pointing to the old name to
3192 * start pointing to the new name
3193 */
Greg Kurzfeabd6c2021-01-18 15:22:59 +01003194 QSIMPLEQ_FOREACH(tfidp, &s->fid_list, next) {
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +05303195 if (v9fs_path_is_ancestor(&fidp->path, &tfidp->path)) {
3196 /* replace the name */
3197 v9fs_fix_path(&tfidp->path, &new_path, strlen(fidp->path.data));
Anthony Liguori8cf89e02010-04-29 17:45:00 +05303198 }
3199 }
M. Mohan Kumarc7b4b0b2010-06-22 12:29:41 +05303200out:
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05303201 if (dirfidp) {
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303202 put_fid(pdu, dirfidp);
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05303203 }
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +05303204 v9fs_path_free(&new_path);
M. Mohan Kumarc7b4b0b2010-06-22 12:29:41 +05303205 return err;
3206}
3207
Aneesh Kumar K.V532decb2011-08-02 11:35:54 +05303208/* Only works with path name based fid */
Greg Kurz8440e222016-10-17 14:13:58 +02003209static void coroutine_fn v9fs_rename(void *opaque)
M. Mohan Kumarc7b4b0b2010-06-22 12:29:41 +05303210{
Aneesh Kumar K.V930b1e12011-05-07 16:01:33 +05303211 int32_t fid;
3212 ssize_t err = 0;
3213 size_t offset = 7;
3214 V9fsString name;
3215 int32_t newdirfid;
3216 V9fsFidState *fidp;
Venkateswararao Jujjuri (JV)ff060302011-05-18 14:18:05 -07003217 V9fsPDU *pdu = opaque;
3218 V9fsState *s = pdu->s;
M. Mohan Kumarc7b4b0b2010-06-22 12:29:41 +05303219
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05303220 v9fs_string_init(&name);
3221 err = pdu_unmarshal(pdu, offset, "dds", &fid, &newdirfid, &name);
3222 if (err < 0) {
3223 goto out_nofid;
3224 }
Greg Kurzfff39a72016-08-30 19:11:05 +02003225
3226 if (name_is_illegal(name.data)) {
3227 err = -ENOENT;
3228 goto out_nofid;
3229 }
3230
Greg Kurz805b5d92016-08-30 19:13:11 +02003231 if (!strcmp(".", name.data) || !strcmp("..", name.data)) {
3232 err = -EISDIR;
3233 goto out_nofid;
3234 }
3235
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303236 fidp = get_fid(pdu, fid);
Aneesh Kumar K.V930b1e12011-05-07 16:01:33 +05303237 if (fidp == NULL) {
M. Mohan Kumarc7b4b0b2010-06-22 12:29:41 +05303238 err = -ENOENT;
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05303239 goto out_nofid;
M. Mohan Kumarc7b4b0b2010-06-22 12:29:41 +05303240 }
Greg Kurz49dd9462016-11-01 12:00:40 +01003241 if (fidp->fid_type != P9_FID_NONE) {
3242 err = -EINVAL;
3243 goto out;
3244 }
Aneesh Kumar K.V532decb2011-08-02 11:35:54 +05303245 /* if fs driver is not path based, return EOPNOTSUPP */
Aneesh Kumar K.Vc98f1d42011-10-12 20:59:18 +05303246 if (!(pdu->s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT)) {
Aneesh Kumar K.V532decb2011-08-02 11:35:54 +05303247 err = -EOPNOTSUPP;
3248 goto out;
3249 }
3250 v9fs_path_write_lock(s);
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303251 err = v9fs_complete_rename(pdu, fidp, newdirfid, &name);
Aneesh Kumar K.V532decb2011-08-02 11:35:54 +05303252 v9fs_path_unlock(s);
Aneesh Kumar K.V930b1e12011-05-07 16:01:33 +05303253 if (!err) {
3254 err = offset;
3255 }
Aneesh Kumar K.V532decb2011-08-02 11:35:54 +05303256out:
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303257 put_fid(pdu, fidp);
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05303258out_nofid:
Wei Liudc295f82015-12-02 15:00:14 +00003259 pdu_complete(pdu, err);
Aneesh Kumar K.V930b1e12011-05-07 16:01:33 +05303260 v9fs_string_free(&name);
M. Mohan Kumarc7b4b0b2010-06-22 12:29:41 +05303261}
3262
Greg Kurz4fa62002017-05-25 10:30:14 +02003263static int coroutine_fn v9fs_fix_fid_paths(V9fsPDU *pdu, V9fsPath *olddir,
3264 V9fsString *old_name,
3265 V9fsPath *newdir,
3266 V9fsString *new_name)
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +05303267{
3268 V9fsFidState *tfidp;
3269 V9fsPath oldpath, newpath;
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303270 V9fsState *s = pdu->s;
Greg Kurz4fa62002017-05-25 10:30:14 +02003271 int err;
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +05303272
3273 v9fs_path_init(&oldpath);
3274 v9fs_path_init(&newpath);
Greg Kurz4fa62002017-05-25 10:30:14 +02003275 err = v9fs_co_name_to_path(pdu, olddir, old_name->data, &oldpath);
3276 if (err < 0) {
3277 goto out;
3278 }
3279 err = v9fs_co_name_to_path(pdu, newdir, new_name->data, &newpath);
3280 if (err < 0) {
3281 goto out;
3282 }
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +05303283
3284 /*
3285 * Fixup fid's pointing to the old name to
3286 * start pointing to the new name
3287 */
Greg Kurzfeabd6c2021-01-18 15:22:59 +01003288 QSIMPLEQ_FOREACH(tfidp, &s->fid_list, next) {
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +05303289 if (v9fs_path_is_ancestor(&oldpath, &tfidp->path)) {
3290 /* replace the name */
3291 v9fs_fix_path(&tfidp->path, &newpath, strlen(oldpath.data));
3292 }
3293 }
Greg Kurz4fa62002017-05-25 10:30:14 +02003294out:
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +05303295 v9fs_path_free(&oldpath);
3296 v9fs_path_free(&newpath);
Greg Kurz4fa62002017-05-25 10:30:14 +02003297 return err;
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +05303298}
3299
Greg Kurz8440e222016-10-17 14:13:58 +02003300static int coroutine_fn v9fs_complete_renameat(V9fsPDU *pdu, int32_t olddirfid,
3301 V9fsString *old_name,
3302 int32_t newdirfid,
3303 V9fsString *new_name)
Aneesh Kumar K.V89bf6592011-05-23 23:24:41 +05303304{
3305 int err = 0;
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303306 V9fsState *s = pdu->s;
Aneesh Kumar K.V89bf6592011-05-23 23:24:41 +05303307 V9fsFidState *newdirfidp = NULL, *olddirfidp = NULL;
3308
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303309 olddirfidp = get_fid(pdu, olddirfid);
Aneesh Kumar K.V89bf6592011-05-23 23:24:41 +05303310 if (olddirfidp == NULL) {
3311 err = -ENOENT;
3312 goto out;
3313 }
Aneesh Kumar K.V89bf6592011-05-23 23:24:41 +05303314 if (newdirfid != -1) {
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303315 newdirfidp = get_fid(pdu, newdirfid);
Aneesh Kumar K.V89bf6592011-05-23 23:24:41 +05303316 if (newdirfidp == NULL) {
3317 err = -ENOENT;
3318 goto out;
3319 }
Aneesh Kumar K.V89bf6592011-05-23 23:24:41 +05303320 } else {
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303321 newdirfidp = get_fid(pdu, olddirfid);
Aneesh Kumar K.V89bf6592011-05-23 23:24:41 +05303322 }
3323
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303324 err = v9fs_co_renameat(pdu, &olddirfidp->path, old_name,
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +05303325 &newdirfidp->path, new_name);
3326 if (err < 0) {
3327 goto out;
Aneesh Kumar K.V89bf6592011-05-23 23:24:41 +05303328 }
Aneesh Kumar K.Vc98f1d42011-10-12 20:59:18 +05303329 if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) {
Aneesh Kumar K.V532decb2011-08-02 11:35:54 +05303330 /* Only for path based fid we need to do the below fixup */
Greg Kurz4fa62002017-05-25 10:30:14 +02003331 err = v9fs_fix_fid_paths(pdu, &olddirfidp->path, old_name,
3332 &newdirfidp->path, new_name);
Aneesh Kumar K.V532decb2011-08-02 11:35:54 +05303333 }
Aneesh Kumar K.V89bf6592011-05-23 23:24:41 +05303334out:
3335 if (olddirfidp) {
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303336 put_fid(pdu, olddirfidp);
Aneesh Kumar K.V89bf6592011-05-23 23:24:41 +05303337 }
3338 if (newdirfidp) {
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303339 put_fid(pdu, newdirfidp);
Aneesh Kumar K.V89bf6592011-05-23 23:24:41 +05303340 }
Aneesh Kumar K.V89bf6592011-05-23 23:24:41 +05303341 return err;
3342}
3343
Greg Kurz8440e222016-10-17 14:13:58 +02003344static void coroutine_fn v9fs_renameat(void *opaque)
Aneesh Kumar K.V89bf6592011-05-23 23:24:41 +05303345{
3346 ssize_t err = 0;
3347 size_t offset = 7;
3348 V9fsPDU *pdu = opaque;
3349 V9fsState *s = pdu->s;
3350 int32_t olddirfid, newdirfid;
3351 V9fsString old_name, new_name;
3352
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05303353 v9fs_string_init(&old_name);
3354 v9fs_string_init(&new_name);
3355 err = pdu_unmarshal(pdu, offset, "dsds", &olddirfid,
3356 &old_name, &newdirfid, &new_name);
3357 if (err < 0) {
3358 goto out_err;
3359 }
Aneesh Kumar K.V89bf6592011-05-23 23:24:41 +05303360
Greg Kurzfff39a72016-08-30 19:11:05 +02003361 if (name_is_illegal(old_name.data) || name_is_illegal(new_name.data)) {
3362 err = -ENOENT;
3363 goto out_err;
3364 }
3365
Greg Kurz805b5d92016-08-30 19:13:11 +02003366 if (!strcmp(".", old_name.data) || !strcmp("..", old_name.data) ||
3367 !strcmp(".", new_name.data) || !strcmp("..", new_name.data)) {
3368 err = -EISDIR;
3369 goto out_err;
3370 }
3371
Aneesh Kumar K.V532decb2011-08-02 11:35:54 +05303372 v9fs_path_write_lock(s);
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303373 err = v9fs_complete_renameat(pdu, olddirfid,
3374 &old_name, newdirfid, &new_name);
Aneesh Kumar K.V532decb2011-08-02 11:35:54 +05303375 v9fs_path_unlock(s);
Aneesh Kumar K.V89bf6592011-05-23 23:24:41 +05303376 if (!err) {
3377 err = offset;
3378 }
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05303379
3380out_err:
Wei Liudc295f82015-12-02 15:00:14 +00003381 pdu_complete(pdu, err);
Aneesh Kumar K.V89bf6592011-05-23 23:24:41 +05303382 v9fs_string_free(&old_name);
3383 v9fs_string_free(&new_name);
3384}
3385
Greg Kurz8440e222016-10-17 14:13:58 +02003386static void coroutine_fn v9fs_wstat(void *opaque)
Anthony Liguori8cf89e02010-04-29 17:45:00 +05303387{
Aneesh Kumar K.Vb81d6852011-05-08 13:06:04 +05303388 int32_t fid;
3389 int err = 0;
3390 int16_t unused;
3391 V9fsStat v9stat;
3392 size_t offset = 7;
3393 struct stat stbuf;
3394 V9fsFidState *fidp;
3395 V9fsPDU *pdu = opaque;
Greg Kurz1d203982018-11-23 13:28:03 +01003396 V9fsState *s = pdu->s;
Aneesh Kumar K.Vb81d6852011-05-08 13:06:04 +05303397
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05303398 v9fs_stat_init(&v9stat);
3399 err = pdu_unmarshal(pdu, offset, "dwS", &fid, &unused, &v9stat);
3400 if (err < 0) {
3401 goto out_nofid;
3402 }
Harsh Prateek Borac572f232011-10-12 19:11:25 +05303403 trace_v9fs_wstat(pdu->tag, pdu->id, fid,
3404 v9stat.mode, v9stat.atime, v9stat.mtime);
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05303405
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303406 fidp = get_fid(pdu, fid);
Aneesh Kumar K.Vb81d6852011-05-08 13:06:04 +05303407 if (fidp == NULL) {
3408 err = -EINVAL;
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05303409 goto out_nofid;
Anthony Liguori8cf89e02010-04-29 17:45:00 +05303410 }
Aneesh Kumar K.Vb81d6852011-05-08 13:06:04 +05303411 /* do we need to sync the file? */
3412 if (donttouch_stat(&v9stat)) {
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303413 err = v9fs_co_fsync(pdu, fidp, 0);
Aneesh Kumar K.Vb81d6852011-05-08 13:06:04 +05303414 goto out;
3415 }
3416 if (v9stat.mode != -1) {
3417 uint32_t v9_mode;
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303418 err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
Aneesh Kumar K.Vb81d6852011-05-08 13:06:04 +05303419 if (err < 0) {
3420 goto out;
3421 }
3422 v9_mode = stat_to_v9mode(&stbuf);
3423 if ((v9stat.mode & P9_STAT_MODE_TYPE_BITS) !=
3424 (v9_mode & P9_STAT_MODE_TYPE_BITS)) {
3425 /* Attempting to change the type */
3426 err = -EIO;
3427 goto out;
3428 }
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303429 err = v9fs_co_chmod(pdu, &fidp->path,
Aneesh Kumar K.Vb81d6852011-05-08 13:06:04 +05303430 v9mode_to_mode(v9stat.mode,
3431 &v9stat.extension));
3432 if (err < 0) {
3433 goto out;
Anthony Liguori8cf89e02010-04-29 17:45:00 +05303434 }
3435 }
Aneesh Kumar K.Vb81d6852011-05-08 13:06:04 +05303436 if (v9stat.mtime != -1 || v9stat.atime != -1) {
Sripathi Kodi8fc39ae2010-06-09 19:14:38 +05303437 struct timespec times[2];
Aneesh Kumar K.Vb81d6852011-05-08 13:06:04 +05303438 if (v9stat.atime != -1) {
3439 times[0].tv_sec = v9stat.atime;
Sripathi Kodi8fc39ae2010-06-09 19:14:38 +05303440 times[0].tv_nsec = 0;
3441 } else {
3442 times[0].tv_nsec = UTIME_OMIT;
3443 }
Aneesh Kumar K.Vb81d6852011-05-08 13:06:04 +05303444 if (v9stat.mtime != -1) {
3445 times[1].tv_sec = v9stat.mtime;
Sripathi Kodi8fc39ae2010-06-09 19:14:38 +05303446 times[1].tv_nsec = 0;
3447 } else {
3448 times[1].tv_nsec = UTIME_OMIT;
3449 }
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303450 err = v9fs_co_utimensat(pdu, &fidp->path, times);
Aneesh Kumar K.Vb81d6852011-05-08 13:06:04 +05303451 if (err < 0) {
3452 goto out;
Anthony Liguori8cf89e02010-04-29 17:45:00 +05303453 }
3454 }
Aneesh Kumar K.Vb81d6852011-05-08 13:06:04 +05303455 if (v9stat.n_gid != -1 || v9stat.n_uid != -1) {
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303456 err = v9fs_co_chown(pdu, &fidp->path, v9stat.n_uid, v9stat.n_gid);
Aneesh Kumar K.Vb81d6852011-05-08 13:06:04 +05303457 if (err < 0) {
Anthony Liguori8cf89e02010-04-29 17:45:00 +05303458 goto out;
Aneesh Kumar K.Vb81d6852011-05-08 13:06:04 +05303459 }
Anthony Liguori8cf89e02010-04-29 17:45:00 +05303460 }
Aneesh Kumar K.Vb81d6852011-05-08 13:06:04 +05303461 if (v9stat.name.size != 0) {
Greg Kurz1d203982018-11-23 13:28:03 +01003462 v9fs_path_write_lock(s);
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303463 err = v9fs_complete_rename(pdu, fidp, -1, &v9stat.name);
Greg Kurz1d203982018-11-23 13:28:03 +01003464 v9fs_path_unlock(s);
Aneesh Kumar K.Vb81d6852011-05-08 13:06:04 +05303465 if (err < 0) {
3466 goto out;
3467 }
3468 }
3469 if (v9stat.length != -1) {
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303470 err = v9fs_co_truncate(pdu, &fidp->path, v9stat.length);
Aneesh Kumar K.Vb81d6852011-05-08 13:06:04 +05303471 if (err < 0) {
3472 goto out;
3473 }
3474 }
3475 err = offset;
Anthony Liguori8cf89e02010-04-29 17:45:00 +05303476out:
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303477 put_fid(pdu, fidp);
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05303478out_nofid:
Aneesh Kumar K.Vb81d6852011-05-08 13:06:04 +05303479 v9fs_stat_free(&v9stat);
Wei Liudc295f82015-12-02 15:00:14 +00003480 pdu_complete(pdu, err);
Anthony Liguori9f107512010-04-29 17:44:44 +05303481}
3482
Aneesh Kumar K.V88a47632011-05-18 16:04:01 -07003483static int v9fs_fill_statfs(V9fsState *s, V9fsPDU *pdu, struct statfs *stbuf)
M. Mohan Kumarbe940c82010-05-10 12:11:03 +05303484{
Aneesh Kumar K.V88a47632011-05-18 16:04:01 -07003485 uint32_t f_type;
3486 uint32_t f_bsize;
3487 uint64_t f_blocks;
3488 uint64_t f_bfree;
3489 uint64_t f_bavail;
3490 uint64_t f_files;
3491 uint64_t f_ffree;
3492 uint64_t fsid_val;
3493 uint32_t f_namelen;
3494 size_t offset = 7;
M. Mohan Kumar5e94c102010-06-09 19:14:28 +05303495 int32_t bsize_factor;
3496
M. Mohan Kumar5e94c102010-06-09 19:14:28 +05303497 /*
3498 * compute bsize factor based on host file system block size
3499 * and client msize
3500 */
Xinhao Zhang01011732020-10-30 12:35:13 +08003501 bsize_factor = (s->msize - P9_IOHDRSZ) / stbuf->f_bsize;
M. Mohan Kumar5e94c102010-06-09 19:14:28 +05303502 if (!bsize_factor) {
3503 bsize_factor = 1;
3504 }
Aneesh Kumar K.V88a47632011-05-18 16:04:01 -07003505 f_type = stbuf->f_type;
3506 f_bsize = stbuf->f_bsize;
3507 f_bsize *= bsize_factor;
M. Mohan Kumar5e94c102010-06-09 19:14:28 +05303508 /*
3509 * f_bsize is adjusted(multiplied) by bsize factor, so we need to
3510 * adjust(divide) the number of blocks, free blocks and available
3511 * blocks by bsize factor
3512 */
Xinhao Zhang01011732020-10-30 12:35:13 +08003513 f_blocks = stbuf->f_blocks / bsize_factor;
3514 f_bfree = stbuf->f_bfree / bsize_factor;
3515 f_bavail = stbuf->f_bavail / bsize_factor;
Aneesh Kumar K.V88a47632011-05-18 16:04:01 -07003516 f_files = stbuf->f_files;
3517 f_ffree = stbuf->f_ffree;
3518 fsid_val = (unsigned int) stbuf->f_fsid.__val[0] |
3519 (unsigned long long)stbuf->f_fsid.__val[1] << 32;
3520 f_namelen = stbuf->f_namelen;
M. Mohan Kumarbe940c82010-05-10 12:11:03 +05303521
Aneesh Kumar K.V88a47632011-05-18 16:04:01 -07003522 return pdu_marshal(pdu, offset, "ddqqqqqqd",
3523 f_type, f_bsize, f_blocks, f_bfree,
3524 f_bavail, f_files, f_ffree,
3525 fsid_val, f_namelen);
M. Mohan Kumarbe940c82010-05-10 12:11:03 +05303526}
3527
Greg Kurz8440e222016-10-17 14:13:58 +02003528static void coroutine_fn v9fs_statfs(void *opaque)
M. Mohan Kumarbe940c82010-05-10 12:11:03 +05303529{
Aneesh Kumar K.V88a47632011-05-18 16:04:01 -07003530 int32_t fid;
3531 ssize_t retval = 0;
3532 size_t offset = 7;
3533 V9fsFidState *fidp;
3534 struct statfs stbuf;
Venkateswararao Jujjuri (JV)ff060302011-05-18 14:18:05 -07003535 V9fsPDU *pdu = opaque;
3536 V9fsState *s = pdu->s;
M. Mohan Kumarbe940c82010-05-10 12:11:03 +05303537
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05303538 retval = pdu_unmarshal(pdu, offset, "d", &fid);
3539 if (retval < 0) {
3540 goto out_nofid;
3541 }
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303542 fidp = get_fid(pdu, fid);
Aneesh Kumar K.V88a47632011-05-18 16:04:01 -07003543 if (fidp == NULL) {
3544 retval = -ENOENT;
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05303545 goto out_nofid;
M. Mohan Kumarbe940c82010-05-10 12:11:03 +05303546 }
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303547 retval = v9fs_co_statfs(pdu, &fidp->path, &stbuf);
Aneesh Kumar K.V88a47632011-05-18 16:04:01 -07003548 if (retval < 0) {
3549 goto out;
3550 }
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05303551 retval = v9fs_fill_statfs(s, pdu, &stbuf);
3552 if (retval < 0) {
3553 goto out;
3554 }
3555 retval += offset;
M. Mohan Kumarbe940c82010-05-10 12:11:03 +05303556out:
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303557 put_fid(pdu, fidp);
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05303558out_nofid:
Wei Liudc295f82015-12-02 15:00:14 +00003559 pdu_complete(pdu, retval);
M. Mohan Kumarbe940c82010-05-10 12:11:03 +05303560}
3561
Greg Kurz8440e222016-10-17 14:13:58 +02003562static void coroutine_fn v9fs_mknod(void *opaque)
M. Mohan Kumar5268cec2010-06-22 12:24:09 +05303563{
Aneesh Kumar K.V1b733fe2011-05-18 16:06:51 -07003564
3565 int mode;
3566 gid_t gid;
3567 int32_t fid;
3568 V9fsQID qid;
3569 int err = 0;
3570 int major, minor;
3571 size_t offset = 7;
3572 V9fsString name;
3573 struct stat stbuf;
Aneesh Kumar K.V1b733fe2011-05-18 16:06:51 -07003574 V9fsFidState *fidp;
Venkateswararao Jujjuri (JV)ff060302011-05-18 14:18:05 -07003575 V9fsPDU *pdu = opaque;
M. Mohan Kumar5268cec2010-06-22 12:24:09 +05303576
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05303577 v9fs_string_init(&name);
3578 err = pdu_unmarshal(pdu, offset, "dsdddd", &fid, &name, &mode,
3579 &major, &minor, &gid);
3580 if (err < 0) {
3581 goto out_nofid;
3582 }
Harsh Prateek Borac572f232011-10-12 19:11:25 +05303583 trace_v9fs_mknod(pdu->tag, pdu->id, fid, mode, major, minor);
M. Mohan Kumar5268cec2010-06-22 12:24:09 +05303584
Greg Kurzfff39a72016-08-30 19:11:05 +02003585 if (name_is_illegal(name.data)) {
3586 err = -ENOENT;
3587 goto out_nofid;
3588 }
3589
Greg Kurz805b5d92016-08-30 19:13:11 +02003590 if (!strcmp(".", name.data) || !strcmp("..", name.data)) {
3591 err = -EEXIST;
3592 goto out_nofid;
3593 }
3594
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303595 fidp = get_fid(pdu, fid);
M. Mohan Kumar5268cec2010-06-22 12:24:09 +05303596 if (fidp == NULL) {
3597 err = -ENOENT;
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05303598 goto out_nofid;
M. Mohan Kumar5268cec2010-06-22 12:24:09 +05303599 }
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303600 err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, gid,
Aneesh Kumar K.V02cb7f32011-05-24 15:10:56 +05303601 makedev(major, minor), mode, &stbuf);
Aneesh Kumar K.V1b733fe2011-05-18 16:06:51 -07003602 if (err < 0) {
3603 goto out;
3604 }
Antonios Motakis3b5ee9e2019-10-10 11:36:05 +02003605 err = stat_to_qid(pdu, &stbuf, &qid);
3606 if (err < 0) {
3607 goto out;
3608 }
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05303609 err = pdu_marshal(pdu, offset, "Q", &qid);
3610 if (err < 0) {
3611 goto out;
3612 }
3613 err += offset;
Aneesh Kumar K.V7999f7e2011-10-24 15:09:49 +05303614 trace_v9fs_mknod_return(pdu->tag, pdu->id,
3615 qid.type, qid.version, qid.path);
M. Mohan Kumar5268cec2010-06-22 12:24:09 +05303616out:
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303617 put_fid(pdu, fidp);
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05303618out_nofid:
Wei Liudc295f82015-12-02 15:00:14 +00003619 pdu_complete(pdu, err);
Aneesh Kumar K.V1b733fe2011-05-18 16:06:51 -07003620 v9fs_string_free(&name);
M. Mohan Kumar5268cec2010-06-22 12:24:09 +05303621}
3622
M. Mohan Kumar82cc3ee2010-09-08 02:19:32 +05303623/*
3624 * Implement posix byte range locking code
3625 * Server side handling of locking code is very simple, because 9p server in
3626 * QEMU can handle only one client. And most of the lock handling
3627 * (like conflict, merging) etc is done by the VFS layer itself, so no need to
3628 * do any thing in * qemu 9p server side lock code path.
3629 * So when a TLOCK request comes, always return success
3630 */
Greg Kurz8440e222016-10-17 14:13:58 +02003631static void coroutine_fn v9fs_lock(void *opaque)
M. Mohan Kumar82cc3ee2010-09-08 02:19:32 +05303632{
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05303633 V9fsFlock flock;
Aneesh Kumar K.V0c27bf22011-08-22 09:14:04 +05303634 size_t offset = 7;
3635 struct stat stbuf;
3636 V9fsFidState *fidp;
3637 int32_t fid, err = 0;
Venkateswararao Jujjuri (JV)ff060302011-05-18 14:18:05 -07003638 V9fsPDU *pdu = opaque;
M. Mohan Kumar82cc3ee2010-09-08 02:19:32 +05303639
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05303640 v9fs_string_init(&flock.client_id);
3641 err = pdu_unmarshal(pdu, offset, "dbdqqds", &fid, &flock.type,
3642 &flock.flags, &flock.start, &flock.length,
3643 &flock.proc_id, &flock.client_id);
3644 if (err < 0) {
3645 goto out_nofid;
3646 }
3647 trace_v9fs_lock(pdu->tag, pdu->id, fid,
3648 flock.type, flock.start, flock.length);
3649
M. Mohan Kumar82cc3ee2010-09-08 02:19:32 +05303650
3651 /* We support only block flag now (that too ignored currently) */
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05303652 if (flock.flags & ~P9_LOCK_FLAGS_BLOCK) {
M. Mohan Kumar82cc3ee2010-09-08 02:19:32 +05303653 err = -EINVAL;
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05303654 goto out_nofid;
M. Mohan Kumar82cc3ee2010-09-08 02:19:32 +05303655 }
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303656 fidp = get_fid(pdu, fid);
Aneesh Kumar K.V0c27bf22011-08-22 09:14:04 +05303657 if (fidp == NULL) {
M. Mohan Kumar82cc3ee2010-09-08 02:19:32 +05303658 err = -ENOENT;
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05303659 goto out_nofid;
M. Mohan Kumar82cc3ee2010-09-08 02:19:32 +05303660 }
Aneesh Kumar K.Vcc720dd2011-10-25 12:10:40 +05303661 err = v9fs_co_fstat(pdu, fidp, &stbuf);
M. Mohan Kumar82cc3ee2010-09-08 02:19:32 +05303662 if (err < 0) {
M. Mohan Kumar82cc3ee2010-09-08 02:19:32 +05303663 goto out;
3664 }
Paolo Bonzini4bae2b32017-02-28 10:31:46 +01003665 err = pdu_marshal(pdu, offset, "b", P9_LOCK_SUCCESS);
3666 if (err < 0) {
3667 goto out;
3668 }
3669 err += offset;
3670 trace_v9fs_lock_return(pdu->tag, pdu->id, P9_LOCK_SUCCESS);
M. Mohan Kumar82cc3ee2010-09-08 02:19:32 +05303671out:
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303672 put_fid(pdu, fidp);
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05303673out_nofid:
Wei Liudc295f82015-12-02 15:00:14 +00003674 pdu_complete(pdu, err);
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05303675 v9fs_string_free(&flock.client_id);
M. Mohan Kumar82cc3ee2010-09-08 02:19:32 +05303676}
3677
M. Mohan Kumar8f354002010-09-08 02:36:52 +05303678/*
3679 * When a TGETLOCK request comes, always return success because all lock
3680 * handling is done by client's VFS layer.
3681 */
Greg Kurz8440e222016-10-17 14:13:58 +02003682static void coroutine_fn v9fs_getlock(void *opaque)
M. Mohan Kumar8f354002010-09-08 02:36:52 +05303683{
Aneesh Kumar K.Ve4e414a2011-05-07 17:21:38 +05303684 size_t offset = 7;
3685 struct stat stbuf;
3686 V9fsFidState *fidp;
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05303687 V9fsGetlock glock;
Aneesh Kumar K.Ve4e414a2011-05-07 17:21:38 +05303688 int32_t fid, err = 0;
Venkateswararao Jujjuri (JV)ff060302011-05-18 14:18:05 -07003689 V9fsPDU *pdu = opaque;
M. Mohan Kumar8f354002010-09-08 02:36:52 +05303690
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05303691 v9fs_string_init(&glock.client_id);
3692 err = pdu_unmarshal(pdu, offset, "dbqqds", &fid, &glock.type,
3693 &glock.start, &glock.length, &glock.proc_id,
3694 &glock.client_id);
3695 if (err < 0) {
3696 goto out_nofid;
3697 }
Harsh Prateek Borac572f232011-10-12 19:11:25 +05303698 trace_v9fs_getlock(pdu->tag, pdu->id, fid,
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05303699 glock.type, glock.start, glock.length);
Harsh Prateek Borac572f232011-10-12 19:11:25 +05303700
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303701 fidp = get_fid(pdu, fid);
Aneesh Kumar K.Ve4e414a2011-05-07 17:21:38 +05303702 if (fidp == NULL) {
M. Mohan Kumar8f354002010-09-08 02:36:52 +05303703 err = -ENOENT;
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05303704 goto out_nofid;
M. Mohan Kumar8f354002010-09-08 02:36:52 +05303705 }
Aneesh Kumar K.Vcc720dd2011-10-25 12:10:40 +05303706 err = v9fs_co_fstat(pdu, fidp, &stbuf);
M. Mohan Kumar8f354002010-09-08 02:36:52 +05303707 if (err < 0) {
M. Mohan Kumar8f354002010-09-08 02:36:52 +05303708 goto out;
3709 }
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05303710 glock.type = P9_LOCK_TYPE_UNLCK;
3711 err = pdu_marshal(pdu, offset, "bqqds", glock.type,
3712 glock.start, glock.length, glock.proc_id,
3713 &glock.client_id);
3714 if (err < 0) {
3715 goto out;
3716 }
3717 err += offset;
3718 trace_v9fs_getlock_return(pdu->tag, pdu->id, glock.type, glock.start,
3719 glock.length, glock.proc_id);
M. Mohan Kumar8f354002010-09-08 02:36:52 +05303720out:
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303721 put_fid(pdu, fidp);
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05303722out_nofid:
Wei Liudc295f82015-12-02 15:00:14 +00003723 pdu_complete(pdu, err);
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05303724 v9fs_string_free(&glock.client_id);
M. Mohan Kumar8f354002010-09-08 02:36:52 +05303725}
3726
Greg Kurz8440e222016-10-17 14:13:58 +02003727static void coroutine_fn v9fs_mkdir(void *opaque)
M. Mohan Kumarb67592e2010-06-22 12:25:22 +05303728{
Venkateswararao Jujjuri (JV)ff060302011-05-18 14:18:05 -07003729 V9fsPDU *pdu = opaque;
Venkateswararao Jujjurie84861f2011-08-08 23:46:14 +05303730 size_t offset = 7;
M. Mohan Kumarb67592e2010-06-22 12:25:22 +05303731 int32_t fid;
Venkateswararao Jujjurie84861f2011-08-08 23:46:14 +05303732 struct stat stbuf;
Venkateswararao Jujjurie84861f2011-08-08 23:46:14 +05303733 V9fsQID qid;
Aneesh Kumar K.V02cb7f32011-05-24 15:10:56 +05303734 V9fsString name;
M. Mohan Kumarb67592e2010-06-22 12:25:22 +05303735 V9fsFidState *fidp;
3736 gid_t gid;
3737 int mode;
Venkateswararao Jujjurie84861f2011-08-08 23:46:14 +05303738 int err = 0;
M. Mohan Kumarb67592e2010-06-22 12:25:22 +05303739
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05303740 v9fs_string_init(&name);
3741 err = pdu_unmarshal(pdu, offset, "dsdd", &fid, &name, &mode, &gid);
3742 if (err < 0) {
3743 goto out_nofid;
3744 }
Harsh Prateek Borac572f232011-10-12 19:11:25 +05303745 trace_v9fs_mkdir(pdu->tag, pdu->id, fid, name.data, mode, gid);
3746
Greg Kurzfff39a72016-08-30 19:11:05 +02003747 if (name_is_illegal(name.data)) {
3748 err = -ENOENT;
3749 goto out_nofid;
3750 }
3751
Greg Kurz805b5d92016-08-30 19:13:11 +02003752 if (!strcmp(".", name.data) || !strcmp("..", name.data)) {
3753 err = -EEXIST;
3754 goto out_nofid;
3755 }
3756
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303757 fidp = get_fid(pdu, fid);
M. Mohan Kumarb67592e2010-06-22 12:25:22 +05303758 if (fidp == NULL) {
3759 err = -ENOENT;
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05303760 goto out_nofid;
M. Mohan Kumarb67592e2010-06-22 12:25:22 +05303761 }
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303762 err = v9fs_co_mkdir(pdu, fidp, &name, mode, fidp->uid, gid, &stbuf);
Venkateswararao Jujjurie84861f2011-08-08 23:46:14 +05303763 if (err < 0) {
3764 goto out;
3765 }
Antonios Motakis3b5ee9e2019-10-10 11:36:05 +02003766 err = stat_to_qid(pdu, &stbuf, &qid);
3767 if (err < 0) {
3768 goto out;
3769 }
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05303770 err = pdu_marshal(pdu, offset, "Q", &qid);
3771 if (err < 0) {
3772 goto out;
3773 }
3774 err += offset;
Aneesh Kumar K.V7999f7e2011-10-24 15:09:49 +05303775 trace_v9fs_mkdir_return(pdu->tag, pdu->id,
3776 qid.type, qid.version, qid.path, err);
M. Mohan Kumarb67592e2010-06-22 12:25:22 +05303777out:
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303778 put_fid(pdu, fidp);
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05303779out_nofid:
Wei Liudc295f82015-12-02 15:00:14 +00003780 pdu_complete(pdu, err);
Venkateswararao Jujjurie84861f2011-08-08 23:46:14 +05303781 v9fs_string_free(&name);
M. Mohan Kumarb67592e2010-06-22 12:25:22 +05303782}
3783
Greg Kurz8440e222016-10-17 14:13:58 +02003784static void coroutine_fn v9fs_xattrwalk(void *opaque)
Aneesh Kumar K.Vfa32ef82010-09-02 11:09:06 +05303785{
Aneesh Kumar K.V670185a2011-05-18 16:05:48 -07003786 int64_t size;
3787 V9fsString name;
3788 ssize_t err = 0;
3789 size_t offset = 7;
3790 int32_t fid, newfid;
3791 V9fsFidState *file_fidp;
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05303792 V9fsFidState *xattr_fidp = NULL;
Venkateswararao Jujjuri (JV)ff060302011-05-18 14:18:05 -07003793 V9fsPDU *pdu = opaque;
3794 V9fsState *s = pdu->s;
Aneesh Kumar K.Vfa32ef82010-09-02 11:09:06 +05303795
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05303796 v9fs_string_init(&name);
3797 err = pdu_unmarshal(pdu, offset, "dds", &fid, &newfid, &name);
3798 if (err < 0) {
3799 goto out_nofid;
3800 }
Harsh Prateek Borac572f232011-10-12 19:11:25 +05303801 trace_v9fs_xattrwalk(pdu->tag, pdu->id, fid, newfid, name.data);
3802
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303803 file_fidp = get_fid(pdu, fid);
Aneesh Kumar K.V670185a2011-05-18 16:05:48 -07003804 if (file_fidp == NULL) {
Aneesh Kumar K.Vfa32ef82010-09-02 11:09:06 +05303805 err = -ENOENT;
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05303806 goto out_nofid;
Aneesh Kumar K.Vfa32ef82010-09-02 11:09:06 +05303807 }
Aneesh Kumar K.V670185a2011-05-18 16:05:48 -07003808 xattr_fidp = alloc_fid(s, newfid);
3809 if (xattr_fidp == NULL) {
Aneesh Kumar K.Vfa32ef82010-09-02 11:09:06 +05303810 err = -EINVAL;
3811 goto out;
3812 }
Aneesh Kumar K.V2289be12011-09-09 15:14:18 +05303813 v9fs_path_copy(&xattr_fidp->path, &file_fidp->path);
Li Qiangba42ebb2016-10-17 14:13:58 +02003814 if (!v9fs_string_size(&name)) {
Aneesh Kumar K.Vfa32ef82010-09-02 11:09:06 +05303815 /*
3816 * listxattr request. Get the size first
3817 */
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303818 size = v9fs_co_llistxattr(pdu, &xattr_fidp->path, NULL, 0);
Aneesh Kumar K.V670185a2011-05-18 16:05:48 -07003819 if (size < 0) {
3820 err = size;
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05303821 clunk_fid(s, xattr_fidp->fid);
Aneesh Kumar K.V670185a2011-05-18 16:05:48 -07003822 goto out;
Aneesh Kumar K.Vfa32ef82010-09-02 11:09:06 +05303823 }
Aneesh Kumar K.V670185a2011-05-18 16:05:48 -07003824 /*
3825 * Read the xattr value
3826 */
3827 xattr_fidp->fs.xattr.len = size;
3828 xattr_fidp->fid_type = P9_FID_XATTR;
Li Qiangdd28fbb2016-11-01 12:00:40 +01003829 xattr_fidp->fs.xattr.xattrwalk_fid = true;
Keno Fischera6475022018-06-07 12:17:22 +02003830 xattr_fidp->fs.xattr.value = g_malloc0(size);
Aneesh Kumar K.V670185a2011-05-18 16:05:48 -07003831 if (size) {
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303832 err = v9fs_co_llistxattr(pdu, &xattr_fidp->path,
Aneesh Kumar K.V670185a2011-05-18 16:05:48 -07003833 xattr_fidp->fs.xattr.value,
3834 xattr_fidp->fs.xattr.len);
3835 if (err < 0) {
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05303836 clunk_fid(s, xattr_fidp->fid);
Aneesh Kumar K.V670185a2011-05-18 16:05:48 -07003837 goto out;
3838 }
3839 }
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05303840 err = pdu_marshal(pdu, offset, "q", size);
3841 if (err < 0) {
3842 goto out;
3843 }
3844 err += offset;
Aneesh Kumar K.Vfa32ef82010-09-02 11:09:06 +05303845 } else {
3846 /*
3847 * specific xattr fid. We check for xattr
3848 * presence also collect the xattr size
3849 */
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303850 size = v9fs_co_lgetxattr(pdu, &xattr_fidp->path,
Aneesh Kumar K.V670185a2011-05-18 16:05:48 -07003851 &name, NULL, 0);
3852 if (size < 0) {
3853 err = size;
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05303854 clunk_fid(s, xattr_fidp->fid);
Aneesh Kumar K.V670185a2011-05-18 16:05:48 -07003855 goto out;
Aneesh Kumar K.Vfa32ef82010-09-02 11:09:06 +05303856 }
Aneesh Kumar K.V670185a2011-05-18 16:05:48 -07003857 /*
3858 * Read the xattr value
3859 */
3860 xattr_fidp->fs.xattr.len = size;
3861 xattr_fidp->fid_type = P9_FID_XATTR;
Li Qiangdd28fbb2016-11-01 12:00:40 +01003862 xattr_fidp->fs.xattr.xattrwalk_fid = true;
Keno Fischera6475022018-06-07 12:17:22 +02003863 xattr_fidp->fs.xattr.value = g_malloc0(size);
Aneesh Kumar K.V670185a2011-05-18 16:05:48 -07003864 if (size) {
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303865 err = v9fs_co_lgetxattr(pdu, &xattr_fidp->path,
Aneesh Kumar K.V670185a2011-05-18 16:05:48 -07003866 &name, xattr_fidp->fs.xattr.value,
3867 xattr_fidp->fs.xattr.len);
3868 if (err < 0) {
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05303869 clunk_fid(s, xattr_fidp->fid);
Aneesh Kumar K.V670185a2011-05-18 16:05:48 -07003870 goto out;
3871 }
3872 }
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05303873 err = pdu_marshal(pdu, offset, "q", size);
3874 if (err < 0) {
3875 goto out;
3876 }
3877 err += offset;
Aneesh Kumar K.Vfa32ef82010-09-02 11:09:06 +05303878 }
Aneesh Kumar K.V7999f7e2011-10-24 15:09:49 +05303879 trace_v9fs_xattrwalk_return(pdu->tag, pdu->id, size);
Aneesh Kumar K.Vfa32ef82010-09-02 11:09:06 +05303880out:
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303881 put_fid(pdu, file_fidp);
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05303882 if (xattr_fidp) {
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303883 put_fid(pdu, xattr_fidp);
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05303884 }
3885out_nofid:
Wei Liudc295f82015-12-02 15:00:14 +00003886 pdu_complete(pdu, err);
Aneesh Kumar K.V670185a2011-05-18 16:05:48 -07003887 v9fs_string_free(&name);
Aneesh Kumar K.Vfa32ef82010-09-02 11:09:06 +05303888}
3889
Greg Kurz8440e222016-10-17 14:13:58 +02003890static void coroutine_fn v9fs_xattrcreate(void *opaque)
Aneesh Kumar K.V10b468b2010-09-02 11:09:07 +05303891{
Keno Fischeraca68972018-06-07 12:17:22 +02003892 int flags, rflags = 0;
Aneesh Kumar K.V10b468b2010-09-02 11:09:07 +05303893 int32_t fid;
Greg Kurz3b79ef22016-11-01 12:00:40 +01003894 uint64_t size;
Aneesh Kumar K.V10b468b2010-09-02 11:09:07 +05303895 ssize_t err = 0;
Aneesh Kumar K.Vf10ff582011-05-18 16:06:26 -07003896 V9fsString name;
3897 size_t offset = 7;
3898 V9fsFidState *file_fidp;
3899 V9fsFidState *xattr_fidp;
3900 V9fsPDU *pdu = opaque;
Aneesh Kumar K.V10b468b2010-09-02 11:09:07 +05303901
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05303902 v9fs_string_init(&name);
3903 err = pdu_unmarshal(pdu, offset, "dsqd", &fid, &name, &size, &flags);
3904 if (err < 0) {
3905 goto out_nofid;
3906 }
Harsh Prateek Borac572f232011-10-12 19:11:25 +05303907 trace_v9fs_xattrcreate(pdu->tag, pdu->id, fid, name.data, size, flags);
Aneesh Kumar K.V10b468b2010-09-02 11:09:07 +05303908
Keno Fischeraca68972018-06-07 12:17:22 +02003909 if (flags & ~(P9_XATTR_CREATE | P9_XATTR_REPLACE)) {
3910 err = -EINVAL;
3911 goto out_nofid;
3912 }
3913
3914 if (flags & P9_XATTR_CREATE) {
3915 rflags |= XATTR_CREATE;
3916 }
3917
3918 if (flags & P9_XATTR_REPLACE) {
3919 rflags |= XATTR_REPLACE;
3920 }
3921
Greg Kurz3b79ef22016-11-01 12:00:40 +01003922 if (size > XATTR_SIZE_MAX) {
3923 err = -E2BIG;
3924 goto out_nofid;
3925 }
3926
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303927 file_fidp = get_fid(pdu, fid);
Aneesh Kumar K.Vf10ff582011-05-18 16:06:26 -07003928 if (file_fidp == NULL) {
Aneesh Kumar K.V10b468b2010-09-02 11:09:07 +05303929 err = -EINVAL;
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05303930 goto out_nofid;
Aneesh Kumar K.V10b468b2010-09-02 11:09:07 +05303931 }
Greg Kurzdd654e02016-11-01 12:00:40 +01003932 if (file_fidp->fid_type != P9_FID_NONE) {
3933 err = -EINVAL;
3934 goto out_put_fid;
3935 }
3936
Aneesh Kumar K.V10b468b2010-09-02 11:09:07 +05303937 /* Make the file fid point to xattr */
Aneesh Kumar K.Vf10ff582011-05-18 16:06:26 -07003938 xattr_fidp = file_fidp;
3939 xattr_fidp->fid_type = P9_FID_XATTR;
3940 xattr_fidp->fs.xattr.copied_len = 0;
Li Qiangdd28fbb2016-11-01 12:00:40 +01003941 xattr_fidp->fs.xattr.xattrwalk_fid = false;
Aneesh Kumar K.Vf10ff582011-05-18 16:06:26 -07003942 xattr_fidp->fs.xattr.len = size;
Keno Fischeraca68972018-06-07 12:17:22 +02003943 xattr_fidp->fs.xattr.flags = rflags;
Aneesh Kumar K.Vf10ff582011-05-18 16:06:26 -07003944 v9fs_string_init(&xattr_fidp->fs.xattr.name);
3945 v9fs_string_copy(&xattr_fidp->fs.xattr.name, &name);
Li Qiangeb687602016-10-17 14:13:58 +02003946 xattr_fidp->fs.xattr.value = g_malloc0(size);
Aneesh Kumar K.Vf10ff582011-05-18 16:06:26 -07003947 err = offset;
Greg Kurzdd654e02016-11-01 12:00:40 +01003948out_put_fid:
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303949 put_fid(pdu, file_fidp);
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05303950out_nofid:
Wei Liudc295f82015-12-02 15:00:14 +00003951 pdu_complete(pdu, err);
Aneesh Kumar K.Vf10ff582011-05-18 16:06:26 -07003952 v9fs_string_free(&name);
Aneesh Kumar K.V10b468b2010-09-02 11:09:07 +05303953}
Aneesh Kumar K.Vfa32ef82010-09-02 11:09:06 +05303954
Greg Kurz8440e222016-10-17 14:13:58 +02003955static void coroutine_fn v9fs_readlink(void *opaque)
M. Mohan Kumardf0973a2010-09-14 15:08:25 +05303956{
Venkateswararao Jujjuri (JV)ff060302011-05-18 14:18:05 -07003957 V9fsPDU *pdu = opaque;
Venkateswararao Jujjuri7a5ca312011-08-08 23:36:41 +05303958 size_t offset = 7;
3959 V9fsString target;
M. Mohan Kumardf0973a2010-09-14 15:08:25 +05303960 int32_t fid;
M. Mohan Kumardf0973a2010-09-14 15:08:25 +05303961 int err = 0;
3962 V9fsFidState *fidp;
3963
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05303964 err = pdu_unmarshal(pdu, offset, "d", &fid);
3965 if (err < 0) {
3966 goto out_nofid;
3967 }
Harsh Prateek Borac572f232011-10-12 19:11:25 +05303968 trace_v9fs_readlink(pdu->tag, pdu->id, fid);
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303969 fidp = get_fid(pdu, fid);
M. Mohan Kumardf0973a2010-09-14 15:08:25 +05303970 if (fidp == NULL) {
3971 err = -ENOENT;
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05303972 goto out_nofid;
M. Mohan Kumardf0973a2010-09-14 15:08:25 +05303973 }
3974
Venkateswararao Jujjuri7a5ca312011-08-08 23:36:41 +05303975 v9fs_string_init(&target);
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303976 err = v9fs_co_readlink(pdu, &fidp->path, &target);
Venkateswararao Jujjuri7a5ca312011-08-08 23:36:41 +05303977 if (err < 0) {
3978 goto out;
3979 }
M. Mohan Kumarddca7f82011-12-14 13:49:13 +05303980 err = pdu_marshal(pdu, offset, "s", &target);
3981 if (err < 0) {
3982 v9fs_string_free(&target);
3983 goto out;
3984 }
3985 err += offset;
Aneesh Kumar K.V7999f7e2011-10-24 15:09:49 +05303986 trace_v9fs_readlink_return(pdu->tag, pdu->id, target.data);
Venkateswararao Jujjuri7a5ca312011-08-08 23:36:41 +05303987 v9fs_string_free(&target);
M. Mohan Kumardf0973a2010-09-14 15:08:25 +05303988out:
Aneesh Kumar K.Vbccacf62011-08-02 11:36:17 +05303989 put_fid(pdu, fidp);
Aneesh Kumar K.V84dfb922011-05-18 17:38:07 +05303990out_nofid:
Wei Liudc295f82015-12-02 15:00:14 +00003991 pdu_complete(pdu, err);
M. Mohan Kumardf0973a2010-09-14 15:08:25 +05303992}
3993
Venkateswararao Jujjuri (JV)ff060302011-05-18 14:18:05 -07003994static CoroutineEntry *pdu_co_handlers[] = {
Sripathi Kodic18e2f92010-06-09 14:57:57 +05303995 [P9_TREADDIR] = v9fs_readdir,
M. Mohan Kumarbe940c82010-05-10 12:11:03 +05303996 [P9_TSTATFS] = v9fs_statfs,
Sripathi Kodi00ede4c2010-07-20 11:44:41 +05303997 [P9_TGETATTR] = v9fs_getattr,
Sripathi Kodic79ce732010-06-17 18:18:47 +05303998 [P9_TSETATTR] = v9fs_setattr,
Aneesh Kumar K.Vfa32ef82010-09-02 11:09:06 +05303999 [P9_TXATTRWALK] = v9fs_xattrwalk,
Aneesh Kumar K.V10b468b2010-09-02 11:09:07 +05304000 [P9_TXATTRCREATE] = v9fs_xattrcreate,
M. Mohan Kumar5268cec2010-06-22 12:24:09 +05304001 [P9_TMKNOD] = v9fs_mknod,
M. Mohan Kumarc7b4b0b2010-06-22 12:29:41 +05304002 [P9_TRENAME] = v9fs_rename,
M. Mohan Kumar82cc3ee2010-09-08 02:19:32 +05304003 [P9_TLOCK] = v9fs_lock,
M. Mohan Kumar8f354002010-09-08 02:36:52 +05304004 [P9_TGETLOCK] = v9fs_getlock,
Aneesh Kumar K.V89bf6592011-05-23 23:24:41 +05304005 [P9_TRENAMEAT] = v9fs_renameat,
M. Mohan Kumardf0973a2010-09-14 15:08:25 +05304006 [P9_TREADLINK] = v9fs_readlink,
Aneesh Kumar K.V7834cf72011-09-09 15:07:01 +05304007 [P9_TUNLINKAT] = v9fs_unlinkat,
M. Mohan Kumarb67592e2010-06-22 12:25:22 +05304008 [P9_TMKDIR] = v9fs_mkdir,
Anthony Liguori9f107512010-04-29 17:44:44 +05304009 [P9_TVERSION] = v9fs_version,
M. Mohan Kumar771e9d42010-06-22 19:47:04 +05304010 [P9_TLOPEN] = v9fs_open,
Anthony Liguori9f107512010-04-29 17:44:44 +05304011 [P9_TATTACH] = v9fs_attach,
4012 [P9_TSTAT] = v9fs_stat,
4013 [P9_TWALK] = v9fs_walk,
4014 [P9_TCLUNK] = v9fs_clunk,
Venkateswararao Jujjuri (JV)b41e95d2010-09-22 17:18:33 -07004015 [P9_TFSYNC] = v9fs_fsync,
Anthony Liguori9f107512010-04-29 17:44:44 +05304016 [P9_TOPEN] = v9fs_open,
4017 [P9_TREAD] = v9fs_read,
4018#if 0
4019 [P9_TAUTH] = v9fs_auth,
4020#endif
4021 [P9_TFLUSH] = v9fs_flush,
Venkateswararao Jujjuri (JV)b2c224b2010-06-09 11:21:15 -07004022 [P9_TLINK] = v9fs_link,
Venkateswararao Jujjuri (JV)08c60fc2010-06-09 14:02:08 -07004023 [P9_TSYMLINK] = v9fs_symlink,
Anthony Liguori9f107512010-04-29 17:44:44 +05304024 [P9_TCREATE] = v9fs_create,
Venkateswararao Jujjuri (JV)c1568af2010-06-17 18:27:24 -07004025 [P9_TLCREATE] = v9fs_lcreate,
Anthony Liguori9f107512010-04-29 17:44:44 +05304026 [P9_TWRITE] = v9fs_write,
4027 [P9_TWSTAT] = v9fs_wstat,
4028 [P9_TREMOVE] = v9fs_remove,
4029};
4030
Greg Kurz8440e222016-10-17 14:13:58 +02004031static void coroutine_fn v9fs_op_not_supp(void *opaque)
Aneesh Kumar K.V5c3234c2011-06-01 12:35:14 +05304032{
Venkateswararao Jujjuri (JV)ff060302011-05-18 14:18:05 -07004033 V9fsPDU *pdu = opaque;
Wei Liudc295f82015-12-02 15:00:14 +00004034 pdu_complete(pdu, -EOPNOTSUPP);
Aneesh Kumar K.V5c3234c2011-06-01 12:35:14 +05304035}
4036
Greg Kurz8440e222016-10-17 14:13:58 +02004037static void coroutine_fn v9fs_fs_ro(void *opaque)
M. Mohan Kumar2c74c2c2011-10-25 12:10:39 +05304038{
4039 V9fsPDU *pdu = opaque;
Wei Liudc295f82015-12-02 15:00:14 +00004040 pdu_complete(pdu, -EROFS);
M. Mohan Kumar2c74c2c2011-10-25 12:10:39 +05304041}
4042
4043static inline bool is_read_only_op(V9fsPDU *pdu)
4044{
4045 switch (pdu->id) {
4046 case P9_TREADDIR:
4047 case P9_TSTATFS:
4048 case P9_TGETATTR:
4049 case P9_TXATTRWALK:
4050 case P9_TLOCK:
4051 case P9_TGETLOCK:
4052 case P9_TREADLINK:
4053 case P9_TVERSION:
4054 case P9_TLOPEN:
4055 case P9_TATTACH:
4056 case P9_TSTAT:
4057 case P9_TWALK:
4058 case P9_TCLUNK:
4059 case P9_TFSYNC:
4060 case P9_TOPEN:
4061 case P9_TREAD:
4062 case P9_TAUTH:
4063 case P9_TFLUSH:
4064 return 1;
4065 default:
4066 return 0;
4067 }
4068}
4069
Greg Kurz506f3272017-05-25 10:30:13 +02004070void pdu_submit(V9fsPDU *pdu, P9MsgHeader *hdr)
Anthony Liguori9f107512010-04-29 17:44:44 +05304071{
Venkateswararao Jujjuri (JV)ff060302011-05-18 14:18:05 -07004072 Coroutine *co;
4073 CoroutineEntry *handler;
Wei Liuad38ce92015-12-02 12:06:28 +00004074 V9fsState *s = pdu->s;
Anthony Liguori9f107512010-04-29 17:44:44 +05304075
Greg Kurz506f3272017-05-25 10:30:13 +02004076 pdu->size = le32_to_cpu(hdr->size_le);
4077 pdu->id = hdr->id;
4078 pdu->tag = le16_to_cpu(hdr->tag_le);
4079
Venkateswararao Jujjuri (JV)ff060302011-05-18 14:18:05 -07004080 if (pdu->id >= ARRAY_SIZE(pdu_co_handlers) ||
4081 (pdu_co_handlers[pdu->id] == NULL)) {
Aneesh Kumar K.V5c3234c2011-06-01 12:35:14 +05304082 handler = v9fs_op_not_supp;
Greg Kurzd1471232018-01-08 11:18:22 +01004083 } else if (is_ro_export(&s->ctx) && !is_read_only_op(pdu)) {
4084 handler = v9fs_fs_ro;
Aneesh Kumar K.V5c3234c2011-06-01 12:35:14 +05304085 } else {
Venkateswararao Jujjuri (JV)ff060302011-05-18 14:18:05 -07004086 handler = pdu_co_handlers[pdu->id];
Aneesh Kumar K.V5c3234c2011-06-01 12:35:14 +05304087 }
M. Mohan Kumar2c74c2c2011-10-25 12:10:39 +05304088
Greg Kurz506f3272017-05-25 10:30:13 +02004089 qemu_co_queue_init(&pdu->complete);
Paolo Bonzini0b8b8752016-07-04 19:10:01 +02004090 co = qemu_coroutine_create(handler, pdu);
4091 qemu_coroutine_enter(co);
Anthony Liguori9f107512010-04-29 17:44:44 +05304092}
4093
Wei Liu2a0c56a2015-12-03 11:55:49 +00004094/* Returns 0 on success, 1 on failure. */
Greg Kurz066eb002018-02-01 21:21:27 +01004095int v9fs_device_realize_common(V9fsState *s, const V9fsTransport *t,
4096 Error **errp)
Wei Liu2a0c56a2015-12-03 11:55:49 +00004097{
Vladimir Sementsov-Ogievskiy92c45122020-07-07 18:50:35 +02004098 ERRP_GUARD();
Wei Liu2a0c56a2015-12-03 11:55:49 +00004099 int i, len;
4100 struct stat stat;
4101 FsDriverEntry *fse;
4102 V9fsPath path;
4103 int rc = 1;
4104
Greg Kurz066eb002018-02-01 21:21:27 +01004105 assert(!s->transport);
4106 s->transport = t;
4107
Wei Liu2a0c56a2015-12-03 11:55:49 +00004108 /* initialize pdu allocator */
4109 QLIST_INIT(&s->free_list);
4110 QLIST_INIT(&s->active_list);
Greg Kurz0d782892017-01-13 18:18:20 +01004111 for (i = 0; i < MAX_REQ; i++) {
Stefano Stabellini583f21f2017-01-03 17:28:44 +01004112 QLIST_INSERT_HEAD(&s->free_list, &s->pdus[i], next);
4113 s->pdus[i].s = s;
4114 s->pdus[i].idx = i;
Wei Liu2a0c56a2015-12-03 11:55:49 +00004115 }
4116
4117 v9fs_path_init(&path);
4118
4119 fse = get_fsdev_fsentry(s->fsconf.fsdev_id);
4120
4121 if (!fse) {
4122 /* We don't have a fsdev identified by fsdev_id */
4123 error_setg(errp, "9pfs device couldn't find fsdev with the "
4124 "id = %s",
4125 s->fsconf.fsdev_id ? s->fsconf.fsdev_id : "NULL");
4126 goto out;
4127 }
4128
4129 if (!s->fsconf.tag) {
4130 /* we haven't specified a mount_tag */
4131 error_setg(errp, "fsdev with id %s needs mount_tag arguments",
4132 s->fsconf.fsdev_id);
4133 goto out;
4134 }
4135
4136 s->ctx.export_flags = fse->export_flags;
4137 s->ctx.fs_root = g_strdup(fse->path);
4138 s->ctx.exops.get_st_gen = NULL;
4139 len = strlen(s->fsconf.tag);
4140 if (len > MAX_TAG_LEN - 1) {
4141 error_setg(errp, "mount tag '%s' (%d bytes) is longer than "
4142 "maximum (%d bytes)", s->fsconf.tag, len, MAX_TAG_LEN - 1);
4143 goto out;
4144 }
4145
4146 s->tag = g_strdup(s->fsconf.tag);
4147 s->ctx.uid = -1;
4148
4149 s->ops = fse->ops;
4150
Tobias Schrammb96feb22017-06-29 15:11:50 +02004151 s->ctx.fmode = fse->fmode;
4152 s->ctx.dmode = fse->dmode;
4153
Greg Kurzfeabd6c2021-01-18 15:22:59 +01004154 QSIMPLEQ_INIT(&s->fid_list);
Wei Liu2a0c56a2015-12-03 11:55:49 +00004155 qemu_co_rwlock_init(&s->rename_lock);
4156
Greg Kurz65603a82018-01-08 11:18:23 +01004157 if (s->ops->init(&s->ctx, errp) < 0) {
4158 error_prepend(errp, "cannot initialize fsdev '%s': ",
4159 s->fsconf.fsdev_id);
Wei Liu2a0c56a2015-12-03 11:55:49 +00004160 goto out;
4161 }
4162
4163 /*
4164 * Check details of export path, We need to use fs driver
4165 * call back to do that. Since we are in the init path, we don't
4166 * use co-routines here.
4167 */
4168 if (s->ops->name_to_path(&s->ctx, NULL, "/", &path) < 0) {
4169 error_setg(errp,
4170 "error in converting name to path %s", strerror(errno));
4171 goto out;
4172 }
4173 if (s->ops->lstat(&s->ctx, &path, &stat)) {
4174 error_setg(errp, "share path %s does not exist", fse->path);
4175 goto out;
4176 } else if (!S_ISDIR(stat.st_mode)) {
4177 error_setg(errp, "share path %s is not a directory", fse->path);
4178 goto out;
4179 }
Pradeep Jagadeeshb8bbdb82017-02-28 10:31:46 +01004180
Antonios Motakis3b5ee9e2019-10-10 11:36:05 +02004181 s->dev_id = stat.st_dev;
4182
Christian Schoenebeck6b6aa822019-10-07 17:02:45 +02004183 /* init inode remapping : */
4184 /* hash table for variable length inode suffixes */
4185 qpd_table_init(&s->qpd_table);
4186 /* hash table for slow/full inode remapping (most users won't need it) */
4187 qpf_table_init(&s->qpf_table);
4188 /* hash table for quick inode remapping */
Antonios Motakis1a6ed332019-10-10 11:36:05 +02004189 qpp_table_init(&s->qpp_table);
Christian Schoenebeck6b6aa822019-10-07 17:02:45 +02004190 s->qp_ndevices = 0;
4191 s->qp_affix_next = 1; /* reserve 0 to detect overflow */
Antonios Motakisf3fe4a22019-10-07 17:02:45 +02004192 s->qp_fullpath_next = 1;
Antonios Motakis1a6ed332019-10-10 11:36:05 +02004193
Pradeep Jagadeeshb8bbdb82017-02-28 10:31:46 +01004194 s->ctx.fst = &fse->fst;
4195 fsdev_throttle_init(s->ctx.fst);
4196
Wei Liu2a0c56a2015-12-03 11:55:49 +00004197 rc = 0;
4198out:
4199 if (rc) {
Markus Armbrusterb69c3c22020-05-05 17:29:24 +02004200 v9fs_device_unrealize_common(s);
Wei Liu2a0c56a2015-12-03 11:55:49 +00004201 }
Greg Kurzc0da0cb2019-10-10 11:36:04 +02004202 v9fs_path_free(&path);
Wei Liu2a0c56a2015-12-03 11:55:49 +00004203 return rc;
4204}
4205
Markus Armbrusterb69c3c22020-05-05 17:29:24 +02004206void v9fs_device_unrealize_common(V9fsState *s)
Wei Liu2a0c56a2015-12-03 11:55:49 +00004207{
Greg Kurzc0da0cb2019-10-10 11:36:04 +02004208 if (s->ops && s->ops->cleanup) {
Li Qiang702dbcc2016-11-23 13:53:34 +01004209 s->ops->cleanup(&s->ctx);
4210 }
Greg Kurzc0da0cb2019-10-10 11:36:04 +02004211 if (s->ctx.fst) {
4212 fsdev_throttle_cleanup(s->ctx.fst);
4213 }
Wei Liu2a0c56a2015-12-03 11:55:49 +00004214 g_free(s->tag);
Christian Schoenebeck6b6aa822019-10-07 17:02:45 +02004215 qp_table_destroy(&s->qpd_table);
Antonios Motakisf3fe4a22019-10-07 17:02:45 +02004216 qp_table_destroy(&s->qpp_table);
4217 qp_table_destroy(&s->qpf_table);
Li Qiang47747182016-11-23 13:53:34 +01004218 g_free(s->ctx.fs_root);
Wei Liu2a0c56a2015-12-03 11:55:49 +00004219}
4220
Greg Kurz0e44a0f2016-10-17 14:13:58 +02004221typedef struct VirtfsCoResetData {
4222 V9fsPDU pdu;
4223 bool done;
4224} VirtfsCoResetData;
4225
4226static void coroutine_fn virtfs_co_reset(void *opaque)
4227{
4228 VirtfsCoResetData *data = opaque;
4229
4230 virtfs_reset(&data->pdu);
4231 data->done = true;
4232}
4233
4234void v9fs_reset(V9fsState *s)
4235{
4236 VirtfsCoResetData data = { .pdu = { .s = s }, .done = false };
4237 Coroutine *co;
4238
4239 while (!QLIST_EMPTY(&s->active_list)) {
4240 aio_poll(qemu_get_aio_context(), true);
4241 }
4242
4243 co = qemu_coroutine_create(virtfs_co_reset, &data);
4244 qemu_coroutine_enter(co);
4245
4246 while (!data.done) {
4247 aio_poll(qemu_get_aio_context(), true);
4248 }
4249}
4250
Wei Liu72a18972016-01-07 18:40:09 +00004251static void __attribute__((__constructor__)) v9fs_set_fd_limit(void)
Aneesh Kumar K.V7a462742011-05-18 15:40:57 +05304252{
4253 struct rlimit rlim;
4254 if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) {
Greg Kurz63325b12016-01-22 15:12:17 +01004255 error_report("Failed to get the resource limit");
Aneesh Kumar K.V7a462742011-05-18 15:40:57 +05304256 exit(1);
4257 }
Xinhao Zhang01011732020-10-30 12:35:13 +08004258 open_fd_hw = rlim.rlim_cur - MIN(400, rlim.rlim_cur / 3);
4259 open_fd_rc = rlim.rlim_cur / 2;
Aneesh Kumar K.V7a462742011-05-18 15:40:57 +05304260}