diff --git a/hw/9pfs/9p-proxy.c b/hw/9pfs/9p-proxy.c index 6f598a0f11..4aa4e0a3ba 100644 --- a/hw/9pfs/9p-proxy.c +++ b/hw/9pfs/9p-proxy.c @@ -537,7 +537,8 @@ static int v9fs_request(V9fsProxy *proxy, int type, void *response, ...) } /* marshal the header details */ - proxy_marshal(iovec, 0, "dd", header.type, header.size); + retval = proxy_marshal(iovec, 0, "dd", header.type, header.size); + assert(retval == 4 * 2); header.size += PROXY_HDR_SZ; retval = qemu_write_full(proxy->sockfd, iovec->iov_base, header.size); diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c index 6026b51a1c..5a6e2c9d3d 100644 --- a/hw/9pfs/9p.c +++ b/hw/9pfs/9p.c @@ -260,7 +260,7 @@ static V9fsFidState *coroutine_fn get_fid(V9fsPDU *pdu, int32_t fid) V9fsFidState *f; V9fsState *s = pdu->s; - for (f = s->fid_list; f; f = f->next) { + QSIMPLEQ_FOREACH(f, &s->fid_list, next) { BUG_ON(f->clunked); if (f->fid == fid) { /* @@ -295,7 +295,7 @@ static V9fsFidState *alloc_fid(V9fsState *s, int32_t fid) { V9fsFidState *f; - for (f = s->fid_list; f; f = f->next) { + QSIMPLEQ_FOREACH(f, &s->fid_list, next) { /* If fid is already there return NULL */ BUG_ON(f->clunked); if (f->fid == fid) { @@ -311,8 +311,7 @@ static V9fsFidState *alloc_fid(V9fsState *s, int32_t fid) * reclaim won't close the file descriptor */ f->flags |= FID_REFERENCED; - f->next = s->fid_list; - s->fid_list = f; + QSIMPLEQ_INSERT_TAIL(&s->fid_list, f, next); v9fs_readdir_init(s->proto_version, &f->fs.dir); v9fs_readdir_init(s->proto_version, &f->fs_reclaim.dir); @@ -401,29 +400,27 @@ static int coroutine_fn put_fid(V9fsPDU *pdu, V9fsFidState *fidp) static V9fsFidState *clunk_fid(V9fsState *s, int32_t fid) { - V9fsFidState **fidpp, *fidp; + V9fsFidState *fidp; - for (fidpp = &s->fid_list; *fidpp; fidpp = &(*fidpp)->next) { - if ((*fidpp)->fid == fid) { - break; + QSIMPLEQ_FOREACH(fidp, &s->fid_list, next) { + if (fidp->fid == fid) { + QSIMPLEQ_REMOVE(&s->fid_list, fidp, V9fsFidState, next); + fidp->clunked = true; + return fidp; } } - if (*fidpp == NULL) { - return NULL; - } - fidp = *fidpp; - *fidpp = fidp->next; - fidp->clunked = 1; - return fidp; + return NULL; } void coroutine_fn v9fs_reclaim_fd(V9fsPDU *pdu) { int reclaim_count = 0; V9fsState *s = pdu->s; - V9fsFidState *f, *reclaim_list = NULL; + V9fsFidState *f; + QSLIST_HEAD(, V9fsFidState) reclaim_list = + QSLIST_HEAD_INITIALIZER(reclaim_list); - for (f = s->fid_list; f; f = f->next) { + QSIMPLEQ_FOREACH(f, &s->fid_list, next) { /* * Unlink fids cannot be reclaimed. Check * for them and skip them. Also skip fids @@ -453,8 +450,7 @@ void coroutine_fn v9fs_reclaim_fd(V9fsPDU *pdu) * a clunk request won't free this fid */ f->ref++; - f->rclm_lst = reclaim_list; - reclaim_list = f; + QSLIST_INSERT_HEAD(&reclaim_list, f, reclaim_next); f->fs_reclaim.fd = f->fs.fd; f->fs.fd = -1; reclaim_count++; @@ -466,8 +462,7 @@ void coroutine_fn v9fs_reclaim_fd(V9fsPDU *pdu) * a clunk request won't free this fid */ f->ref++; - f->rclm_lst = reclaim_list; - reclaim_list = f; + QSLIST_INSERT_HEAD(&reclaim_list, f, reclaim_next); f->fs_reclaim.dir.stream = f->fs.dir.stream; f->fs.dir.stream = NULL; reclaim_count++; @@ -481,15 +476,14 @@ void coroutine_fn v9fs_reclaim_fd(V9fsPDU *pdu) * Now close the fid in reclaim list. Free them if they * are already clunked. */ - while (reclaim_list) { - f = reclaim_list; - reclaim_list = f->rclm_lst; + while (!QSLIST_EMPTY(&reclaim_list)) { + f = QSLIST_FIRST(&reclaim_list); + QSLIST_REMOVE(&reclaim_list, f, V9fsFidState, reclaim_next); if (f->fid_type == P9_FID_FILE) { v9fs_co_close(pdu, &f->fs_reclaim); } else if (f->fid_type == P9_FID_DIR) { v9fs_co_closedir(pdu, &f->fs_reclaim); } - f->rclm_lst = NULL; /* * Now drop the fid reference, free it * if clunked. @@ -502,32 +496,50 @@ static int coroutine_fn v9fs_mark_fids_unreclaim(V9fsPDU *pdu, V9fsPath *path) { int err; V9fsState *s = pdu->s; - V9fsFidState *fidp; + V9fsFidState *fidp, *fidp_next; -again: - for (fidp = s->fid_list; fidp; fidp = fidp->next) { - if (fidp->path.size != path->size) { - continue; - } - if (!memcmp(fidp->path.data, path->data, path->size)) { + fidp = QSIMPLEQ_FIRST(&s->fid_list); + if (!fidp) { + return 0; + } + + /* + * v9fs_reopen_fid() can yield : a reference on the fid must be held + * to ensure its pointer remains valid and we can safely pass it to + * QSIMPLEQ_NEXT(). The corresponding put_fid() can also yield so + * we must keep a reference on the next fid as well. So the logic here + * 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) { + if (fidp->path.size == path->size && + !memcmp(fidp->path.data, path->data, path->size)) { /* Mark the fid non reclaimable. */ fidp->flags |= FID_NON_RECLAIMABLE; /* reopen the file/dir if already closed */ err = v9fs_reopen_fid(pdu, fidp); if (err < 0) { + put_fid(pdu, fidp); return err; } - /* - * Go back to head of fid list because - * the list could have got updated when - * switched to the worker thread - */ - if (err == 0) { - goto again; - } } + + 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; } @@ -537,14 +549,14 @@ static void coroutine_fn virtfs_reset(V9fsPDU *pdu) V9fsFidState *fidp; /* Free all fids */ - while (s->fid_list) { + while (!QSIMPLEQ_EMPTY(&s->fid_list)) { /* Get fid */ - fidp = s->fid_list; + fidp = QSIMPLEQ_FIRST(&s->fid_list); fidp->ref++; /* Clunk fid */ - s->fid_list = fidp->next; - fidp->clunked = 1; + QSIMPLEQ_REMOVE(&s->fid_list, fidp, V9fsFidState, next); + fidp->clunked = true; put_fid(pdu, fidp); } @@ -3121,7 +3133,7 @@ static int coroutine_fn v9fs_complete_rename(V9fsPDU *pdu, V9fsFidState *fidp, * Fixup fid's pointing to the old name to * start pointing to the new name */ - for (tfidp = s->fid_list; tfidp; tfidp = tfidp->next) { + QSIMPLEQ_FOREACH(tfidp, &s->fid_list, next) { if (v9fs_path_is_ancestor(&fidp->path, &tfidp->path)) { /* replace the name */ v9fs_fix_path(&tfidp->path, &new_path, strlen(fidp->path.data)); @@ -3215,7 +3227,7 @@ static int coroutine_fn v9fs_fix_fid_paths(V9fsPDU *pdu, V9fsPath *olddir, * Fixup fid's pointing to the old name to * start pointing to the new name */ - for (tfidp = s->fid_list; tfidp; tfidp = tfidp->next) { + QSIMPLEQ_FOREACH(tfidp, &s->fid_list, next) { if (v9fs_path_is_ancestor(&oldpath, &tfidp->path)) { /* replace the name */ v9fs_fix_path(&tfidp->path, &newpath, strlen(oldpath.data)); @@ -4081,7 +4093,7 @@ int v9fs_device_realize_common(V9fsState *s, const V9fsTransport *t, s->ctx.fmode = fse->fmode; s->ctx.dmode = fse->dmode; - s->fid_list = NULL; + QSIMPLEQ_INIT(&s->fid_list); qemu_co_rwlock_init(&s->rename_lock); if (s->ops->init(&s->ctx, errp) < 0) { diff --git a/hw/9pfs/9p.h b/hw/9pfs/9p.h index 32df81f360..00381591ff 100644 --- a/hw/9pfs/9p.h +++ b/hw/9pfs/9p.h @@ -279,9 +279,9 @@ struct V9fsFidState { int open_flags; uid_t uid; int ref; - int clunked; - V9fsFidState *next; - V9fsFidState *rclm_lst; + bool clunked; + QSIMPLEQ_ENTRY(V9fsFidState) next; + QSLIST_ENTRY(V9fsFidState) reclaim_next; }; typedef enum AffixType_t { @@ -339,7 +339,7 @@ typedef struct { struct V9fsState { QLIST_HEAD(, V9fsPDU) free_list; QLIST_HEAD(, V9fsPDU) active_list; - V9fsFidState *fid_list; + QSIMPLEQ_HEAD(, V9fsFidState) fid_list; FileOperations *ops; FsContext ctx; char *tag;