mirror of
https://gitlab.com/qemu-project/qemu
synced 2024-10-15 23:43:55 +00:00
9pfs: performance, Windows host prep, tests restructure
* Highlight of this PR is Linus Heckemann's GHashTable patch which brings massive general performance improvements of 9p server somewhere between factor 6 .. 12. * Bin Meng's g_mkdir patch is a preparatory patch for upcoming Windows host support of 9p server. * The rest of the patches in this PR are 9p test code restructuring and refactoring changes to improve readability and to ease maintenance of 9p test code on the long-term. -----BEGIN PGP SIGNATURE----- iQJLBAABCgA1FiEEltjREM96+AhPiFkBNMK1h2Wkc5UFAmNWbs8XHHFlbXVfb3Nz QGNydWRlYnl0ZS5jb20ACgkQNMK1h2Wkc5V4cw/8CqoSJqoJixlP8kAGDYWq3CgF SKd09rIzLSWyyufAoZr1TqLwRrvEQRlZJSpL4fGvRpQLv0IQCu4x59ohHRob25Tm Fe7IxYBNuBwLW4yu+Y7FaujeGoYAi9Qw5q4ijq3/aSSiIeuXySKB2JmW71CQ+Tbe uwivsnMtWzQ7qsNwrtXYbxDs7UGkdsiW2sEQUS26GMApAXZoB+38hwtTW2Y9MOrC 58JuZza/fUVPzo0V1D0ggRawb5O2VTF5fz8aGFG4FvoyIW6DDZFSfnyre9QxivOl 5McWwSQ/D04vdEK9ornGPYr9YRGuP8g07p1EW9OfKeie4I41e9pS3UminK5lVCgo SfBHzz96efM5XR+Wnl4yVKowivmTqjwUU8lDqW2eB/7YBRuYUzrpxYe//UPv4q1J zaQV3pgwFAVkVJCnkcLCa1JQbH581bXSsuRlDdYqoRYfyzXoxbywNjvn9BXE0PrG WRecS//GyN3GVZYxMwb3H052110pYsYIg2YZ2H4QiqCwpEHHvy+L/ZXm19vbDm7B GYJQPUK8/y0NGwZsUYcUSx1TWlU9ZPwrbqZfv7e7+B6FL4VNjdaqb8PvS9admWSq LOSzrVVIus+nb7tP99d1Fb6oRyCy3x8E48gTr5UtTJHC4SAw/OBJmem6GOc/D490 H7Dq8Y27qsQ6fT7iPm8= =MxSG -----END PGP SIGNATURE----- Merge tag 'pull-9p-20221024' of https://github.com/cschoenebeck/qemu into staging 9pfs: performance, Windows host prep, tests restructure * Highlight of this PR is Linus Heckemann's GHashTable patch which brings massive general performance improvements of 9p server somewhere between factor 6 .. 12. * Bin Meng's g_mkdir patch is a preparatory patch for upcoming Windows host support of 9p server. * The rest of the patches in this PR are 9p test code restructuring and refactoring changes to improve readability and to ease maintenance of 9p test code on the long-term. # -----BEGIN PGP SIGNATURE----- # # iQJLBAABCgA1FiEEltjREM96+AhPiFkBNMK1h2Wkc5UFAmNWbs8XHHFlbXVfb3Nz # QGNydWRlYnl0ZS5jb20ACgkQNMK1h2Wkc5V4cw/8CqoSJqoJixlP8kAGDYWq3CgF # SKd09rIzLSWyyufAoZr1TqLwRrvEQRlZJSpL4fGvRpQLv0IQCu4x59ohHRob25Tm # Fe7IxYBNuBwLW4yu+Y7FaujeGoYAi9Qw5q4ijq3/aSSiIeuXySKB2JmW71CQ+Tbe # uwivsnMtWzQ7qsNwrtXYbxDs7UGkdsiW2sEQUS26GMApAXZoB+38hwtTW2Y9MOrC # 58JuZza/fUVPzo0V1D0ggRawb5O2VTF5fz8aGFG4FvoyIW6DDZFSfnyre9QxivOl # 5McWwSQ/D04vdEK9ornGPYr9YRGuP8g07p1EW9OfKeie4I41e9pS3UminK5lVCgo # SfBHzz96efM5XR+Wnl4yVKowivmTqjwUU8lDqW2eB/7YBRuYUzrpxYe//UPv4q1J # zaQV3pgwFAVkVJCnkcLCa1JQbH581bXSsuRlDdYqoRYfyzXoxbywNjvn9BXE0PrG # WRecS//GyN3GVZYxMwb3H052110pYsYIg2YZ2H4QiqCwpEHHvy+L/ZXm19vbDm7B # GYJQPUK8/y0NGwZsUYcUSx1TWlU9ZPwrbqZfv7e7+B6FL4VNjdaqb8PvS9admWSq # LOSzrVVIus+nb7tP99d1Fb6oRyCy3x8E48gTr5UtTJHC4SAw/OBJmem6GOc/D490 # H7Dq8Y27qsQ6fT7iPm8= # =MxSG # -----END PGP SIGNATURE----- # gpg: Signature made Mon 24 Oct 2022 06:54:07 EDT # gpg: using RSA key 96D8D110CF7AF8084F88590134C2B58765A47395 # gpg: issuer "qemu_oss@crudebyte.com" # gpg: Good signature from "Christian Schoenebeck <qemu_oss@crudebyte.com>" [unknown] # gpg: WARNING: The key's User ID is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: ECAB 1A45 4014 1413 BA38 4926 30DB 47C3 A012 D5F4 # Subkey fingerprint: 96D8 D110 CF7A F808 4F88 5901 34C2 B587 65A4 7395 * tag 'pull-9p-20221024' of https://github.com/cschoenebeck/qemu: (23 commits) tests/9p: remove unnecessary g_strdup() calls tests/9p: merge v9fs_tunlinkat() and do_unlinkat() tests/9p: merge v9fs_tlink() and do_hardlink() tests/9p: merge v9fs_tsymlink() and do_symlink() tests/9p: merge v9fs_tlcreate() and do_lcreate() tests/9p: merge v9fs_tmkdir() and do_mkdir() tests/9p: convert v9fs_tflush() to declarative arguments tests/9p: simplify callers of twrite() tests/9p: convert v9fs_twrite() to declarative arguments tests/9p: simplify callers of tlopen() tests/9p: convert v9fs_tlopen() to declarative arguments tests/9p: simplify callers of treaddir() tests/9p: convert v9fs_treaddir() to declarative arguments tests/9p: simplify callers of tgetattr() tests/9p: convert v9fs_tgetattr() to declarative arguments tests/9p: simplify callers of tattach() tests/9p: merge v9fs_tattach(), do_attach(), do_attach_rqid() tests/9p: merge v9fs_tversion() and do_version() tests/9p: simplify callers of twalk() tests/9p: merge *walk*() functions ... Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
commit
e750a7ace4
|
@ -10,6 +10,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
|
#include <glib/gstdio.h>
|
||||||
#include <sys/resource.h>
|
#include <sys/resource.h>
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#include <syslog.h>
|
#include <syslog.h>
|
||||||
|
@ -639,7 +640,7 @@ static int do_create_others(int type, struct iovec *iovec)
|
||||||
if (retval < 0) {
|
if (retval < 0) {
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
retval = mkdir(path.data, mode);
|
retval = g_mkdir(path.data, mode);
|
||||||
break;
|
break;
|
||||||
case T_SYMLINK:
|
case T_SYMLINK:
|
||||||
retval = proxy_unmarshal(iovec, offset, "ss", &oldpath, &path);
|
retval = proxy_unmarshal(iovec, offset, "ss", &oldpath, &path);
|
||||||
|
|
144
hw/9pfs/9p.c
144
hw/9pfs/9p.c
|
@ -256,7 +256,8 @@ static size_t v9fs_string_size(V9fsString *str)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* returns 0 if fid got re-opened, 1 if not, < 0 on error */
|
* returns 0 if fid got re-opened, 1 if not, < 0 on error
|
||||||
|
*/
|
||||||
static int coroutine_fn v9fs_reopen_fid(V9fsPDU *pdu, V9fsFidState *f)
|
static int coroutine_fn v9fs_reopen_fid(V9fsPDU *pdu, V9fsFidState *f)
|
||||||
{
|
{
|
||||||
int err = 1;
|
int err = 1;
|
||||||
|
@ -282,9 +283,9 @@ static V9fsFidState *coroutine_fn get_fid(V9fsPDU *pdu, int32_t fid)
|
||||||
V9fsFidState *f;
|
V9fsFidState *f;
|
||||||
V9fsState *s = pdu->s;
|
V9fsState *s = pdu->s;
|
||||||
|
|
||||||
QSIMPLEQ_FOREACH(f, &s->fid_list, next) {
|
f = g_hash_table_lookup(s->fids, GINT_TO_POINTER(fid));
|
||||||
|
if (f) {
|
||||||
BUG_ON(f->clunked);
|
BUG_ON(f->clunked);
|
||||||
if (f->fid == fid) {
|
|
||||||
/*
|
/*
|
||||||
* Update the fid ref upfront so that
|
* Update the fid ref upfront so that
|
||||||
* we don't get reclaimed when we yield
|
* we don't get reclaimed when we yield
|
||||||
|
@ -309,7 +310,6 @@ static V9fsFidState *coroutine_fn get_fid(V9fsPDU *pdu, int32_t fid)
|
||||||
f->flags |= FID_REFERENCED;
|
f->flags |= FID_REFERENCED;
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,13 +317,12 @@ static V9fsFidState *alloc_fid(V9fsState *s, int32_t fid)
|
||||||
{
|
{
|
||||||
V9fsFidState *f;
|
V9fsFidState *f;
|
||||||
|
|
||||||
QSIMPLEQ_FOREACH(f, &s->fid_list, next) {
|
f = g_hash_table_lookup(s->fids, GINT_TO_POINTER(fid));
|
||||||
|
if (f) {
|
||||||
/* If fid is already there return NULL */
|
/* If fid is already there return NULL */
|
||||||
BUG_ON(f->clunked);
|
BUG_ON(f->clunked);
|
||||||
if (f->fid == fid) {
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
f = g_new0(V9fsFidState, 1);
|
f = g_new0(V9fsFidState, 1);
|
||||||
f->fid = fid;
|
f->fid = fid;
|
||||||
f->fid_type = P9_FID_NONE;
|
f->fid_type = P9_FID_NONE;
|
||||||
|
@ -333,7 +332,7 @@ static V9fsFidState *alloc_fid(V9fsState *s, int32_t fid)
|
||||||
* reclaim won't close the file descriptor
|
* reclaim won't close the file descriptor
|
||||||
*/
|
*/
|
||||||
f->flags |= FID_REFERENCED;
|
f->flags |= FID_REFERENCED;
|
||||||
QSIMPLEQ_INSERT_TAIL(&s->fid_list, f, next);
|
g_hash_table_insert(s->fids, GINT_TO_POINTER(fid), f);
|
||||||
|
|
||||||
v9fs_readdir_init(s->proto_version, &f->fs.dir);
|
v9fs_readdir_init(s->proto_version, &f->fs.dir);
|
||||||
v9fs_readdir_init(s->proto_version, &f->fs_reclaim.dir);
|
v9fs_readdir_init(s->proto_version, &f->fs_reclaim.dir);
|
||||||
|
@ -424,13 +423,13 @@ static V9fsFidState *clunk_fid(V9fsState *s, int32_t fid)
|
||||||
{
|
{
|
||||||
V9fsFidState *fidp;
|
V9fsFidState *fidp;
|
||||||
|
|
||||||
QSIMPLEQ_FOREACH(fidp, &s->fid_list, next) {
|
/* TODO: Use g_hash_table_steal_extended() instead? */
|
||||||
if (fidp->fid == fid) {
|
fidp = g_hash_table_lookup(s->fids, GINT_TO_POINTER(fid));
|
||||||
QSIMPLEQ_REMOVE(&s->fid_list, fidp, V9fsFidState, next);
|
if (fidp) {
|
||||||
|
g_hash_table_remove(s->fids, GINT_TO_POINTER(fid));
|
||||||
fidp->clunked = true;
|
fidp->clunked = true;
|
||||||
return fidp;
|
return fidp;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -439,10 +438,15 @@ void coroutine_fn v9fs_reclaim_fd(V9fsPDU *pdu)
|
||||||
int reclaim_count = 0;
|
int reclaim_count = 0;
|
||||||
V9fsState *s = pdu->s;
|
V9fsState *s = pdu->s;
|
||||||
V9fsFidState *f;
|
V9fsFidState *f;
|
||||||
|
GHashTableIter iter;
|
||||||
|
gpointer fid;
|
||||||
|
|
||||||
|
g_hash_table_iter_init(&iter, s->fids);
|
||||||
|
|
||||||
QSLIST_HEAD(, V9fsFidState) reclaim_list =
|
QSLIST_HEAD(, V9fsFidState) reclaim_list =
|
||||||
QSLIST_HEAD_INITIALIZER(reclaim_list);
|
QSLIST_HEAD_INITIALIZER(reclaim_list);
|
||||||
|
|
||||||
QSIMPLEQ_FOREACH(f, &s->fid_list, next) {
|
while (g_hash_table_iter_next(&iter, &fid, (gpointer *) &f)) {
|
||||||
/*
|
/*
|
||||||
* Unlink fids cannot be reclaimed. Check
|
* Unlink fids cannot be reclaimed. Check
|
||||||
* for them and skip them. Also skip fids
|
* for them and skip them. Also skip fids
|
||||||
|
@ -514,72 +518,85 @@ void coroutine_fn v9fs_reclaim_fd(V9fsPDU *pdu)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is used when a path is removed from the directory tree. Any
|
||||||
|
* fids that still reference it must not be closed from then on, since
|
||||||
|
* they cannot be reopened.
|
||||||
|
*/
|
||||||
static int coroutine_fn v9fs_mark_fids_unreclaim(V9fsPDU *pdu, V9fsPath *path)
|
static int coroutine_fn v9fs_mark_fids_unreclaim(V9fsPDU *pdu, V9fsPath *path)
|
||||||
{
|
{
|
||||||
int err;
|
int err = 0;
|
||||||
V9fsState *s = pdu->s;
|
V9fsState *s = pdu->s;
|
||||||
V9fsFidState *fidp, *fidp_next;
|
V9fsFidState *fidp;
|
||||||
|
gpointer fid;
|
||||||
|
GHashTableIter iter;
|
||||||
|
/*
|
||||||
|
* The most common case is probably that we have exactly one
|
||||||
|
* fid for the given path, so preallocate exactly one.
|
||||||
|
*/
|
||||||
|
g_autoptr(GArray) to_reopen = g_array_sized_new(FALSE, FALSE,
|
||||||
|
sizeof(V9fsFidState *), 1);
|
||||||
|
gint i;
|
||||||
|
|
||||||
fidp = QSIMPLEQ_FIRST(&s->fid_list);
|
g_hash_table_iter_init(&iter, s->fids);
|
||||||
if (!fidp) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* v9fs_reopen_fid() can yield : a reference on the fid must be held
|
* We iterate over the fid table looking for the entries we need
|
||||||
* to ensure its pointer remains valid and we can safely pass it to
|
* to reopen, and store them in to_reopen. This is because
|
||||||
* QSIMPLEQ_NEXT(). The corresponding put_fid() can also yield so
|
* v9fs_reopen_fid() and put_fid() yield. This allows the fid table
|
||||||
* we must keep a reference on the next fid as well. So the logic here
|
* to be modified in the meantime, invalidating our iterator.
|
||||||
* is to get a reference on a fid and only put it back during the next
|
|
||||||
* iteration after we could get a reference on the next fid. Start with
|
|
||||||
* the first one.
|
|
||||||
*/
|
*/
|
||||||
for (fidp->ref++; fidp; fidp = fidp_next) {
|
while (g_hash_table_iter_next(&iter, &fid, (gpointer *) &fidp)) {
|
||||||
if (fidp->path.size == path->size &&
|
if (fidp->path.size == path->size &&
|
||||||
!memcmp(fidp->path.data, path->data, path->size)) {
|
!memcmp(fidp->path.data, path->data, path->size)) {
|
||||||
/* Mark the fid non reclaimable. */
|
/*
|
||||||
|
* Ensure the fid survives a potential clunk request during
|
||||||
|
* v9fs_reopen_fid or put_fid.
|
||||||
|
*/
|
||||||
|
fidp->ref++;
|
||||||
fidp->flags |= FID_NON_RECLAIMABLE;
|
fidp->flags |= FID_NON_RECLAIMABLE;
|
||||||
|
g_array_append_val(to_reopen, fidp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < to_reopen->len; i++) {
|
||||||
|
fidp = g_array_index(to_reopen, V9fsFidState*, i);
|
||||||
/* reopen the file/dir if already closed */
|
/* reopen the file/dir if already closed */
|
||||||
err = v9fs_reopen_fid(pdu, fidp);
|
err = v9fs_reopen_fid(pdu, fidp);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
put_fid(pdu, fidp);
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < to_reopen->len; i++) {
|
||||||
|
put_fid(pdu, g_array_index(to_reopen, V9fsFidState*, i));
|
||||||
|
}
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fidp_next = QSIMPLEQ_NEXT(fidp, next);
|
|
||||||
|
|
||||||
if (fidp_next) {
|
|
||||||
/*
|
|
||||||
* Ensure the next fid survives a potential clunk request during
|
|
||||||
* put_fid() below and v9fs_reopen_fid() in the next iteration.
|
|
||||||
*/
|
|
||||||
fidp_next->ref++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We're done with this fid */
|
|
||||||
put_fid(pdu, fidp);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void coroutine_fn virtfs_reset(V9fsPDU *pdu)
|
static void coroutine_fn virtfs_reset(V9fsPDU *pdu)
|
||||||
{
|
{
|
||||||
V9fsState *s = pdu->s;
|
V9fsState *s = pdu->s;
|
||||||
V9fsFidState *fidp;
|
V9fsFidState *fidp;
|
||||||
|
GList *freeing;
|
||||||
|
/*
|
||||||
|
* Get a list of all the values (fid states) in the table, which
|
||||||
|
* we then...
|
||||||
|
*/
|
||||||
|
g_autoptr(GList) fids = g_hash_table_get_values(s->fids);
|
||||||
|
|
||||||
/* Free all fids */
|
/* ... remove from the table, taking over ownership. */
|
||||||
while (!QSIMPLEQ_EMPTY(&s->fid_list)) {
|
g_hash_table_steal_all(s->fids);
|
||||||
/* Get fid */
|
|
||||||
fidp = QSIMPLEQ_FIRST(&s->fid_list);
|
/*
|
||||||
|
* This allows us to release our references to them asynchronously without
|
||||||
|
* iterating over the hash table and risking iterator invalidation
|
||||||
|
* through concurrent modifications.
|
||||||
|
*/
|
||||||
|
for (freeing = fids; freeing; freeing = freeing->next) {
|
||||||
|
fidp = freeing->data;
|
||||||
fidp->ref++;
|
fidp->ref++;
|
||||||
|
|
||||||
/* Clunk fid */
|
|
||||||
QSIMPLEQ_REMOVE(&s->fid_list, fidp, V9fsFidState, next);
|
|
||||||
fidp->clunked = true;
|
fidp->clunked = true;
|
||||||
|
|
||||||
put_fid(pdu, fidp);
|
put_fid(pdu, fidp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3205,6 +3222,8 @@ static int coroutine_fn v9fs_complete_rename(V9fsPDU *pdu, V9fsFidState *fidp,
|
||||||
V9fsFidState *tfidp;
|
V9fsFidState *tfidp;
|
||||||
V9fsState *s = pdu->s;
|
V9fsState *s = pdu->s;
|
||||||
V9fsFidState *dirfidp = NULL;
|
V9fsFidState *dirfidp = NULL;
|
||||||
|
GHashTableIter iter;
|
||||||
|
gpointer fid;
|
||||||
|
|
||||||
v9fs_path_init(&new_path);
|
v9fs_path_init(&new_path);
|
||||||
if (newdirfid != -1) {
|
if (newdirfid != -1) {
|
||||||
|
@ -3238,11 +3257,13 @@ static int coroutine_fn v9fs_complete_rename(V9fsPDU *pdu, V9fsFidState *fidp,
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Fixup fid's pointing to the old name to
|
* Fixup fid's pointing to the old name to
|
||||||
* start pointing to the new name
|
* start pointing to the new name
|
||||||
*/
|
*/
|
||||||
QSIMPLEQ_FOREACH(tfidp, &s->fid_list, next) {
|
g_hash_table_iter_init(&iter, s->fids);
|
||||||
|
while (g_hash_table_iter_next(&iter, &fid, (gpointer *) &tfidp)) {
|
||||||
if (v9fs_path_is_ancestor(&fidp->path, &tfidp->path)) {
|
if (v9fs_path_is_ancestor(&fidp->path, &tfidp->path)) {
|
||||||
/* replace the name */
|
/* replace the name */
|
||||||
v9fs_fix_path(&tfidp->path, &new_path, strlen(fidp->path.data));
|
v9fs_fix_path(&tfidp->path, &new_path, strlen(fidp->path.data));
|
||||||
|
@ -3320,6 +3341,8 @@ static int coroutine_fn v9fs_fix_fid_paths(V9fsPDU *pdu, V9fsPath *olddir,
|
||||||
V9fsPath oldpath, newpath;
|
V9fsPath oldpath, newpath;
|
||||||
V9fsState *s = pdu->s;
|
V9fsState *s = pdu->s;
|
||||||
int err;
|
int err;
|
||||||
|
GHashTableIter iter;
|
||||||
|
gpointer fid;
|
||||||
|
|
||||||
v9fs_path_init(&oldpath);
|
v9fs_path_init(&oldpath);
|
||||||
v9fs_path_init(&newpath);
|
v9fs_path_init(&newpath);
|
||||||
|
@ -3336,7 +3359,8 @@ static int coroutine_fn v9fs_fix_fid_paths(V9fsPDU *pdu, V9fsPath *olddir,
|
||||||
* Fixup fid's pointing to the old name to
|
* Fixup fid's pointing to the old name to
|
||||||
* start pointing to the new name
|
* start pointing to the new name
|
||||||
*/
|
*/
|
||||||
QSIMPLEQ_FOREACH(tfidp, &s->fid_list, next) {
|
g_hash_table_iter_init(&iter, s->fids);
|
||||||
|
while (g_hash_table_iter_next(&iter, &fid, (gpointer *) &tfidp)) {
|
||||||
if (v9fs_path_is_ancestor(&oldpath, &tfidp->path)) {
|
if (v9fs_path_is_ancestor(&oldpath, &tfidp->path)) {
|
||||||
/* replace the name */
|
/* replace the name */
|
||||||
v9fs_fix_path(&tfidp->path, &newpath, strlen(oldpath.data));
|
v9fs_fix_path(&tfidp->path, &newpath, strlen(oldpath.data));
|
||||||
|
@ -4226,7 +4250,7 @@ int v9fs_device_realize_common(V9fsState *s, const V9fsTransport *t,
|
||||||
s->ctx.fmode = fse->fmode;
|
s->ctx.fmode = fse->fmode;
|
||||||
s->ctx.dmode = fse->dmode;
|
s->ctx.dmode = fse->dmode;
|
||||||
|
|
||||||
QSIMPLEQ_INIT(&s->fid_list);
|
s->fids = g_hash_table_new(NULL, NULL);
|
||||||
qemu_co_rwlock_init(&s->rename_lock);
|
qemu_co_rwlock_init(&s->rename_lock);
|
||||||
|
|
||||||
if (s->ops->init(&s->ctx, errp) < 0) {
|
if (s->ops->init(&s->ctx, errp) < 0) {
|
||||||
|
@ -4286,6 +4310,10 @@ void v9fs_device_unrealize_common(V9fsState *s)
|
||||||
if (s->ctx.fst) {
|
if (s->ctx.fst) {
|
||||||
fsdev_throttle_cleanup(s->ctx.fst);
|
fsdev_throttle_cleanup(s->ctx.fst);
|
||||||
}
|
}
|
||||||
|
if (s->fids) {
|
||||||
|
g_hash_table_destroy(s->fids);
|
||||||
|
s->fids = NULL;
|
||||||
|
}
|
||||||
g_free(s->tag);
|
g_free(s->tag);
|
||||||
qp_table_destroy(&s->qpd_table);
|
qp_table_destroy(&s->qpd_table);
|
||||||
qp_table_destroy(&s->qpp_table);
|
qp_table_destroy(&s->qpp_table);
|
||||||
|
|
|
@ -339,7 +339,7 @@ typedef struct {
|
||||||
struct V9fsState {
|
struct V9fsState {
|
||||||
QLIST_HEAD(, V9fsPDU) free_list;
|
QLIST_HEAD(, V9fsPDU) free_list;
|
||||||
QLIST_HEAD(, V9fsPDU) active_list;
|
QLIST_HEAD(, V9fsPDU) active_list;
|
||||||
QSIMPLEQ_HEAD(, V9fsFidState) fid_list;
|
GHashTable *fids;
|
||||||
FileOperations *ops;
|
FileOperations *ops;
|
||||||
FsContext ctx;
|
FsContext ctx;
|
||||||
char *tag;
|
char *tag;
|
||||||
|
|
|
@ -34,6 +34,7 @@ libqos_srcs = files(
|
||||||
'tpci200.c',
|
'tpci200.c',
|
||||||
'virtio.c',
|
'virtio.c',
|
||||||
'virtio-9p.c',
|
'virtio-9p.c',
|
||||||
|
'virtio-9p-client.c',
|
||||||
'virtio-balloon.c',
|
'virtio-balloon.c',
|
||||||
'virtio-blk.c',
|
'virtio-blk.c',
|
||||||
'vhost-user-blk.c',
|
'vhost-user-blk.c',
|
||||||
|
|
1049
tests/qtest/libqos/virtio-9p-client.c
Normal file
1049
tests/qtest/libqos/virtio-9p-client.c
Normal file
File diff suppressed because it is too large
Load diff
494
tests/qtest/libqos/virtio-9p-client.h
Normal file
494
tests/qtest/libqos/virtio-9p-client.h
Normal file
|
@ -0,0 +1,494 @@
|
||||||
|
/*
|
||||||
|
* 9P network client for VirtIO 9P test cases (based on QTest)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2014 SUSE LINUX Products GmbH
|
||||||
|
*
|
||||||
|
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||||
|
* See the COPYING file in the top-level directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Not so fast! You might want to read the 9p developer docs first:
|
||||||
|
* https://wiki.qemu.org/Documentation/9p
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TESTS_LIBQOS_VIRTIO_9P_CLIENT_H
|
||||||
|
#define TESTS_LIBQOS_VIRTIO_9P_CLIENT_H
|
||||||
|
|
||||||
|
#include "hw/9pfs/9p.h"
|
||||||
|
#include "hw/9pfs/9p-synth.h"
|
||||||
|
#include "virtio-9p.h"
|
||||||
|
#include "qgraph.h"
|
||||||
|
#include "tests/qtest/libqtest-single.h"
|
||||||
|
|
||||||
|
#define P9_MAX_SIZE 4096 /* Max size of a T-message or R-message */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
QTestState *qts;
|
||||||
|
QVirtio9P *v9p;
|
||||||
|
uint16_t tag;
|
||||||
|
uint64_t t_msg;
|
||||||
|
uint32_t t_size;
|
||||||
|
uint64_t r_msg;
|
||||||
|
/* No r_size, it is hardcoded to P9_MAX_SIZE */
|
||||||
|
size_t t_off;
|
||||||
|
size_t r_off;
|
||||||
|
uint32_t free_head;
|
||||||
|
} P9Req;
|
||||||
|
|
||||||
|
/* type[1] version[4] path[8] */
|
||||||
|
typedef char v9fs_qid[13];
|
||||||
|
|
||||||
|
typedef struct v9fs_attr {
|
||||||
|
uint64_t valid;
|
||||||
|
v9fs_qid qid;
|
||||||
|
uint32_t mode;
|
||||||
|
uint32_t uid;
|
||||||
|
uint32_t gid;
|
||||||
|
uint64_t nlink;
|
||||||
|
uint64_t rdev;
|
||||||
|
uint64_t size;
|
||||||
|
uint64_t blksize;
|
||||||
|
uint64_t blocks;
|
||||||
|
uint64_t atime_sec;
|
||||||
|
uint64_t atime_nsec;
|
||||||
|
uint64_t mtime_sec;
|
||||||
|
uint64_t mtime_nsec;
|
||||||
|
uint64_t ctime_sec;
|
||||||
|
uint64_t ctime_nsec;
|
||||||
|
uint64_t btime_sec;
|
||||||
|
uint64_t btime_nsec;
|
||||||
|
uint64_t gen;
|
||||||
|
uint64_t data_version;
|
||||||
|
} v9fs_attr;
|
||||||
|
|
||||||
|
#define P9_GETATTR_BASIC 0x000007ffULL /* Mask for fields up to BLOCKS */
|
||||||
|
#define P9_GETATTR_ALL 0x00003fffULL /* Mask for ALL fields */
|
||||||
|
|
||||||
|
struct V9fsDirent {
|
||||||
|
v9fs_qid qid;
|
||||||
|
uint64_t offset;
|
||||||
|
uint8_t type;
|
||||||
|
char *name;
|
||||||
|
struct V9fsDirent *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* options for 'Twalk' 9p request */
|
||||||
|
typedef struct TWalkOpt {
|
||||||
|
/* 9P client being used (mandatory) */
|
||||||
|
QVirtio9P *client;
|
||||||
|
/* user supplied tag number being returned with response (optional) */
|
||||||
|
uint16_t tag;
|
||||||
|
/* file ID of directory from where walk should start (optional) */
|
||||||
|
uint32_t fid;
|
||||||
|
/* file ID for target directory being walked to (optional) */
|
||||||
|
uint32_t newfid;
|
||||||
|
/* low level variant of path to walk to (optional) */
|
||||||
|
uint16_t nwname;
|
||||||
|
char **wnames;
|
||||||
|
/* high level variant of path to walk to (optional) */
|
||||||
|
const char *path;
|
||||||
|
/* data being received from 9p server as 'Rwalk' response (optional) */
|
||||||
|
struct {
|
||||||
|
uint16_t *nwqid;
|
||||||
|
v9fs_qid **wqid;
|
||||||
|
} rwalk;
|
||||||
|
/* only send Twalk request but not wait for a reply? (optional) */
|
||||||
|
bool requestOnly;
|
||||||
|
/* do we expect an Rlerror response, if yes which error code? (optional) */
|
||||||
|
uint32_t expectErr;
|
||||||
|
} TWalkOpt;
|
||||||
|
|
||||||
|
/* result of 'Twalk' 9p request */
|
||||||
|
typedef struct TWalkRes {
|
||||||
|
/* file ID of target directory been walked to */
|
||||||
|
uint32_t newfid;
|
||||||
|
/* if requestOnly was set: request object for further processing */
|
||||||
|
P9Req *req;
|
||||||
|
} TWalkRes;
|
||||||
|
|
||||||
|
/* options for 'Tversion' 9p request */
|
||||||
|
typedef struct TVersionOpt {
|
||||||
|
/* 9P client being used (mandatory) */
|
||||||
|
QVirtio9P *client;
|
||||||
|
/* user supplied tag number being returned with response (optional) */
|
||||||
|
uint16_t tag;
|
||||||
|
/* maximum message size that can be handled by client (optional) */
|
||||||
|
uint32_t msize;
|
||||||
|
/* protocol version (optional) */
|
||||||
|
const char *version;
|
||||||
|
/* only send Tversion request but not wait for a reply? (optional) */
|
||||||
|
bool requestOnly;
|
||||||
|
/* do we expect an Rlerror response, if yes which error code? (optional) */
|
||||||
|
uint32_t expectErr;
|
||||||
|
} TVersionOpt;
|
||||||
|
|
||||||
|
/* result of 'Tversion' 9p request */
|
||||||
|
typedef struct TVersionRes {
|
||||||
|
/* if requestOnly was set: request object for further processing */
|
||||||
|
P9Req *req;
|
||||||
|
} TVersionRes;
|
||||||
|
|
||||||
|
/* options for 'Tattach' 9p request */
|
||||||
|
typedef struct TAttachOpt {
|
||||||
|
/* 9P client being used (mandatory) */
|
||||||
|
QVirtio9P *client;
|
||||||
|
/* user supplied tag number being returned with response (optional) */
|
||||||
|
uint16_t tag;
|
||||||
|
/* file ID to be associated with root of file tree (optional) */
|
||||||
|
uint32_t fid;
|
||||||
|
/* numerical uid of user being introduced to server (optional) */
|
||||||
|
uint32_t n_uname;
|
||||||
|
/* data being received from 9p server as 'Rattach' response (optional) */
|
||||||
|
struct {
|
||||||
|
/* server's idea of the root of the file tree */
|
||||||
|
v9fs_qid *qid;
|
||||||
|
} rattach;
|
||||||
|
/* only send Tattach request but not wait for a reply? (optional) */
|
||||||
|
bool requestOnly;
|
||||||
|
/* do we expect an Rlerror response, if yes which error code? (optional) */
|
||||||
|
uint32_t expectErr;
|
||||||
|
} TAttachOpt;
|
||||||
|
|
||||||
|
/* result of 'Tattach' 9p request */
|
||||||
|
typedef struct TAttachRes {
|
||||||
|
/* if requestOnly was set: request object for further processing */
|
||||||
|
P9Req *req;
|
||||||
|
} TAttachRes;
|
||||||
|
|
||||||
|
/* options for 'Tgetattr' 9p request */
|
||||||
|
typedef struct TGetAttrOpt {
|
||||||
|
/* 9P client being used (mandatory) */
|
||||||
|
QVirtio9P *client;
|
||||||
|
/* user supplied tag number being returned with response (optional) */
|
||||||
|
uint16_t tag;
|
||||||
|
/* file ID of file/dir whose attributes shall be retrieved (required) */
|
||||||
|
uint32_t fid;
|
||||||
|
/* bitmask indicating attribute fields to be retrieved (optional) */
|
||||||
|
uint64_t request_mask;
|
||||||
|
/* data being received from 9p server as 'Rgetattr' response (optional) */
|
||||||
|
struct {
|
||||||
|
v9fs_attr *attr;
|
||||||
|
} rgetattr;
|
||||||
|
/* only send Tgetattr request but not wait for a reply? (optional) */
|
||||||
|
bool requestOnly;
|
||||||
|
/* do we expect an Rlerror response, if yes which error code? (optional) */
|
||||||
|
uint32_t expectErr;
|
||||||
|
} TGetAttrOpt;
|
||||||
|
|
||||||
|
/* result of 'Tgetattr' 9p request */
|
||||||
|
typedef struct TGetAttrRes {
|
||||||
|
/* if requestOnly was set: request object for further processing */
|
||||||
|
P9Req *req;
|
||||||
|
} TGetAttrRes;
|
||||||
|
|
||||||
|
/* options for 'Treaddir' 9p request */
|
||||||
|
typedef struct TReadDirOpt {
|
||||||
|
/* 9P client being used (mandatory) */
|
||||||
|
QVirtio9P *client;
|
||||||
|
/* user supplied tag number being returned with response (optional) */
|
||||||
|
uint16_t tag;
|
||||||
|
/* file ID of directory whose entries shall be retrieved (required) */
|
||||||
|
uint32_t fid;
|
||||||
|
/* offset in entries stream, i.e. for multiple requests (optional) */
|
||||||
|
uint64_t offset;
|
||||||
|
/* maximum bytes to be returned by server (required) */
|
||||||
|
uint32_t count;
|
||||||
|
/* data being received from 9p server as 'Rreaddir' response (optional) */
|
||||||
|
struct {
|
||||||
|
uint32_t *count;
|
||||||
|
uint32_t *nentries;
|
||||||
|
struct V9fsDirent **entries;
|
||||||
|
} rreaddir;
|
||||||
|
/* only send Treaddir request but not wait for a reply? (optional) */
|
||||||
|
bool requestOnly;
|
||||||
|
/* do we expect an Rlerror response, if yes which error code? (optional) */
|
||||||
|
uint32_t expectErr;
|
||||||
|
} TReadDirOpt;
|
||||||
|
|
||||||
|
/* result of 'Treaddir' 9p request */
|
||||||
|
typedef struct TReadDirRes {
|
||||||
|
/* if requestOnly was set: request object for further processing */
|
||||||
|
P9Req *req;
|
||||||
|
} TReadDirRes;
|
||||||
|
|
||||||
|
/* options for 'Tlopen' 9p request */
|
||||||
|
typedef struct TLOpenOpt {
|
||||||
|
/* 9P client being used (mandatory) */
|
||||||
|
QVirtio9P *client;
|
||||||
|
/* user supplied tag number being returned with response (optional) */
|
||||||
|
uint16_t tag;
|
||||||
|
/* file ID of file / directory to be opened (required) */
|
||||||
|
uint32_t fid;
|
||||||
|
/* Linux open(2) flags such as O_RDONLY, O_RDWR, O_WRONLY (optional) */
|
||||||
|
uint32_t flags;
|
||||||
|
/* data being received from 9p server as 'Rlopen' response (optional) */
|
||||||
|
struct {
|
||||||
|
v9fs_qid *qid;
|
||||||
|
uint32_t *iounit;
|
||||||
|
} rlopen;
|
||||||
|
/* only send Tlopen request but not wait for a reply? (optional) */
|
||||||
|
bool requestOnly;
|
||||||
|
/* do we expect an Rlerror response, if yes which error code? (optional) */
|
||||||
|
uint32_t expectErr;
|
||||||
|
} TLOpenOpt;
|
||||||
|
|
||||||
|
/* result of 'Tlopen' 9p request */
|
||||||
|
typedef struct TLOpenRes {
|
||||||
|
/* if requestOnly was set: request object for further processing */
|
||||||
|
P9Req *req;
|
||||||
|
} TLOpenRes;
|
||||||
|
|
||||||
|
/* options for 'Twrite' 9p request */
|
||||||
|
typedef struct TWriteOpt {
|
||||||
|
/* 9P client being used (mandatory) */
|
||||||
|
QVirtio9P *client;
|
||||||
|
/* user supplied tag number being returned with response (optional) */
|
||||||
|
uint16_t tag;
|
||||||
|
/* file ID of file to write to (required) */
|
||||||
|
uint32_t fid;
|
||||||
|
/* start position of write from beginning of file (optional) */
|
||||||
|
uint64_t offset;
|
||||||
|
/* how many bytes to write */
|
||||||
|
uint32_t count;
|
||||||
|
/* data to be written */
|
||||||
|
const void *data;
|
||||||
|
/* only send Twrite request but not wait for a reply? (optional) */
|
||||||
|
bool requestOnly;
|
||||||
|
/* do we expect an Rlerror response, if yes which error code? (optional) */
|
||||||
|
uint32_t expectErr;
|
||||||
|
} TWriteOpt;
|
||||||
|
|
||||||
|
/* result of 'Twrite' 9p request */
|
||||||
|
typedef struct TWriteRes {
|
||||||
|
/* if requestOnly was set: request object for further processing */
|
||||||
|
P9Req *req;
|
||||||
|
/* amount of bytes written */
|
||||||
|
uint32_t count;
|
||||||
|
} TWriteRes;
|
||||||
|
|
||||||
|
/* options for 'Tflush' 9p request */
|
||||||
|
typedef struct TFlushOpt {
|
||||||
|
/* 9P client being used (mandatory) */
|
||||||
|
QVirtio9P *client;
|
||||||
|
/* user supplied tag number being returned with response (optional) */
|
||||||
|
uint16_t tag;
|
||||||
|
/* message to flush (required) */
|
||||||
|
uint16_t oldtag;
|
||||||
|
/* only send Tflush request but not wait for a reply? (optional) */
|
||||||
|
bool requestOnly;
|
||||||
|
/* do we expect an Rlerror response, if yes which error code? (optional) */
|
||||||
|
uint32_t expectErr;
|
||||||
|
} TFlushOpt;
|
||||||
|
|
||||||
|
/* result of 'Tflush' 9p request */
|
||||||
|
typedef struct TFlushRes {
|
||||||
|
/* if requestOnly was set: request object for further processing */
|
||||||
|
P9Req *req;
|
||||||
|
} TFlushRes;
|
||||||
|
|
||||||
|
/* options for 'Tmkdir' 9p request */
|
||||||
|
typedef struct TMkdirOpt {
|
||||||
|
/* 9P client being used (mandatory) */
|
||||||
|
QVirtio9P *client;
|
||||||
|
/* user supplied tag number being returned with response (optional) */
|
||||||
|
uint16_t tag;
|
||||||
|
/* low level variant of directory where new one shall be created */
|
||||||
|
uint32_t dfid;
|
||||||
|
/* high-level variant of directory where new one shall be created */
|
||||||
|
const char *atPath;
|
||||||
|
/* New directory's name (required) */
|
||||||
|
const char *name;
|
||||||
|
/* Linux mkdir(2) mode bits (optional) */
|
||||||
|
uint32_t mode;
|
||||||
|
/* effective group ID of caller */
|
||||||
|
uint32_t gid;
|
||||||
|
/* data being received from 9p server as 'Rmkdir' response (optional) */
|
||||||
|
struct {
|
||||||
|
/* QID of newly created directory */
|
||||||
|
v9fs_qid *qid;
|
||||||
|
} rmkdir;
|
||||||
|
/* only send Tmkdir request but not wait for a reply? (optional) */
|
||||||
|
bool requestOnly;
|
||||||
|
/* do we expect an Rlerror response, if yes which error code? (optional) */
|
||||||
|
uint32_t expectErr;
|
||||||
|
} TMkdirOpt;
|
||||||
|
|
||||||
|
/* result of 'TMkdir' 9p request */
|
||||||
|
typedef struct TMkdirRes {
|
||||||
|
/* if requestOnly was set: request object for further processing */
|
||||||
|
P9Req *req;
|
||||||
|
} TMkdirRes;
|
||||||
|
|
||||||
|
/* options for 'Tlcreate' 9p request */
|
||||||
|
typedef struct TlcreateOpt {
|
||||||
|
/* 9P client being used (mandatory) */
|
||||||
|
QVirtio9P *client;
|
||||||
|
/* user supplied tag number being returned with response (optional) */
|
||||||
|
uint16_t tag;
|
||||||
|
/* low-level variant of directory where new file shall be created */
|
||||||
|
uint32_t fid;
|
||||||
|
/* high-level variant of directory where new file shall be created */
|
||||||
|
const char *atPath;
|
||||||
|
/* name of new file (required) */
|
||||||
|
const char *name;
|
||||||
|
/* Linux kernel intent bits */
|
||||||
|
uint32_t flags;
|
||||||
|
/* Linux create(2) mode bits */
|
||||||
|
uint32_t mode;
|
||||||
|
/* effective group ID of caller */
|
||||||
|
uint32_t gid;
|
||||||
|
/* data being received from 9p server as 'Rlcreate' response (optional) */
|
||||||
|
struct {
|
||||||
|
v9fs_qid *qid;
|
||||||
|
uint32_t *iounit;
|
||||||
|
} rlcreate;
|
||||||
|
/* only send Tlcreate request but not wait for a reply? (optional) */
|
||||||
|
bool requestOnly;
|
||||||
|
/* do we expect an Rlerror response, if yes which error code? (optional) */
|
||||||
|
uint32_t expectErr;
|
||||||
|
} TlcreateOpt;
|
||||||
|
|
||||||
|
/* result of 'Tlcreate' 9p request */
|
||||||
|
typedef struct TlcreateRes {
|
||||||
|
/* if requestOnly was set: request object for further processing */
|
||||||
|
P9Req *req;
|
||||||
|
} TlcreateRes;
|
||||||
|
|
||||||
|
/* options for 'Tsymlink' 9p request */
|
||||||
|
typedef struct TsymlinkOpt {
|
||||||
|
/* 9P client being used (mandatory) */
|
||||||
|
QVirtio9P *client;
|
||||||
|
/* user supplied tag number being returned with response (optional) */
|
||||||
|
uint16_t tag;
|
||||||
|
/* low-level variant of directory where symlink shall be created */
|
||||||
|
uint32_t fid;
|
||||||
|
/* high-level variant of directory where symlink shall be created */
|
||||||
|
const char *atPath;
|
||||||
|
/* name of symlink (required) */
|
||||||
|
const char *name;
|
||||||
|
/* where symlink will point to (required) */
|
||||||
|
const char *symtgt;
|
||||||
|
/* effective group ID of caller */
|
||||||
|
uint32_t gid;
|
||||||
|
/* data being received from 9p server as 'Rsymlink' response (optional) */
|
||||||
|
struct {
|
||||||
|
v9fs_qid *qid;
|
||||||
|
} rsymlink;
|
||||||
|
/* only send Tsymlink request but not wait for a reply? (optional) */
|
||||||
|
bool requestOnly;
|
||||||
|
/* do we expect an Rlerror response, if yes which error code? (optional) */
|
||||||
|
uint32_t expectErr;
|
||||||
|
} TsymlinkOpt;
|
||||||
|
|
||||||
|
/* result of 'Tsymlink' 9p request */
|
||||||
|
typedef struct TsymlinkRes {
|
||||||
|
/* if requestOnly was set: request object for further processing */
|
||||||
|
P9Req *req;
|
||||||
|
} TsymlinkRes;
|
||||||
|
|
||||||
|
/* options for 'Tlink' 9p request */
|
||||||
|
typedef struct TlinkOpt {
|
||||||
|
/* 9P client being used (mandatory) */
|
||||||
|
QVirtio9P *client;
|
||||||
|
/* user supplied tag number being returned with response (optional) */
|
||||||
|
uint16_t tag;
|
||||||
|
/* low-level variant of directory where hard link shall be created */
|
||||||
|
uint32_t dfid;
|
||||||
|
/* high-level variant of directory where hard link shall be created */
|
||||||
|
const char *atPath;
|
||||||
|
/* low-level variant of target referenced by new hard link */
|
||||||
|
uint32_t fid;
|
||||||
|
/* high-level variant of target referenced by new hard link */
|
||||||
|
const char *toPath;
|
||||||
|
/* name of hard link (required) */
|
||||||
|
const char *name;
|
||||||
|
/* only send Tlink request but not wait for a reply? (optional) */
|
||||||
|
bool requestOnly;
|
||||||
|
/* do we expect an Rlerror response, if yes which error code? (optional) */
|
||||||
|
uint32_t expectErr;
|
||||||
|
} TlinkOpt;
|
||||||
|
|
||||||
|
/* result of 'Tlink' 9p request */
|
||||||
|
typedef struct TlinkRes {
|
||||||
|
/* if requestOnly was set: request object for further processing */
|
||||||
|
P9Req *req;
|
||||||
|
} TlinkRes;
|
||||||
|
|
||||||
|
/* options for 'Tunlinkat' 9p request */
|
||||||
|
typedef struct TunlinkatOpt {
|
||||||
|
/* 9P client being used (mandatory) */
|
||||||
|
QVirtio9P *client;
|
||||||
|
/* user supplied tag number being returned with response (optional) */
|
||||||
|
uint16_t tag;
|
||||||
|
/* low-level variant of directory where name shall be unlinked */
|
||||||
|
uint32_t dirfd;
|
||||||
|
/* high-level variant of directory where name shall be unlinked */
|
||||||
|
const char *atPath;
|
||||||
|
/* name of directory entry to be unlinked (required) */
|
||||||
|
const char *name;
|
||||||
|
/* Linux unlinkat(2) flags */
|
||||||
|
uint32_t flags;
|
||||||
|
/* only send Tunlinkat request but not wait for a reply? (optional) */
|
||||||
|
bool requestOnly;
|
||||||
|
/* do we expect an Rlerror response, if yes which error code? (optional) */
|
||||||
|
uint32_t expectErr;
|
||||||
|
} TunlinkatOpt;
|
||||||
|
|
||||||
|
/* result of 'Tunlinkat' 9p request */
|
||||||
|
typedef struct TunlinkatRes {
|
||||||
|
/* if requestOnly was set: request object for further processing */
|
||||||
|
P9Req *req;
|
||||||
|
} TunlinkatRes;
|
||||||
|
|
||||||
|
void v9fs_set_allocator(QGuestAllocator *t_alloc);
|
||||||
|
void v9fs_memwrite(P9Req *req, const void *addr, size_t len);
|
||||||
|
void v9fs_memskip(P9Req *req, size_t len);
|
||||||
|
void v9fs_memread(P9Req *req, void *addr, size_t len);
|
||||||
|
void v9fs_uint8_read(P9Req *req, uint8_t *val);
|
||||||
|
void v9fs_uint16_write(P9Req *req, uint16_t val);
|
||||||
|
void v9fs_uint16_read(P9Req *req, uint16_t *val);
|
||||||
|
void v9fs_uint32_write(P9Req *req, uint32_t val);
|
||||||
|
void v9fs_uint64_write(P9Req *req, uint64_t val);
|
||||||
|
void v9fs_uint32_read(P9Req *req, uint32_t *val);
|
||||||
|
void v9fs_uint64_read(P9Req *req, uint64_t *val);
|
||||||
|
uint16_t v9fs_string_size(const char *string);
|
||||||
|
void v9fs_string_write(P9Req *req, const char *string);
|
||||||
|
void v9fs_string_read(P9Req *req, uint16_t *len, char **string);
|
||||||
|
P9Req *v9fs_req_init(QVirtio9P *v9p, uint32_t size, uint8_t id,
|
||||||
|
uint16_t tag);
|
||||||
|
void v9fs_req_send(P9Req *req);
|
||||||
|
void v9fs_req_wait_for_reply(P9Req *req, uint32_t *len);
|
||||||
|
void v9fs_req_recv(P9Req *req, uint8_t id);
|
||||||
|
void v9fs_req_free(P9Req *req);
|
||||||
|
void v9fs_rlerror(P9Req *req, uint32_t *err);
|
||||||
|
TVersionRes v9fs_tversion(TVersionOpt);
|
||||||
|
void v9fs_rversion(P9Req *req, uint16_t *len, char **version);
|
||||||
|
TAttachRes v9fs_tattach(TAttachOpt);
|
||||||
|
void v9fs_rattach(P9Req *req, v9fs_qid *qid);
|
||||||
|
TWalkRes v9fs_twalk(TWalkOpt opt);
|
||||||
|
void v9fs_rwalk(P9Req *req, uint16_t *nwqid, v9fs_qid **wqid);
|
||||||
|
TGetAttrRes v9fs_tgetattr(TGetAttrOpt);
|
||||||
|
void v9fs_rgetattr(P9Req *req, v9fs_attr *attr);
|
||||||
|
TReadDirRes v9fs_treaddir(TReadDirOpt);
|
||||||
|
void v9fs_rreaddir(P9Req *req, uint32_t *count, uint32_t *nentries,
|
||||||
|
struct V9fsDirent **entries);
|
||||||
|
void v9fs_free_dirents(struct V9fsDirent *e);
|
||||||
|
TLOpenRes v9fs_tlopen(TLOpenOpt);
|
||||||
|
void v9fs_rlopen(P9Req *req, v9fs_qid *qid, uint32_t *iounit);
|
||||||
|
TWriteRes v9fs_twrite(TWriteOpt);
|
||||||
|
void v9fs_rwrite(P9Req *req, uint32_t *count);
|
||||||
|
TFlushRes v9fs_tflush(TFlushOpt);
|
||||||
|
void v9fs_rflush(P9Req *req);
|
||||||
|
TMkdirRes v9fs_tmkdir(TMkdirOpt);
|
||||||
|
void v9fs_rmkdir(P9Req *req, v9fs_qid *qid);
|
||||||
|
TlcreateRes v9fs_tlcreate(TlcreateOpt);
|
||||||
|
void v9fs_rlcreate(P9Req *req, v9fs_qid *qid, uint32_t *iounit);
|
||||||
|
TsymlinkRes v9fs_tsymlink(TsymlinkOpt);
|
||||||
|
void v9fs_rsymlink(P9Req *req, v9fs_qid *qid);
|
||||||
|
TlinkRes v9fs_tlink(TlinkOpt);
|
||||||
|
void v9fs_rlink(P9Req *req);
|
||||||
|
TunlinkatRes v9fs_tunlinkat(TunlinkatOpt);
|
||||||
|
void v9fs_runlinkat(P9Req *req);
|
||||||
|
|
||||||
|
#endif
|
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue