diff mbox

[06/33] libceph: fixup error handling in osdmap_decode()

Message ID 1395944299-21970-7-git-send-email-ilya.dryomov@inktank.com (mailing list archive)
State New, archived
Headers show

Commit Message

Ilya Dryomov March 27, 2014, 6:17 p.m. UTC
The existing error handling scheme requires resetting err to -EINVAL
prior to calling any ceph_decode_* macro.  This is ugly and fragile,
and there already are a few places where we would return 0 on error,
due to a missing reset.  Fix this by adding a special e_inval label to
be used by all ceph_decode_* macros.

Signed-off-by: Ilya Dryomov <ilya.dryomov@inktank.com>
---
 net/ceph/osdmap.c |   53 +++++++++++++++++++++++++++--------------------------
 1 file changed, 27 insertions(+), 26 deletions(-)

Comments

Alex Elder March 27, 2014, 7:25 p.m. UTC | #1
On 03/27/2014 01:17 PM, Ilya Dryomov wrote:
> The existing error handling scheme requires resetting err to -EINVAL
> prior to calling any ceph_decode_* macro.  This is ugly and fragile,
> and there already are a few places where we would return 0 on error,
> due to a missing reset.  Fix this by adding a special e_inval label to
> be used by all ceph_decode_* macros.

I don't see where it's returning 0 on error, but I think this
is a good change anyway.

I'd use "einval" or "err_inval" instead of "e_inval".  But
no matter.

Looks good.

Reviewed-by: Alex Elder <elder@linaro.org>


> Signed-off-by: Ilya Dryomov <ilya.dryomov@inktank.com>
> ---
>  net/ceph/osdmap.c |   53 +++++++++++++++++++++++++++--------------------------
>  1 file changed, 27 insertions(+), 26 deletions(-)
> 
> diff --git a/net/ceph/osdmap.c b/net/ceph/osdmap.c
> index a82df6ea0749..298d076eee89 100644
> --- a/net/ceph/osdmap.c
> +++ b/net/ceph/osdmap.c
> @@ -688,36 +688,37 @@ static int osdmap_decode(void **p, void *end, struct ceph_osdmap *map)
>  {
>  	u16 version;
>  	u32 len, max, i;
> -	int err = -EINVAL;
>  	u32 epoch = 0;
>  	void *start = *p;
> +	int err;
>  	struct ceph_pg_pool_info *pi;
>  
>  	dout("%s %p to %p len %d\n", __func__, *p, end, (int)(end - *p));
>  
> -	ceph_decode_16_safe(p, end, version, bad);
> +	ceph_decode_16_safe(p, end, version, e_inval);
>  	if (version > 6) {
>  		pr_warning("got unknown v %d > 6 of osdmap\n", version);
> -		goto bad;
> +		goto e_inval;
>  	}
>  	if (version < 6) {
>  		pr_warning("got old v %d < 6 of osdmap\n", version);
> -		goto bad;
> +		goto e_inval;
>  	}
>  
> -	ceph_decode_need(p, end, 2*sizeof(u64)+6*sizeof(u32), bad);
> +	ceph_decode_need(p, end, 2*sizeof(u64)+6*sizeof(u32), e_inval);
>  	ceph_decode_copy(p, &map->fsid, sizeof(map->fsid));
>  	epoch = map->epoch = ceph_decode_32(p);
>  	ceph_decode_copy(p, &map->created, sizeof(map->created));
>  	ceph_decode_copy(p, &map->modified, sizeof(map->modified));
>  
> -	ceph_decode_32_safe(p, end, max, bad);
> +	ceph_decode_32_safe(p, end, max, e_inval);
>  	while (max--) {
> -		ceph_decode_need(p, end, 8 + 2, bad);
> -		err = -ENOMEM;
> +		ceph_decode_need(p, end, 8 + 2, e_inval);
>  		pi = kzalloc(sizeof(*pi), GFP_NOFS);
> -		if (!pi)
> +		if (!pi) {
> +			err = -ENOMEM;
>  			goto bad;
> +		}
>  		pi->id = ceph_decode_64(p);
>  		err = __decode_pool(p, end, pi);
>  		if (err < 0) {
> @@ -728,27 +729,25 @@ static int osdmap_decode(void **p, void *end, struct ceph_osdmap *map)
>  	}
>  
>  	err = __decode_pool_names(p, end, map);
> -	if (err < 0) {
> -		dout("fail to decode pool names");
> +	if (err)
>  		goto bad;
> -	}
>  
> -	ceph_decode_32_safe(p, end, map->pool_max, bad);
> +	ceph_decode_32_safe(p, end, map->pool_max, e_inval);
>  
> -	ceph_decode_32_safe(p, end, map->flags, bad);
> +	ceph_decode_32_safe(p, end, map->flags, e_inval);
>  
>  	max = ceph_decode_32(p);
>  
>  	/* (re)alloc osd arrays */
>  	err = osdmap_set_max_osd(map, max);
> -	if (err < 0)
> +	if (err)
>  		goto bad;
>  
>  	/* osds */
> -	err = -EINVAL;
>  	ceph_decode_need(p, end, 3*sizeof(u32) +
>  			 map->max_osd*(1 + sizeof(*map->osd_weight) +
> -				       sizeof(*map->osd_addr)), bad);
> +				       sizeof(*map->osd_addr)), e_inval);
> +
>  	*p += 4; /* skip length field (should match max) */
>  	ceph_decode_copy(p, map->osd_state, map->max_osd);
>  
> @@ -762,7 +761,7 @@ static int osdmap_decode(void **p, void *end, struct ceph_osdmap *map)
>  		ceph_decode_addr(&map->osd_addr[i]);
>  
>  	/* pg_temp */
> -	ceph_decode_32_safe(p, end, len, bad);
> +	ceph_decode_32_safe(p, end, len, e_inval);
>  	for (i = 0; i < len; i++) {
>  		int n, j;
>  		struct ceph_pg pgid;
> @@ -771,16 +770,16 @@ static int osdmap_decode(void **p, void *end, struct ceph_osdmap *map)
>  		err = ceph_decode_pgid(p, end, &pgid);
>  		if (err)
>  			goto bad;
> -		ceph_decode_need(p, end, sizeof(u32), bad);
> +		ceph_decode_need(p, end, sizeof(u32), e_inval);
>  		n = ceph_decode_32(p);
> -		err = -EINVAL;
>  		if (n > (UINT_MAX - sizeof(*pg)) / sizeof(u32))
> -			goto bad;
> -		ceph_decode_need(p, end, n * sizeof(u32), bad);
> -		err = -ENOMEM;
> +			goto e_inval;
> +		ceph_decode_need(p, end, n * sizeof(u32), e_inval);
>  		pg = kmalloc(sizeof(*pg) + n*sizeof(u32), GFP_NOFS);
> -		if (!pg)
> +		if (!pg) {
> +			err = -ENOMEM;
>  			goto bad;
> +		}
>  		pg->pgid = pgid;
>  		pg->len = n;
>  		for (j = 0; j < n; j++)
> @@ -794,10 +793,10 @@ static int osdmap_decode(void **p, void *end, struct ceph_osdmap *map)
>  	}
>  
>  	/* crush */
> -	ceph_decode_32_safe(p, end, len, bad);
> +	ceph_decode_32_safe(p, end, len, e_inval);
>  	dout("osdmap_decode crush len %d from off 0x%x\n", len,
>  	     (int)(*p - start));
> -	ceph_decode_need(p, end, len, bad);
> +	ceph_decode_need(p, end, len, e_inval);
>  	map->crush = crush_decode(*p, end);
>  	*p += len;
>  	if (IS_ERR(map->crush)) {
> @@ -812,6 +811,8 @@ static int osdmap_decode(void **p, void *end, struct ceph_osdmap *map)
>  	dout("full osdmap epoch %d max_osd %d\n", map->epoch, map->max_osd);
>  	return 0;
>  
> +e_inval:
> +	err = -EINVAL;
>  bad:
>  	pr_err("corrupt full osdmap (%d) epoch %d off %d (%p of %p-%p)\n",
>  	       err, epoch, (int)(*p - start), *p, start, end);
> 

--
To unsubscribe from this list: send the line "unsubscribe ceph-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Ilya Dryomov March 28, 2014, 2:56 p.m. UTC | #2
On Thu, Mar 27, 2014 at 9:25 PM, Alex Elder <elder@ieee.org> wrote:
> On 03/27/2014 01:17 PM, Ilya Dryomov wrote:
>> The existing error handling scheme requires resetting err to -EINVAL
>> prior to calling any ceph_decode_* macro.  This is ugly and fragile,
>> and there already are a few places where we would return 0 on error,
>> due to a missing reset.  Fix this by adding a special e_inval label to
>> be used by all ceph_decode_* macros.
>
> I don't see where it's returning 0 on error, but I think this
> is a good change anyway.

Here:

        err = __decode_pool_names(p, end, map); <--
        if (err < 0) {
                dout("fail to decode pool names");
                goto bad;
        }

        ceph_decode_32_safe(p, end, map->pool_max, bad); <--

        ceph_decode_32_safe(p, end, map->flags, bad); <--

Or here (if at least one pg_temp mapping is present):

                err = __insert_pg_mapping(pg, &map->pg_temp); <--
                if (err)
                        goto bad;
                dout(" added pg_temp %lld.%x len %d\n", pgid.pool, pgid.seed,
                     len);
        }

        /* crush */
        ceph_decode_32_safe(p, end, len, bad); <--
        dout("osdmap_decode crush len %d from off 0x%x\n", len,
             (int)(*p - start));
        ceph_decode_need(p, end, len, bad); <--

And a lot more in osdmap_apply_incremental().  There are three ways out:

(1) a separate variable for helper retvals;
(2) resetting err to -EINVAL prior to each ceph_decode_* (if it's
    not already -EINVAL, of course);
(3) a separate e_inval label.

(3) is the only reasonable way to do this.  (1) leads to things like

    ret = foo_helper();
    if (ret) {
            err = ret;
            ...
    }

and (2) is error-prone and hardly maintainable.

>
> I'd use "einval" or "err_inval" instead of "e_inval".  But
> no matter.

We already use "e_inval" in osd_client.c (OK, that was me), so I'll
keep it for consistency.  I could rename them all to "Einval" to make
them stand out though (I see some "Efoo" labels in fs/).

Thanks,

                Ilya
--
To unsubscribe from this list: send the line "unsubscribe ceph-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Alex Elder March 28, 2014, 4:22 p.m. UTC | #3
On 03/28/2014 09:56 AM, Ilya Dryomov wrote:
> On Thu, Mar 27, 2014 at 9:25 PM, Alex Elder <elder@ieee.org> wrote:
>> On 03/27/2014 01:17 PM, Ilya Dryomov wrote:
>>> The existing error handling scheme requires resetting err to -EINVAL
>>> prior to calling any ceph_decode_* macro.  This is ugly and fragile,
>>> and there already are a few places where we would return 0 on error,
>>> due to a missing reset.  Fix this by adding a special e_inval label to
>>> be used by all ceph_decode_* macros.
>>
>> I don't see where it's returning 0 on error, but I think this
>> is a good change anyway.
> 
> Here:
> 
>         err = __decode_pool_names(p, end, map); <--
>         if (err < 0) {
>                 dout("fail to decode pool names");
>                 goto bad;
>         }
> 
>         ceph_decode_32_safe(p, end, map->pool_max, bad); <--
> 
>         ceph_decode_32_safe(p, end, map->flags, bad); <--

Fragile indeed.

