From: Greg Kurz <groug@kaod.org>
To: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Cc: "fam@euphon.net" <fam@euphon.net>,
"peter.maydell@linaro.org" <peter.maydell@linaro.org>,
"mst@redhat.com" <mst@redhat.com>,
"codyprime@gmail.com" <codyprime@gmail.com>,
"mark.cave-ayland@ilande.co.uk" <mark.cave-ayland@ilande.co.uk>,
"qemu-devel@nongnu.org" <qemu-devel@nongnu.org>,
"mdroth@linux.vnet.ibm.com" <mdroth@linux.vnet.ibm.com>,
"kraxel@redhat.com" <kraxel@redhat.com>,
"mreitz@redhat.com" <mreitz@redhat.com>,
"qemu-block@nongnu.org" <qemu-block@nongnu.org>,
"quintela@redhat.com" <quintela@redhat.com>,
"david@redhat.com" <david@redhat.com>,
"armbru@redhat.com" <armbru@redhat.com>,
"pasic@linux.ibm.com" <pasic@linux.ibm.com>,
"borntraeger@de.ibm.com" <borntraeger@de.ibm.com>,
"marcandre.lureau@redhat.com" <marcandre.lureau@redhat.com>,
"rth@twiddle.net" <rth@twiddle.net>,
"farman@linux.ibm.com" <farman@linux.ibm.com>,
"dgilbert@redhat.com" <dgilbert@redhat.com>,
"alex.williamson@redhat.com" <alex.williamson@redhat.com>,
"qemu-arm@nongnu.org" <qemu-arm@nongnu.org>,
"stefanha@redhat.com" <stefanha@redhat.com>,
"jsnow@redhat.com" <jsnow@redhat.com>,
"david@gibson.dropbear.id.au" <david@gibson.dropbear.id.au>,
"kwolf@redhat.com" <kwolf@redhat.com>,
"berrange@redhat.com" <berrange@redhat.com>,
"cohuck@redhat.com" <cohuck@redhat.com>,
"qemu-s390x@nongnu.org" <qemu-s390x@nongnu.org>,
"sundeep.lkml@gmail.com" <sundeep.lkml@gmail.com>,
"qemu-ppc@nongnu.org" <qemu-ppc@nongnu.org>,
"pbonzini@redhat.com" <pbonzini@redhat.com>
Subject: Re: [Qemu-devel] [RFC] error: auto propagated local_err
Date: Thu, 19 Sep 2019 12:08:34 +0200 [thread overview]
Message-ID: <20190919120834.0ef0470b@bahia.lan> (raw)
In-Reply-To: <4234506a-171e-bff4-3edb-8c50ed9ec722@virtuozzo.com>
On Thu, 19 Sep 2019 09:28:11 +0000
Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> wrote:
> 19.09.2019 11:59, Greg Kurz wrote:
> > On Wed, 18 Sep 2019 16:02:44 +0300
> > Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> wrote:
> >
> >> Hi all!
> >>
> >> Here is a proposal (three of them, actually) of auto propagation for
> >> local_err, to not call error_propagate on every exit point, when we
> >> deal with local_err.
> >>
> >> It also may help make Greg's series[1] about error_append_hint smaller.
> >>
> >
> > This will depend on whether we reach a consensus soon enough (soft
> > freeze for 4.2 is 2019-10-29). Otherwise, I think my series should
> > be merged as is, and auto-propagation to be delayed to 4.3.
> >
> >> See definitions and examples below.
> >>
> >> I'm cc-ing to this RFC everyone from series[1] CC list, as if we like
> >> it, the idea will touch same code (and may be more).
> >>
> >
> > When we have a good auto-propagation mechanism available, I guess
> > this can be beneficial for most of the code, not only the places
> > where we add hints (or prepend something, see below).
> >
> >> [1]: https://lists.gnu.org/archive/html/qemu-devel/2019-09/msg03449.html
> >>
> >> Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
> >> ---
> >> include/qapi/error.h | 102 +++++++++++++++++++++++++++++++++++++++++++
> >> block.c | 63 ++++++++++++--------------
> >> block/backup.c | 8 +++-
> >> block/gluster.c | 7 +++
> >> 4 files changed, 144 insertions(+), 36 deletions(-)
> >>
> >> diff --git a/include/qapi/error.h b/include/qapi/error.h
> >> index 3f95141a01..083e061014 100644
> >> --- a/include/qapi/error.h
> >> +++ b/include/qapi/error.h
> >> @@ -322,6 +322,108 @@ void error_set_internal(Error **errp,
> >> ErrorClass err_class, const char *fmt, ...)
> >> GCC_FMT_ATTR(6, 7);
> >>
> >> +typedef struct ErrorPropagator {
> >> + Error **errp;
> >> + Error *local_err;
> >> +} ErrorPropagator;
> >> +
> >> +static inline void error_propagator_cleanup(ErrorPropagator *prop)
> >> +{
> >> + if (prop->local_err) {
> >> + error_propagate(prop->errp, prop->local_err);
> >
> > We also have error_propagate_prepend(), which is basically a variant of
> > error_prepend()+error_propagate() that can cope with &error_fatal. This
> > was introduced by Markus in commit 4b5766488fd3, for similar reasons that
> > motivated my series. It has ~30 users in the tree.
> >
> > There's no such thing a generic cleanup function with a printf-like
> > interface, so all of these should be converted back to error_prepend()
> > if we go for auto-propagation.
> >
> > Aside from propagation, one can sometime choose to call things like
> > error_free() or error_free_or_abort()... Auto-propagation should
> > detect that and not call error_propagate() in this case.
>
> Hmm, for example, qmp_eject, which error_free or error_propagate..
> We can leave such cases as is, not many of them. Or introduce
> safe_errp_free(Error **errp), which will zero pointer after freeing.
>
Maybe even turning error_free() to take an Error ** ? It looks
safe to zero out a dangling pointer. Of course the API change
would need to be propagated to all error_* functions that
explicitly call error_free().
> >
> >> + }
> >> +}
> >> +
> >> +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(ErrorPropagator, error_propagator_cleanup);
> >> +
> >> +/*
> >> + * ErrorPropagationPair
> >> + *
> >> + * [Error *local_err, Error **errp]
> >> + *
> >> + * First element is local_err, second is original errp, which is propagation
> >> + * target. Yes, errp has a bit another type, so it should be converted.
> >> + *
> >> + * ErrorPropagationPair may be used as errp, which points to local_err,
> >> + * as it's type is compatible.
> >> + */
> >> +typedef Error *ErrorPropagationPair[2];
> >> +
> >> +static inline void error_propagation_pair_cleanup(ErrorPropagationPair *arr)
> >> +{
> >> + Error *local_err = (*arr)[0];
> >> + Error **errp = (Error **)(*arr)[1];
> >> +
> >> + if (local_err) {
> >> + error_propagate(errp, local_err);
> >> + }
> >> +}
> >> +
> >> +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(ErrorPropagationPair,
> >> + error_propagation_pair_cleanup);
> >> +
> >> +/*
> >> + * DEF_AUTO_ERRP
> >> + *
> >> + * Define auto_errp variable, which may be used instead of errp, and
> >> + * *auto_errp may be safely checked to be zero or not, and may be safely
> >> + * used for error_append_hint(). auto_errp is automatically propagated
> >> + * to errp at function exit.
> >> + */
> >> +#define DEF_AUTO_ERRP(auto_errp, errp) \
> >> + g_auto(ErrorPropagationPair) (auto_errp) = {NULL, (Error *)(errp)}
> >> +
> >> +
> >> +/*
> >> + * Another variant:
> >> + * Pros:
> >> + * - normal structure instead of cheating with array
> >> + * - we can directly use errp, if it's not NULL and don't point to
> >> + * error_abort or error_fatal
> >> + * Cons:
> >> + * - we need to define two variables instead of one
> >> + */
> >> +typedef struct ErrorPropagationStruct {
> >> + Error *local_err;
> >> + Error **errp;
> >> +} ErrorPropagationStruct;
> >> +
> >> +static inline void error_propagation_struct_cleanup(ErrorPropagationStruct *prop)
> >> +{
> >> + if (prop->local_err) {
> >> + error_propagate(prop->errp, prop->local_err);
> >> + }
> >> +}
> >> +
> >> +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(ErrorPropagationStruct,
> >> + error_propagation_struct_cleanup);
> >> +
> >> +#define DEF_AUTO_ERRP_V2(auto_errp, errp) \
> >> + g_auto(ErrorPropagationStruct) (__auto_errp_prop) = {.errp = (errp)}; \
> >> + Error **auto_errp = \
> >> + ((errp) == NULL || *(errp) == error_abort || *(errp) == error_fatal) ? \
> >> + &__auto_errp_prop.local_err : \
> >> + (errp);
> >> +
> >> +/*
> >> + * Third variant:
> >> + * Pros:
> >> + * - simpler movement for functions which don't have local_err yet
> >> + * the only thing to do is to call one macro at function start.
> >> + * This extremely simplifies Greg's series
> >> + * Cons:
> >> + * - looks like errp shadowing.. Still seems safe.
> >> + * - must be after all definitions of local variables and before any
> >> + * code.
> >> + * - like v2, several statements in one open macro
> >> + */
> >> +#define MAKE_ERRP_SAFE(errp) \
> >> +g_auto(ErrorPropagationStruct) (__auto_errp_prop) = {.errp = (errp)}; \
> >> +if ((errp) == NULL || *(errp) == error_abort || *(errp) == error_fatal) { \
> >> + (errp) = &__auto_errp_prop.local_err; \
> >> +}
> >> +
> >> +
> >> /*
> >> * Special error destination to abort on error.
> >> * See error_setg() and error_propagate() for details.
> >> diff --git a/block.c b/block.c
> >> index 5944124845..5253663329 100644
> >> --- a/block.c
> >> +++ b/block.c
> >> @@ -1275,12 +1275,11 @@ static int bdrv_open_driver(BlockDriverState *bs, BlockDriver *drv,
> >> const char *node_name, QDict *options,
> >> int open_flags, Error **errp)
> >> {
> >> - Error *local_err = NULL;
> >> + DEF_AUTO_ERRP_V2(auto_errp, errp);
> >> int i, ret;
> >>
> >> - bdrv_assign_node_name(bs, node_name, &local_err);
> >> - if (local_err) {
> >> - error_propagate(errp, local_err);
> >> + bdrv_assign_node_name(bs, node_name, auto_errp);
> >> + if (*auto_errp) {
> >> return -EINVAL;
> >> }
> >>
> >> @@ -1290,20 +1289,21 @@ static int bdrv_open_driver(BlockDriverState *bs, BlockDriver *drv,
> >>
> >> if (drv->bdrv_file_open) {
> >> assert(!drv->bdrv_needs_filename || bs->filename[0]);
> >> - ret = drv->bdrv_file_open(bs, options, open_flags, &local_err);
> >> + ret = drv->bdrv_file_open(bs, options, open_flags, auto_errp);
> >> } else if (drv->bdrv_open) {
> >> - ret = drv->bdrv_open(bs, options, open_flags, &local_err);
> >> + ret = drv->bdrv_open(bs, options, open_flags, auto_errp);
> >> } else {
> >> ret = 0;
> >> }
> >>
> >> if (ret < 0) {
> >> - if (local_err) {
> >> - error_propagate(errp, local_err);
> >> - } else if (bs->filename[0]) {
> >> - error_setg_errno(errp, -ret, "Could not open '%s'", bs->filename);
> >> - } else {
> >> - error_setg_errno(errp, -ret, "Could not open image");
> >> + if (!*auto_errp) {
> >> + if (bs->filename[0]) {
> >> + error_setg_errno(errp, -ret, "Could not open '%s'",
> >> + bs->filename);
> >> + } else {
> >> + error_setg_errno(errp, -ret, "Could not open image");
> >> + }
> >> }
> >> goto open_failed;
> >> }
> >> @@ -1314,9 +1314,8 @@ static int bdrv_open_driver(BlockDriverState *bs, BlockDriver *drv,
> >> return ret;
> >> }
> >>
> >> - bdrv_refresh_limits(bs, &local_err);
> >> - if (local_err) {
> >> - error_propagate(errp, local_err);
> >> + bdrv_refresh_limits(bs, auto_errp);
> >> + if (*auto_errp) {
> >> return -EINVAL;
> >> }
> >>
> >> @@ -4238,17 +4237,17 @@ out:
> >> void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top,
> >> Error **errp)
> >> {
> >> - Error *local_err = NULL;
> >> + g_auto(ErrorPropagator) prop = {.errp = errp};
> >>
> >> - bdrv_set_backing_hd(bs_new, bs_top, &local_err);
> >> - if (local_err) {
> >> - error_propagate(errp, local_err);
> >> + errp = &prop.local_err;
> >> +
> >> + bdrv_set_backing_hd(bs_new, bs_top, errp);
> >> + if (*errp) {
> >> goto out;
> >> }
> >>
> >> - bdrv_replace_node(bs_top, bs_new, &local_err);
> >> - if (local_err) {
> >> - error_propagate(errp, local_err);
> >> + bdrv_replace_node(bs_top, bs_new, errp);
> >> + if (*errp) {
> >> bdrv_set_backing_hd(bs_new, NULL, &error_abort);
> >> goto out;
> >> }
> >> @@ -5309,9 +5308,9 @@ void bdrv_init_with_whitelist(void)
> >> static void coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs,
> >> Error **errp)
> >> {
> >> + DEF_AUTO_ERRP(auto_errp, errp);
> >> BdrvChild *child, *parent;
> >> uint64_t perm, shared_perm;
> >> - Error *local_err = NULL;
> >> int ret;
> >> BdrvDirtyBitmap *bm;
> >>
> >> @@ -5324,9 +5323,8 @@ static void coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs,
> >> }
> >>
> >> QLIST_FOREACH(child, &bs->children, next) {
> >> - bdrv_co_invalidate_cache(child->bs, &local_err);
> >> - if (local_err) {
> >> - error_propagate(errp, local_err);
> >> + bdrv_co_invalidate_cache(child->bs, auto_errp);
> >> + if (*auto_errp) {
> >> return;
> >> }
> >> }
> >> @@ -5346,19 +5344,17 @@ static void coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs,
> >> */
> >> bs->open_flags &= ~BDRV_O_INACTIVE;
> >> bdrv_get_cumulative_perm(bs, &perm, &shared_perm);
> >> - ret = bdrv_check_perm(bs, NULL, perm, shared_perm, NULL, NULL, &local_err);
> >> + ret = bdrv_check_perm(bs, NULL, perm, shared_perm, NULL, NULL, auto_errp);
> >> if (ret < 0) {
> >> bs->open_flags |= BDRV_O_INACTIVE;
> >> - error_propagate(errp, local_err);
> >> return;
> >> }
> >> bdrv_set_perm(bs, perm, shared_perm);
> >>
> >> if (bs->drv->bdrv_co_invalidate_cache) {
> >> - bs->drv->bdrv_co_invalidate_cache(bs, &local_err);
> >> - if (local_err) {
> >> + bs->drv->bdrv_co_invalidate_cache(bs, auto_errp);
> >> + if (*auto_errp) {
> >> bs->open_flags |= BDRV_O_INACTIVE;
> >> - error_propagate(errp, local_err);
> >> return;
> >> }
> >> }
> >> @@ -5378,10 +5374,9 @@ static void coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs,
> >>
> >> QLIST_FOREACH(parent, &bs->parents, next_parent) {
> >> if (parent->role->activate) {
> >> - parent->role->activate(parent, &local_err);
> >> - if (local_err) {
> >> + parent->role->activate(parent, auto_errp);
> >> + if (*auto_errp) {
> >> bs->open_flags |= BDRV_O_INACTIVE;
> >> - error_propagate(errp, local_err);
> >> return;
> >> }
> >> }
> >> diff --git a/block/backup.c b/block/backup.c
> >> index 89f7f89200..462dea4fbb 100644
> >> --- a/block/backup.c
> >> +++ b/block/backup.c
> >> @@ -583,6 +583,10 @@ static const BlockJobDriver backup_job_driver = {
> >> static int64_t backup_calculate_cluster_size(BlockDriverState *target,
> >> Error **errp)
> >> {
> >> + /*
> >> + * Example of using DEF_AUTO_ERRP to make error_append_hint safe
> >> + */
> >> + DEF_AUTO_ERRP(auto_errp, errp);
> >> int ret;
> >> BlockDriverInfo bdi;
> >>
> >> @@ -602,10 +606,10 @@ static int64_t backup_calculate_cluster_size(BlockDriverState *target,
> >> BACKUP_CLUSTER_SIZE_DEFAULT);
> >> return BACKUP_CLUSTER_SIZE_DEFAULT;
> >> } else if (ret < 0 && !target->backing) {
> >> - error_setg_errno(errp, -ret,
> >> + error_setg_errno(auto_errp, -ret,
> >> "Couldn't determine the cluster size of the target image, "
> >> "which has no backing file");
> >> - error_append_hint(errp,
> >> + error_append_hint(auto_errp,
> >> "Aborting, since this may create an unusable destination image\n");
> >> return ret;
> >> } else if (ret < 0 && target->backing) {
> >> diff --git a/block/gluster.c b/block/gluster.c
> >> index 64028b2cba..799a2dbeca 100644
> >> --- a/block/gluster.c
> >> +++ b/block/gluster.c
> >> @@ -695,6 +695,13 @@ static int qemu_gluster_parse(BlockdevOptionsGluster *gconf,
> >> QDict *options, Error **errp)
> >> {
> >> int ret;
> >> + /*
> >> + * Example of using MAKE_ERRP_SAFE to make error_append_hint safe. We
> >> + * only need to add one macro call. Note, it must be placed exactly after
> >> + * all local variables defenition.
> >> + */
> >> + MAKE_ERRP_SAFE(errp);
> >> +
> >> if (filename) {
> >> ret = qemu_gluster_parse_uri(gconf, filename);
> >> if (ret < 0) {
> >
>
>
next prev parent reply other threads:[~2019-09-19 10:11 UTC|newest]
Thread overview: 45+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-09-18 13:02 [Qemu-devel] [RFC] error: auto propagated local_err Vladimir Sementsov-Ogievskiy
2019-09-18 17:10 ` Eric Blake
2019-09-18 17:46 ` Vladimir Sementsov-Ogievskiy
2019-09-18 18:05 ` Eric Blake
2019-09-18 18:32 ` Eric Blake
2019-09-19 6:47 ` Vladimir Sementsov-Ogievskiy
2019-09-19 13:29 ` Eric Blake
2019-09-19 9:17 ` Kevin Wolf
2019-09-19 9:47 ` Vladimir Sementsov-Ogievskiy
2019-09-19 10:09 ` Daniel P. Berrangé
2019-09-19 10:21 ` Vladimir Sementsov-Ogievskiy
2019-09-19 11:55 ` Daniel P. Berrangé
2019-09-19 12:00 ` Vladimir Sementsov-Ogievskiy
2019-09-19 13:03 ` Kevin Wolf
2019-09-19 13:17 ` Vladimir Sementsov-Ogievskiy
2019-09-19 13:44 ` Eric Blake
2019-09-19 13:40 ` Eric Blake
2019-09-19 14:13 ` Vladimir Sementsov-Ogievskiy
2019-09-19 14:26 ` Eric Blake
2019-09-19 14:30 ` Vladimir Sementsov-Ogievskiy
2019-09-19 14:44 ` Eric Blake
2019-09-19 14:49 ` Daniel P. Berrangé
2019-09-19 15:24 ` Eric Blake
2019-09-19 15:37 ` Vladimir Sementsov-Ogievskiy
2019-09-19 15:50 ` Daniel P. Berrangé
2019-09-19 16:16 ` Vladimir Sementsov-Ogievskiy
2019-09-19 16:51 ` Daniel P. Berrangé
2019-09-20 12:58 ` Eric Blake
2019-09-19 15:12 ` Vladimir Sementsov-Ogievskiy
2019-09-19 14:34 ` Kevin Wolf
2019-09-19 1:54 ` [Qemu-devel] " no-reply
2019-09-19 7:32 ` David Hildenbrand
2019-09-19 7:41 ` Vladimir Sementsov-Ogievskiy
2019-09-19 7:53 ` David Hildenbrand
2019-09-19 8:20 ` Vladimir Sementsov-Ogievskiy
2019-09-19 8:23 ` David Hildenbrand
2019-09-19 8:59 ` Greg Kurz
2019-09-19 9:28 ` Vladimir Sementsov-Ogievskiy
2019-09-19 10:08 ` Greg Kurz [this message]
2019-09-19 8:59 ` Max Reitz
2019-09-19 9:14 ` Vladimir Sementsov-Ogievskiy
2019-09-19 9:33 ` Max Reitz
2019-09-19 10:03 ` Vladimir Sementsov-Ogievskiy
2019-09-19 11:52 ` Max Reitz
2019-09-20 11:46 ` Vladimir Sementsov-Ogievskiy
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20190919120834.0ef0470b@bahia.lan \
--to=groug@kaod.org \
--cc=alex.williamson@redhat.com \
--cc=armbru@redhat.com \
--cc=berrange@redhat.com \
--cc=borntraeger@de.ibm.com \
--cc=codyprime@gmail.com \
--cc=cohuck@redhat.com \
--cc=david@gibson.dropbear.id.au \
--cc=david@redhat.com \
--cc=dgilbert@redhat.com \
--cc=fam@euphon.net \
--cc=farman@linux.ibm.com \
--cc=jsnow@redhat.com \
--cc=kraxel@redhat.com \
--cc=kwolf@redhat.com \
--cc=marcandre.lureau@redhat.com \
--cc=mark.cave-ayland@ilande.co.uk \
--cc=mdroth@linux.vnet.ibm.com \
--cc=mreitz@redhat.com \
--cc=mst@redhat.com \
--cc=pasic@linux.ibm.com \
--cc=pbonzini@redhat.com \
--cc=peter.maydell@linaro.org \
--cc=qemu-arm@nongnu.org \
--cc=qemu-block@nongnu.org \
--cc=qemu-devel@nongnu.org \
--cc=qemu-ppc@nongnu.org \
--cc=qemu-s390x@nongnu.org \
--cc=quintela@redhat.com \
--cc=rth@twiddle.net \
--cc=stefanha@redhat.com \
--cc=sundeep.lkml@gmail.com \
--cc=vsementsov@virtuozzo.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).