I don't particularly like the encoding of an assumed
label in a macro the way these *_safe() macros do either
but they do the job and they're all over the place.
The biggest reason is that it assumes something about
context, but this is another one, it makes things less
obvious.  Oh well.

> Or here (if at least one pg_temp mapping is present):
> 
>                 err = __insert_pg_mapping(pg, &map->pg_temp); <--
>                 if (err)
>                         goto bad;
>                 dout(" added pg_temp %lld.%x len %d\n", pgid.pool, pgid.seed,
>                      len);
>         }
> 
>         /* crush */
>         ceph_decode_32_safe(p, end, len, bad); <--
>         dout("osdmap_decode crush len %d from off 0x%x\n", len,
>              (int)(*p - start));
>         ceph_decode_need(p, end, len, bad); <--
> 
> And a lot more in osdmap_apply_incremental().  There are three ways out:
> 
> (1) a separate variable for helper retvals;
> (2) resetting err to -EINVAL prior to each ceph_decode_* (if it's
>     not already -EINVAL, of course);
> (3) a separate e_inval label.
> 
> (3) is the only reasonable way to do this.  (1) leads to things like
> 
>     ret = foo_helper();
>     if (ret) {
>             err = ret;
>             ...
>     }
> 
> and (2) is error-prone and hardly maintainable.

I agree, (3) is the right fix.

>> I'd use "einval" or "err_inval" instead of "e_inval".  But
>> no matter.
> 
> We already use "e_inval" in osd_client.c (OK, that was me), so I'll
> keep it for consistency.  I could rename them all to "Einval" to make
> them stand out though (I see some "Efoo" labels in fs/).

Not a big deal.  Beauty is in the eye of the beholder.

					-Alex
> Thanks,
> 
>                 Ilya
> 

--
To unsubscribe from this list: send the line "unsubscribe ceph-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/net/ceph/osdmap.c b/net/ceph/osdmap.c
index a82df6ea0749..298d076eee89 100644
--- a/net/ceph/osdmap.c
+++ b/net/ceph/osdmap.c
@@ -688,36 +688,37 @@  static int osdmap_decode(void **p, void *end, struct ceph_osdmap *map)
 {
 	u16 version;
 	u32 len, max, i;
-	int err = -EINVAL;
 	u32 epoch = 0;
 	void *start = *p;
+	int err;
 	struct ceph_pg_pool_info *pi;
 
 	dout("%s %p to %p len %d\n", __func__, *p, end, (int)(end - *p));
 
-	ceph_decode_16_safe(p, end, version, bad);
+	ceph_decode_16_safe(p, end, version, e_inval);
 	if (version > 6) {
 		pr_warning("got unknown v %d > 6 of osdmap\n", version);
-		goto bad;
+		goto e_inval;
 	}
 	if (version < 6) {
 		pr_warning("got old v %d < 6 of osdmap\n", version);
-		goto bad;
+		goto e_inval;
 	}
 
-	ceph_decode_need(p, end, 2*sizeof(u64)+6*sizeof(u32), bad);
+	ceph_decode_need(p, end, 2*sizeof(u64)+6*sizeof(u32), e_inval);
 	ceph_decode_copy(p, &map->fsid, sizeof(map->fsid));
 	epoch = map->epoch = ceph_decode_32(p);
 	ceph_decode_copy(p, &map->created, sizeof(map->created));
 	ceph_decode_copy(p, &map->modified, sizeof(map->modified));
 
-	ceph_decode_32_safe(p, end, max, bad);
+	ceph_decode_32_safe(p, end, max, e_inval);
 	while (max--) {
-		ceph_decode_need(p, end, 8 + 2, bad);
-		err = -ENOMEM;
+		ceph_decode_need(p, end, 8 + 2, e_inval);
 		pi = kzalloc(sizeof(*pi), GFP_NOFS);
-		if (!pi)
+		if (!pi) {
+			err = -ENOMEM;
 			goto bad;
+		}
 		pi->id = ceph_decode_64(p);
 		err = __decode_pool(p, end, pi);
 		if (err < 0) {
@@ -728,27 +729,25 @@  static int osdmap_decode(void **p, void *end, struct ceph_osdmap *map)
 	}
 
 	err = __decode_pool_names(p, end, map);
-	if (err < 0) {
-		dout("fail to decode pool names");
+	if (err)
 		goto bad;
-	}
 
-	ceph_decode_32_safe(p, end, map->pool_max, bad);
+	ceph_decode_32_safe(p, end, map->pool_max, e_inval);
 
-	ceph_decode_32_safe(p, end, map->flags, bad);
+	ceph_decode_32_safe(p, end, map->flags, e_inval);
 
 	max = ceph_decode_32(p);
 
 	/* (re)alloc osd arrays */
 	err = osdmap_set_max_osd(map, max);
-	if (err < 0)
+	if (err)
 		goto bad;
 
 	/* osds */
-	err = -EINVAL;
 	ceph_decode_need(p, end, 3*sizeof(u32) +
 			 map->max_osd*(1 + sizeof(*map->osd_weight) +
-				       sizeof(*map->osd_addr)), bad);
+				       sizeof(*map->osd_addr)), e_inval);
+
 	*p += 4; /* skip length field (should match max) */
 	ceph_decode_copy(p, map->osd_state, map->max_osd);
 
@@ -762,7 +761,7 @@  static int osdmap_decode(void **p, void *end, struct ceph_osdmap *map)
 		ceph_decode_addr(&map->osd_addr[i]);
 
 	/* pg_temp */
-	ceph_decode_32_safe(p, end, len, bad);
+	ceph_decode_32_safe(p, end, len, e_inval);
 	for (i = 0; i < len; i++) {
 		int n, j;
 		struct ceph_pg pgid;
@@ -771,16 +770,16 @@  static int osdmap_decode(void **p, void *end, struct ceph_osdmap *map)
 		err = ceph_decode_pgid(p, end, &pgid);
 		if (err)
 			goto bad;
-		ceph_decode_need(p, end, sizeof(u32), bad);
+		ceph_decode_need(p, end, sizeof(u32), e_inval);
 		n = ceph_decode_32(p);
-		err = -EINVAL;
 		if (n > (UINT_MAX - sizeof(*pg)) / sizeof(u32))
-			goto bad;
-		ceph_decode_need(p, end, n * sizeof(u32), bad);
-		err = -ENOMEM;
+			goto e_inval;
+		ceph_decode_need(p, end, n * sizeof(u32), e_inval);
 		pg = kmalloc(sizeof(*pg) + n*sizeof(u32), GFP_NOFS);
-		if (!pg)
+		if (!pg) {
+			err = -ENOMEM;
 			goto bad;
+		}
 		pg->pgid = pgid;
 		pg->len = n;
 		for (j = 0; j < n; j++)
@@ -794,10 +793,10 @@  static int osdmap_decode(void **p, void *end, struct ceph_osdmap *map)
 	}
 
 	/* crush */
-	ceph_decode_32_safe(p, end, len, bad);
+	ceph_decode_32_safe(p, end, len, e_inval);
 	dout("osdmap_decode crush len %d from off 0x%x\n", len,
 	     (int)(*p - start));
-	ceph_decode_need(p, end, len, bad);
+	ceph_decode_need(p, end, len, e_inval);
 	map->crush = crush_decode(*p, end);
 	*p += len;
 	if (IS_ERR(map->crush)) {
@@ -812,6 +811,8 @@  static int osdmap_decode(void **p, void *end, struct ceph_osdmap *map)
 	dout("full osdmap epoch %d max_osd %d\n", map->epoch, map->max_osd);
 	return 0;
 
+e_inval:
+	err = -EINVAL;
 bad:
 	pr_err("corrupt full osdmap (%d) epoch %d off %d (%p of %p-%p)\n",
 	       err, epoch, (int)(*p - start), *p, start, end);