public inbox for linux-media@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] video_device: don't free_irq() an element past array vpif_obj.dev[] and fix test
@ 2010-02-09 11:59 Roel Kluin
  2010-02-18 16:31 ` Karicheri, Muralidharan
  0 siblings, 1 reply; 7+ messages in thread
From: Roel Kluin @ 2010-02-09 11:59 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, linux-media, Andrew Morton, LKML

In vpif_get_std_info(): std_info doesn't need the NULL test, it was already
dereferenced anyway. If std_info->stdid is 0 we could early return -1.

In vpif_probe(): local variable q was only assigned. If we error out with
either last two goto's then j equals VPIF_DISPLAY_MAX_DEVICES. So after the
probe_out: label, k also reaches VPIF_DISPLAY_MAX_DEVICES after the loop. In
the first iteration in the loop after vpif_int_err: a free_irq() can occur
of an element &vpif_obj.dev[VPIF_DISPLAY_MAX_DEVICES]->channel_id which is
outside vpif_obj.dev[] array boundaries.

Signed-off-by: Roel Kluin <roel.kluin@gmail.com>
---
Or am I mistaken?

diff --git a/drivers/media/video/davinci/vpif_display.c b/drivers/media/video/davinci/vpif_display.c
index dfddef7..8f6605d 100644
--- a/drivers/media/video/davinci/vpif_display.c
+++ b/drivers/media/video/davinci/vpif_display.c
@@ -383,7 +383,7 @@ static int vpif_get_std_info(struct channel_obj *ch)
 	int index;
 
 	std_info->stdid = vid_ch->stdid;
-	if (!std_info)
+	if (!std_info->stdid)
 		return -1;
 
 	for (index = 0; index < ARRAY_SIZE(ch_params); index++) {
@@ -1423,7 +1423,7 @@ static __init int vpif_probe(struct platform_device *pdev)
 {
 	struct vpif_subdev_info *subdevdata;
 	struct vpif_display_config *config;
-	int i, j = 0, k, q, m, err = 0;
+	int i, j = 0, k, m, err = 0;
 	struct i2c_adapter *i2c_adap;
 	struct common_obj *common;
 	struct channel_obj *ch;
@@ -1573,10 +1573,12 @@ probe_out:
 		video_device_release(ch->video_dev);
 		ch->video_dev = NULL;
 	}
+	if (k == VPIF_DISPLAY_MAX_DEVICES)
+		k = VPIF_DISPLAY_MAX_DEVICES - 1;
 vpif_int_err:
 	v4l2_device_unregister(&vpif_obj.v4l2_dev);
 	vpif_err("VPIF IRQ request failed\n");
-	for (q = k; k >= 0; k--) {
+	for (; k >= 0; k--) {
 		for (m = i; m >= res->start; m--)
 			free_irq(m, (void *)(&vpif_obj.dev[k]->channel_id));
 		res = platform_get_resource(pdev, IORESOURCE_IRQ, k-1);

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* RE: [PATCH] video_device: don't free_irq() an element past array vpif_obj.dev[] and fix test
  2010-02-09 11:59 [PATCH] video_device: don't free_irq() an element past array vpif_obj.dev[] and fix test Roel Kluin
@ 2010-02-18 16:31 ` Karicheri, Muralidharan
  2010-02-18 20:02   ` roel kluin
  0 siblings, 1 reply; 7+ messages in thread
From: Karicheri, Muralidharan @ 2010-02-18 16:31 UTC (permalink / raw)
  To: Roel Kluin, Mauro Carvalho Chehab, linux-media@vger.kernel.org,
	Andrew Morton, LKML

Roel,

Thanks for the patch. 

>In vpif_get_std_info(): std_info doesn't need the NULL test, it was already
>dereferenced anyway. If std_info->stdid is 0 we could early return -1.
>
>In vpif_probe(): local variable q was only assigned. If we error out with
>either last two goto's then j equals VPIF_DISPLAY_MAX_DEVICES. So after the
>probe_out: label, k also reaches VPIF_DISPLAY_MAX_DEVICES after the loop.
>In
>the first iteration in the loop after vpif_int_err: a free_irq() can occur
>of an element &vpif_obj.dev[VPIF_DISPLAY_MAX_DEVICES]->channel_id which is
>outside vpif_obj.dev[] array boundaries.
>
>Signed-off-by: Roel Kluin <roel.kluin@gmail.com>
>---
>Or am I mistaken?
>
>diff --git a/drivers/media/video/davinci/vpif_display.c
>b/drivers/media/video/davinci/vpif_display.c
>index dfddef7..8f6605d 100644
>--- a/drivers/media/video/davinci/vpif_display.c
>+++ b/drivers/media/video/davinci/vpif_display.c
>@@ -383,7 +383,7 @@ static int vpif_get_std_info(struct channel_obj *ch)
> 	int index;
>
> 	std_info->stdid = vid_ch->stdid;
>-	if (!std_info)
>+	if (!std_info->stdid)
> 		return -1;
>
This is a NACK. We shouldn't check for stdid since the function is supposed
to update std_info. So just remove

if (!std_info)
	return -1;

I am okay with the below change. So please re-submit the patch with the 
above change and my ACK.

Thanks

Murali

> 	for (index = 0; index < ARRAY_SIZE(ch_params); index++) {
>@@ -1423,7 +1423,7 @@ static __init int vpif_probe(struct platform_device
>*pdev)
> {
> 	struct vpif_subdev_info *subdevdata;
> 	struct vpif_display_config *config;
>-	int i, j = 0, k, q, m, err = 0;
>+	int i, j = 0, k, m, err = 0;
> 	struct i2c_adapter *i2c_adap;
> 	struct common_obj *common;
> 	struct channel_obj *ch;
>@@ -1573,10 +1573,12 @@ probe_out:
> 		video_device_release(ch->video_dev);
> 		ch->video_dev = NULL;
> 	}
>+	if (k == VPIF_DISPLAY_MAX_DEVICES)
>+		k = VPIF_DISPLAY_MAX_DEVICES - 1;
> vpif_int_err:
> 	v4l2_device_unregister(&vpif_obj.v4l2_dev);
> 	vpif_err("VPIF IRQ request failed\n");
>-	for (q = k; k >= 0; k--) {
>+	for (; k >= 0; k--) {
> 		for (m = i; m >= res->start; m--)
> 			free_irq(m, (void *)(&vpif_obj.dev[k]->channel_id));
> 		res = platform_get_resource(pdev, IORESOURCE_IRQ, k-1);
>--
>To unsubscribe from this list: send the line "unsubscribe linux-media" in
>the body of a message to majordomo@vger.kernel.org
>More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] video_device: don't free_irq() an element past array vpif_obj.dev[] and fix test
  2010-02-18 16:31 ` Karicheri, Muralidharan
@ 2010-02-18 20:02   ` roel kluin
  2010-02-18 20:25     ` Karicheri, Muralidharan
  0 siblings, 1 reply; 7+ messages in thread
From: roel kluin @ 2010-02-18 20:02 UTC (permalink / raw)
  To: Karicheri, Muralidharan
  Cc: Mauro Carvalho Chehab, linux-media@vger.kernel.org, Andrew Morton,
	LKML

>>-      if (!std_info)
>>+      if (!std_info->stdid)
>>               return -1;
>>
> This is a NACK. We shouldn't check for stdid since the function is supposed
> to update std_info. So just remove
>
> if (!std_info)
>        return -1;

I don't see how std_info could get updated. consider the loop in case
std_info->stdid equals 0:

        for (index = 0; index < ARRAY_SIZE(ch_params); index++) {
                config = &ch_params[index];

(config is a local variable)

                if (config->stdid & std_info->stdid) {

This fails for every index if std_info->stdid equals 0.

                        memcpy(std_info, config, sizeof(*config));
                        break;
                }
        }

So we always reach this with index == ARRAY_SIZE(ch_params)

        if (index == ARRAY_SIZE(ch_params))
                return -1;

So we could have returned -1 earlier.

> I am okay with the below change. So please re-submit the patch with the
> above change and my ACK.
>
> Thanks
>
> Murali
>

>>+      if (k == VPIF_DISPLAY_MAX_DEVICES)
>>+              k = VPIF_DISPLAY_MAX_DEVICES - 1;

actually I think this is still not right. shouldn't it be be

k = VPIF_DISPLAY_MAX_DEVICES - 1;

> are you using this driver in your project?

No, I just found this in the code.

Thanks, Roel

^ permalink raw reply	[flat|nested] 7+ messages in thread

* RE: [PATCH] video_device: don't free_irq() an element past array vpif_obj.dev[] and fix test
  2010-02-18 20:02   ` roel kluin
@ 2010-02-18 20:25     ` Karicheri, Muralidharan
  2010-02-19 19:35       ` Roel Kluin
  2010-02-19 19:50       ` Roel Kluin
  0 siblings, 2 replies; 7+ messages in thread
From: Karicheri, Muralidharan @ 2010-02-18 20:25 UTC (permalink / raw)
  To: roel kluin
  Cc: Mauro Carvalho Chehab, linux-media@vger.kernel.org, Andrew Morton,
	LKML



>>>-      if (!std_info)
>>>+      if (!std_info->stdid)
>>>               return -1;
>>>
>> This is a NACK. We shouldn't check for stdid since the function is
>supposed
>> to update std_info. So just remove
>>
>> if (!std_info)
>>        return -1;
>
>I don't see how std_info could get updated. consider the loop in case
>std_info->stdid equals 0:

Ok. You are right! The ch_params[] is a table for keeping the information
about different standards supported. For a given stdid in std_info, the function matches the stdid with that in the table and get the corresponding entry.


>> I am okay with the below change. So please re-submit the patch with the
>> above change and my ACK.
>>
>> Thanks
>>
>> Murali
>>
>
>>>+      if (k == VPIF_DISPLAY_MAX_DEVICES)
>>>+              k = VPIF_DISPLAY_MAX_DEVICES - 1;
>
>actually I think this is still not right. shouldn't it be be
>
>k = VPIF_DISPLAY_MAX_DEVICES - 1;

What you mean here? What you suggest here is same as in your patch, right?

Murali
>
>> are you using this driver in your project?
>
>No, I just found this in the code.
>
>Thanks, Roel

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] video_device: don't free_irq() an element past array vpif_obj.dev[] and fix test
  2010-02-18 20:25     ` Karicheri, Muralidharan
@ 2010-02-19 19:35       ` Roel Kluin
  2010-02-19 19:50       ` Roel Kluin
  1 sibling, 0 replies; 7+ messages in thread
From: Roel Kluin @ 2010-02-19 19:35 UTC (permalink / raw)
  To: Karicheri, Muralidharan
  Cc: Mauro Carvalho Chehab, linux-media@vger.kernel.org, Andrew Morton,
	LKML


> Ok. You are right! The ch_params[] is a table for keeping the information
> about different standards supported. For a given stdid in std_info, the function matches the stdid with that in the table and get the corresponding entry.

>>>> +      if (k == VPIF_DISPLAY_MAX_DEVICES)
>>>> +              k = VPIF_DISPLAY_MAX_DEVICES - 1;
>>
>> actually I think this is still not right. shouldn't it be be
>>
>> k = VPIF_DISPLAY_MAX_DEVICES - 1;
> 
> What you mean here? What you suggest here is same as in your patch, right?

I think there were many more issues:

The first loop ends when platform_get_resource() returns NULL. Can it occur
that no platform_get_resource() succeeded? I think we should error return if
that happens. Could k grow larger than VPIF_DISPLAY_MAX_DEVICES there?
Should we err out in that case?

In the loop `for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++)' if
video_device_alloc() fails I think we correctly release the devices,
but we have to do more before we reach label vpif_int_err.

As mentioned, we left the first loop with a res of NULL, which is
dereferenced at label vpif_int_err. So we have to get the resource again,
however, k was incremented at the end of that loop as well. Also i used
as index in the second loop as well should point to res->end before going
to label vpif_int_err, to free all requested irqs. All this needs to be
done for later error labels as well, so a new label should be added.

Variable k can't be reused, it is needed to get the resource in case a
error and cleanup is required.

Also in label probe_out a loop with k as index is used, but k is already
an index that is required to get the resource later.

If we reach label vpif_int_err, res shouldn't be NULL, since we
dereference it. Previously we had:

        for (; k >= 0; k--) {
                for (m = i; m >= res->start; m--)
                        free_irq(m, (void *)(&vpif_obj.dev[k]->channel_id));
                res = platform_get_resource(pdev, IORESOURCE_IRQ, k-1);
                m = res->end;
        }

In the last iteration k equals 0, so we call platform_get_resource() with
-1 as a third argument. Since platform_get_resource() uses an unsigned it
is converted to 0xffffffff. platform_get_resource() fails for every index
and returns NULL. A test is lacking and we dereference NULL.

This all occurs at the new label alloc_vid_fail.

The error "VPIF IRQ request failed" should only be displayed when 
request_irq() failed, not in the case of other errors.

Also I changed some indexes, so a few could be removed.

I must admit I did not test this, except with checkpatch.pl, but I think
the issues are real and should be fixed. Do you have comments?

 drivers/media/video/davinci/vpif_display.c |   61 +++++++++++++++++++---------
 1 files changed, 41 insertions(+), 20 deletions(-)

diff --git a/drivers/media/video/davinci/vpif_display.c b/drivers/media/video/davinci/vpif_display.c
index dfddef7..ae8ca94 100644
--- a/drivers/media/video/davinci/vpif_display.c
+++ b/drivers/media/video/davinci/vpif_display.c
@@ -383,7 +383,7 @@ static int vpif_get_std_info(struct channel_obj *ch)
 	int index;
 
 	std_info->stdid = vid_ch->stdid;
-	if (!std_info)
+	if (!std_info->stdid)
 		return -1;
 
 	for (index = 0; index < ARRAY_SIZE(ch_params); index++) {
@@ -1423,7 +1423,7 @@ static __init int vpif_probe(struct platform_device *pdev)
 {
 	struct vpif_subdev_info *subdevdata;
 	struct vpif_display_config *config;
-	int i, j = 0, k, q, m, err = 0;
+	int i, j, k, err;
 	struct i2c_adapter *i2c_adap;
 	struct common_obj *common;
 	struct channel_obj *ch;
@@ -1452,12 +1452,18 @@ static __init int vpif_probe(struct platform_device *pdev)
 			if (request_irq(i, vpif_channel_isr, IRQF_DISABLED,
 					"DM646x_Display",
 				(void *)(&vpif_obj.dev[k]->channel_id))) {
+				i--;
 				err = -EBUSY;
+				vpif_err("VPIF IRQ request failed\n");
 				goto vpif_int_err;
 			}
 		}
 		k++;
+		if (k >= VPIF_DISPLAY_MAX_DEVICES)
+			break;
 	}
+	if (k == 0)
+		return -ENODEV;
 
 	for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) {
 
@@ -1472,7 +1478,7 @@ static __init int vpif_probe(struct platform_device *pdev)
 				video_device_release(ch->video_dev);
 			}
 			err = -ENOMEM;
-			goto vpif_int_err;
+			goto alloc_vid_fail;
 		}
 
 		/* Initialize field of video device */
@@ -1489,13 +1495,13 @@ static __init int vpif_probe(struct platform_device *pdev)
 		ch->video_dev = vfd;
 	}
 
-	for (j = 0; j < VPIF_DISPLAY_MAX_DEVICES; j++) {
-		ch = vpif_obj.dev[j];
+	for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) {
+		ch = vpif_obj.dev[i];
 		/* Initialize field of the channel objects */
 		atomic_set(&ch->usrs, 0);
-		for (k = 0; k < VPIF_NUMOBJECTS; k++) {
-			ch->common[k].numbuffers = 0;
-			common = &ch->common[k];
+		for (j = 0; j < VPIF_NUMOBJECTS; j++) {
+			ch->common[j].numbuffers = 0;
+			common = &ch->common[j];
 			common->io_usrs = 0;
 			common->started = 0;
 			spin_lock_init(&common->irqlock);
@@ -1506,12 +1512,12 @@ static __init int vpif_probe(struct platform_device *pdev)
 			common->ctop_off = common->cbtm_off = 0;
 			common->cur_frm = common->next_frm = NULL;
 			memset(&common->fmt, 0, sizeof(common->fmt));
-			common->numbuffers = config_params.numbuffers[k];
+			common->numbuffers = config_params.numbuffers[j];
 
 		}
 		ch->initialized = 0;
-		ch->channel_id = j;
-		if (j < 2)
+		ch->channel_id = i;
+		if (i < 2)
 			ch->common[VPIF_VIDEO_INDEX].numbuffers =
 			    config_params.numbuffers[ch->channel_id];
 		else
@@ -1529,7 +1535,7 @@ static __init int vpif_probe(struct platform_device *pdev)
 				(int)ch, (int)&ch->video_dev);
 
 		err = video_register_device(ch->video_dev,
-					  VFL_TYPE_GRABBER, (j ? 3 : 2));
+					  VFL_TYPE_GRABBER, (i ? 3 : 2));
 		if (err < 0)
 			goto probe_out;
 
@@ -1567,20 +1573,35 @@ static __init int vpif_probe(struct platform_device *pdev)
 probe_subdev_out:
 	kfree(vpif_obj.sd);
 probe_out:
-	for (k = 0; k < j; k++) {
-		ch = vpif_obj.dev[k];
+	for (j = 0; j < i; j++) {
+		ch = vpif_obj.dev[j];
 		video_unregister_device(ch->video_dev);
 		video_device_release(ch->video_dev);
 		ch->video_dev = NULL;
 	}
+alloc_vid_fail:
+	while (k--) {
+		res = platform_get_resource(pdev, IORESOURCE_IRQ, k);
+		if (res != NULL)
+			break;
+		vpif_err("Couldn't get resource %d, irqs not freed.\n", k);
+	}
+	if (res == NULL) {
+		vpif_err("Couldn't get any resource.\n");
+		return err;
+	}
+
+	i = res->end;
 vpif_int_err:
 	v4l2_device_unregister(&vpif_obj.v4l2_dev);
-	vpif_err("VPIF IRQ request failed\n");
-	for (q = k; k >= 0; k--) {
-		for (m = i; m >= res->start; m--)
-			free_irq(m, (void *)(&vpif_obj.dev[k]->channel_id));
-		res = platform_get_resource(pdev, IORESOURCE_IRQ, k-1);
-		m = res->end;
+
+	for (j = i; j >= res->start; j--)
+		free_irq(j, (void *)(&vpif_obj.dev[k]->channel_id));
+
+	while (k--) {
+		res = platform_get_resource(pdev, IORESOURCE_IRQ, k);
+		for (j =  res->end; j >= res->start; j--)
+			free_irq(j, (void *)(&vpif_obj.dev[k]->channel_id));
 	}
 
 	return err;

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH] video_device: don't free_irq() an element past array vpif_obj.dev[] and fix test
  2010-02-18 20:25     ` Karicheri, Muralidharan
  2010-02-19 19:35       ` Roel Kluin
@ 2010-02-19 19:50       ` Roel Kluin
  2010-02-19 23:28         ` Roel Kluin
  1 sibling, 1 reply; 7+ messages in thread
From: Roel Kluin @ 2010-02-19 19:50 UTC (permalink / raw)
  To: Karicheri, Muralidharan
  Cc: Mauro Carvalho Chehab, linux-media@vger.kernel.org, Andrew Morton,
	LKML

The first loop ends when platform_get_resource() returns NULL. Can it occur
that no platform_get_resource() succeeded? I think we should error return if
that happens. Could k grow larger than VPIF_DISPLAY_MAX_DEVICES there?
Should we err out in that case?

In the loop `for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++)' if
video_device_alloc() fails I think we correctly release the devices,
but we have to do more before we reach label vpif_int_err.

As mentioned, we left the first loop with a res of NULL, which is
dereferenced at label vpif_int_err. So we have to get the resource again,
however, k was incremented at the end of that loop as well. Also i used
as index in the second loop as well should point to res->end before going
to label vpif_int_err, to free all requested irqs. All this needs to be
done for later error labels as well, so a new label is added where this
occurs, alloc_vid_fail.

Variable k can't be reused in the third for-loop and at label probe_out.
As mentioned k is needed to get the resource in case a error and clean-up
is required.

If we reach label vpif_int_err, res shouldn't be NULL, since we
dereference it. Previously we had:

        for (; k >= 0; k--) {
                for (m = i; m >= res->start; m--)
                        free_irq(m, (void *)(&vpif_obj.dev[k]->channel_id));
                res = platform_get_resource(pdev, IORESOURCE_IRQ, k-1);
                m = res->end;
        }

In the last iteration k equals 0, so we call platform_get_resource() with
-1 as a third argument. Since platform_get_resource() uses an unsigned it
is converted to 0xffffffff. platform_get_resource() fails for every index
and returns NULL. A test is lacking and we dereference NULL.

The error "VPIF IRQ request failed" should only be displayed when 
request_irq() failed, not in the case of other errors.

Also I changed some indexes, so a few could be removed.

Signed-off-by: Roel Kluin <roel.kluin@gmail.com>
---
There were some errors in the changelog and a signoff was missing.

> Ok. You are right! The ch_params[] is a table for keeping the information
> about different standards supported. For a given stdid in std_info, the function matches the stdid with that in the table and get the corresponding entry.

>>>> +      if (k == VPIF_DISPLAY_MAX_DEVICES)
>>>> +              k = VPIF_DISPLAY_MAX_DEVICES - 1;
>>
>> actually I think this is still not right. shouldn't it be be
>>
>> k = VPIF_DISPLAY_MAX_DEVICES - 1;
> 
> What you mean here? What you suggest here is same as in your patch, right?

I must admit I did not test this, except with checkpatch.pl, but I think
the issues are real and should be fixed. Do you have comments?

 drivers/media/video/davinci/vpif_display.c |   61 +++++++++++++++++++---------
 1 files changed, 41 insertions(+), 20 deletions(-)

diff --git a/drivers/media/video/davinci/vpif_display.c b/drivers/media/video/davinci/vpif_display.c
index dfddef7..ae8ca94 100644
--- a/drivers/media/video/davinci/vpif_display.c
+++ b/drivers/media/video/davinci/vpif_display.c
@@ -383,7 +383,7 @@ static int vpif_get_std_info(struct channel_obj *ch)
 	int index;
 
 	std_info->stdid = vid_ch->stdid;
-	if (!std_info)
+	if (!std_info->stdid)
 		return -1;
 
 	for (index = 0; index < ARRAY_SIZE(ch_params); index++) {
@@ -1423,7 +1423,7 @@ static __init int vpif_probe(struct platform_device *pdev)
 {
 	struct vpif_subdev_info *subdevdata;
 	struct vpif_display_config *config;
-	int i, j = 0, k, q, m, err = 0;
+	int i, j, k, err;
 	struct i2c_adapter *i2c_adap;
 	struct common_obj *common;
 	struct channel_obj *ch;
@@ -1452,12 +1452,18 @@ static __init int vpif_probe(struct platform_device *pdev)
 			if (request_irq(i, vpif_channel_isr, IRQF_DISABLED,
 					"DM646x_Display",
 				(void *)(&vpif_obj.dev[k]->channel_id))) {
+				i--;
 				err = -EBUSY;
+				vpif_err("VPIF IRQ request failed\n");
 				goto vpif_int_err;
 			}
 		}
 		k++;
+		if (k >= VPIF_DISPLAY_MAX_DEVICES)
+			break;
 	}
+	if (k == 0)
+		return -ENODEV;
 
 	for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) {
 
@@ -1472,7 +1478,7 @@ static __init int vpif_probe(struct platform_device *pdev)
 				video_device_release(ch->video_dev);
 			}
 			err = -ENOMEM;
-			goto vpif_int_err;
+			goto alloc_vid_fail;
 		}
 
 		/* Initialize field of video device */
@@ -1489,13 +1495,13 @@ static __init int vpif_probe(struct platform_device *pdev)
 		ch->video_dev = vfd;
 	}
 
-	for (j = 0; j < VPIF_DISPLAY_MAX_DEVICES; j++) {
-		ch = vpif_obj.dev[j];
+	for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) {
+		ch = vpif_obj.dev[i];
 		/* Initialize field of the channel objects */
 		atomic_set(&ch->usrs, 0);
-		for (k = 0; k < VPIF_NUMOBJECTS; k++) {
-			ch->common[k].numbuffers = 0;
-			common = &ch->common[k];
+		for (j = 0; j < VPIF_NUMOBJECTS; j++) {
+			ch->common[j].numbuffers = 0;
+			common = &ch->common[j];
 			common->io_usrs = 0;
 			common->started = 0;
 			spin_lock_init(&common->irqlock);
@@ -1506,12 +1512,12 @@ static __init int vpif_probe(struct platform_device *pdev)
 			common->ctop_off = common->cbtm_off = 0;
 			common->cur_frm = common->next_frm = NULL;
 			memset(&common->fmt, 0, sizeof(common->fmt));
-			common->numbuffers = config_params.numbuffers[k];
+			common->numbuffers = config_params.numbuffers[j];
 
 		}
 		ch->initialized = 0;
-		ch->channel_id = j;
-		if (j < 2)
+		ch->channel_id = i;
+		if (i < 2)
 			ch->common[VPIF_VIDEO_INDEX].numbuffers =
 			    config_params.numbuffers[ch->channel_id];
 		else
@@ -1529,7 +1535,7 @@ static __init int vpif_probe(struct platform_device *pdev)
 				(int)ch, (int)&ch->video_dev);
 
 		err = video_register_device(ch->video_dev,
-					  VFL_TYPE_GRABBER, (j ? 3 : 2));
+					  VFL_TYPE_GRABBER, (i ? 3 : 2));
 		if (err < 0)
 			goto probe_out;
 
@@ -1567,20 +1573,35 @@ static __init int vpif_probe(struct platform_device *pdev)
 probe_subdev_out:
 	kfree(vpif_obj.sd);
 probe_out:
-	for (k = 0; k < j; k++) {
-		ch = vpif_obj.dev[k];
+	for (j = 0; j < i; j++) {
+		ch = vpif_obj.dev[j];
 		video_unregister_device(ch->video_dev);
 		video_device_release(ch->video_dev);
 		ch->video_dev = NULL;
 	}
+alloc_vid_fail:
+	while (k--) {
+		res = platform_get_resource(pdev, IORESOURCE_IRQ, k);
+		if (res != NULL)
+			break;
+		vpif_err("Couldn't get resource %d, irqs not freed.\n", k);
+	}
+	if (res == NULL) {
+		vpif_err("Couldn't get any resource.\n");
+		return err;
+	}
+
+	i = res->end;
 vpif_int_err:
 	v4l2_device_unregister(&vpif_obj.v4l2_dev);
-	vpif_err("VPIF IRQ request failed\n");
-	for (q = k; k >= 0; k--) {
-		for (m = i; m >= res->start; m--)
-			free_irq(m, (void *)(&vpif_obj.dev[k]->channel_id));
-		res = platform_get_resource(pdev, IORESOURCE_IRQ, k-1);
-		m = res->end;
+
+	for (j = i; j >= res->start; j--)
+		free_irq(j, (void *)(&vpif_obj.dev[k]->channel_id));
+
+	while (k--) {
+		res = platform_get_resource(pdev, IORESOURCE_IRQ, k);
+		for (j =  res->end; j >= res->start; j--)
+			free_irq(j, (void *)(&vpif_obj.dev[k]->channel_id));
 	}
 
 	return err;

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH] video_device: don't free_irq() an element past array vpif_obj.dev[] and fix test
  2010-02-19 19:50       ` Roel Kluin
@ 2010-02-19 23:28         ` Roel Kluin
  0 siblings, 0 replies; 7+ messages in thread
From: Roel Kluin @ 2010-02-19 23:28 UTC (permalink / raw)
  To: Roel Kluin
  Cc: Karicheri, Muralidharan, Mauro Carvalho Chehab,
	linux-media@vger.kernel.org, Andrew Morton, LKML,
	davinci-linux-open-source

The first loop ends when platform_get_resource() returns NULL. Can it occur
that no platform_get_resource() succeeded? I think we should error return if
that happens. Could k grow larger than VPIF_DISPLAY_MAX_DEVICES there? Should
we err out in that case?

In the loop `for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++)' if
video_device_alloc() fails I think we correctly release the devices, but we
have to do more before we reach label vpif_int_err.

As mentioned, we left the first loop with a res of NULL, which is dereferenced
at label vpif_int_err. So we have to get the resource again, however, k was
incremented at the end of that loop as well. Also i used as index in the second
loop as well should point to res->end before going to label vpif_int_err, to
free all requested irqs. All this needs to be done for later error labels as
well, so a new label is added where this occurs, alloc_vid_fail.

Variable k can't be reused in the third for-loop and at label probe_out. As
mentioned k is needed to get the resource in case a error and clean-up is
required.

If we reach label vpif_int_err, res shouldn't be NULL, since we dereference it.
Previously we had:

        for (; k >= 0; k--) {
                for (m = i; m >= res->start; m--)
                        free_irq(m, (void *)(&vpif_obj.dev[k]->channel_id));
                res = platform_get_resource(pdev, IORESOURCE_IRQ, k-1);
                m = res->end;
        }

In the last iteration k equals 0, so we call platform_get_resource() with -1 as
a third argument. Since platform_get_resource() uses an unsigned it is
converted to 0xffffffff. platform_get_resource() fails for every index and
returns NULL. A test is lacking and we dereference NULL.

The error "VPIF IRQ request failed" should only be displayed when request_irq()
failed, not in the case of other errors.

Also I changed some indexes, so a few could be removed.

Signed-off-by: Roel Kluin <roel.kluin@gmail.com>
---
> I think there were many more issues:

> I must admit I did not compile test this, except with checkpatch.pl, but I
> think the issues are real and should be fixed. Comments?

I would like to compile test but cannot compile test these because of errors
like drivers/net/davinci_emac.c:69:11: error: unable to open 'mach/dm646x.h'

I found these three other functions in davinci code that have very similar
problems. The changelog is about vpif_probe() in vpif_display.c.

Since the functions are somewhat similar, maybe code should be shared, but
where should one put that?

Roel

 drivers/media/video/davinci/vpif_capture.c |   63 +++++++++++++----------
 drivers/media/video/davinci/vpif_display.c |   76 ++++++++++++++++++----------
 drivers/net/davinci_emac.c                 |   64 ++++++++++++++++--------
 3 files changed, 129 insertions(+), 74 deletions(-)

diff --git a/drivers/media/video/davinci/vpif_capture.c b/drivers/media/video/davinci/vpif_capture.c
index 7813072..096e727 100644
--- a/drivers/media/video/davinci/vpif_capture.c
+++ b/drivers/media/video/davinci/vpif_capture.c
@@ -1915,7 +1915,7 @@ static __init int vpif_probe(struct platform_device *pdev)
 {
 	struct vpif_subdev_info *subdevdata;
 	struct vpif_capture_config *config;
-	int i, j, k, m, q, err;
+	int i, j, k, err;
 	struct i2c_adapter *i2c_adap;
 	struct channel_obj *ch;
 	struct common_obj *common;
@@ -1936,14 +1936,18 @@ static __init int vpif_probe(struct platform_device *pdev)
 		for (i = res->start; i <= res->end; i++) {
 			if (request_irq(i, vpif_channel_isr, IRQF_DISABLED,
 					"DM646x_Capture",
-				(void *)(&vpif_obj.dev[k]->channel_id))) {
-				err = -EBUSY;
+				&vpif_obj.dev[k]->channel_id)) {
 				i--;
+				err = -EBUSY;
 				goto vpif_int_err;
 			}
 		}
 		k++;
+		if (k >= VPIF_DISPLAY_MAX_DEVICES)
+			break;
 	}
+	if (k == 0)
+		return -ENODEV;
 
 	for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) {
 		/* Get the pointer to the channel object */
@@ -1972,16 +1976,16 @@ static __init int vpif_probe(struct platform_device *pdev)
 		ch->video_dev = vfd;
 	}
 
-	for (j = 0; j < VPIF_CAPTURE_MAX_DEVICES; j++) {
-		ch = vpif_obj.dev[j];
-		ch->channel_id = j;
+	for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) {
+		ch = vpif_obj.dev[i];
+		ch->channel_id = i;
 		common = &(ch->common[VPIF_VIDEO_INDEX]);
 		spin_lock_init(&common->irqlock);
 		mutex_init(&common->lock);
 		/* Initialize prio member of channel object */
 		v4l2_prio_init(&ch->prio);
 		err = video_register_device(ch->video_dev,
-					    VFL_TYPE_GRABBER, (j ? 1 : 0));
+					    VFL_TYPE_GRABBER, (i ? 1 : 0));
 		if (err)
 			goto probe_out;
 
@@ -2007,24 +2011,24 @@ static __init int vpif_probe(struct platform_device *pdev)
 		goto probe_subdev_out;
 	}
 
-	for (i = 0; i < subdev_count; i++) {
-		subdevdata = &config->subdev_info[i];
-		vpif_obj.sd[i] =
+	for (j = 0; j < subdev_count; j++) {
+		subdevdata = &config->subdev_info[j];
+		vpif_obj.sd[j] =
 			v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev,
 						  i2c_adap,
 						  subdevdata->name,
 						  &subdevdata->board_info,
 						  NULL);
 
-		if (!vpif_obj.sd[i]) {
+		if (!vpif_obj.sd[j]) {
 			vpif_err("Error registering v4l2 subdevice\n");
 			goto probe_subdev_out;
 		}
 		v4l2_info(&vpif_obj.v4l2_dev, "registered sub device %s\n",
 			  subdevdata->name);
 
-		if (vpif_obj.sd[i])
-			vpif_obj.sd[i]->grp_id = 1 << i;
+		if (vpif_obj.sd[j])
+			vpif_obj.sd[j]->grp_id = 1 << j;
 	}
 	v4l2_info(&vpif_obj.v4l2_dev, "DM646x VPIF Capture driver"
 		  " initialized\n");
@@ -2034,30 +2038,37 @@ static __init int vpif_probe(struct platform_device *pdev)
 probe_subdev_out:
 	/* free sub devices memory */
 	kfree(vpif_obj.sd);
-
-	j = VPIF_CAPTURE_MAX_DEVICES;
 probe_out:
 	v4l2_device_unregister(&vpif_obj.v4l2_dev);
-	for (k = 0; k < j; k++) {
+	for (j = 0; j < i; j++) {
 		/* Get the pointer to the channel object */
-		ch = vpif_obj.dev[k];
+		ch = vpif_obj.dev[j];
 		/* Unregister video device */
 		video_unregister_device(ch->video_dev);
 	}
 
 vpif_dev_alloc_err:
-	k = VPIF_CAPTURE_MAX_DEVICES-1;
-	res = platform_get_resource(pdev, IORESOURCE_IRQ, k);
+	while (k--) {
+		res = platform_get_resource(pdev, IORESOURCE_IRQ, k);
+		if (res != NULL)
+			break;
+		vpif_err("Couldn't free irqs for resource %d.\n", k);
+	}
+	if (res == NULL)
+		return err;
 	i = res->end;
-
 vpif_int_err:
-	for (q = k; q >= 0; q--) {
-		for (m = i; m >= (int)res->start; m--)
-			free_irq(m, (void *)(&vpif_obj.dev[q]->channel_id));
+	for (j = i; j >= (int)res->start; j--)
+		free_irq(j, &vpif_obj.dev[k]->channel_id);
 
-		res = platform_get_resource(pdev, IORESOURCE_IRQ, q-1);
-		if (res)
-			i = res->end;
+	while (k--) {
+		res = platform_get_resource(pdev, IORESOURCE_IRQ, k);
+		if (res == NULL) {
+			vpif_err("Couldn't free irqs for resource %d.\n", k);
+			continue;
+		}
+		for (j = res->end; j >= (int)res->start; j--)
+			free_irq(j, &vpif_obj.dev[k]->channel_id);
 	}
 	return err;
 }
diff --git a/drivers/media/video/davinci/vpif_display.c b/drivers/media/video/davinci/vpif_display.c
index dfddef7..6bcedbf 100644
--- a/drivers/media/video/davinci/vpif_display.c
+++ b/drivers/media/video/davinci/vpif_display.c
@@ -383,7 +383,7 @@ static int vpif_get_std_info(struct channel_obj *ch)
 	int index;
 
 	std_info->stdid = vid_ch->stdid;
-	if (!std_info)
+	if (!std_info->stdid)
 		return -1;
 
 	for (index = 0; index < ARRAY_SIZE(ch_params); index++) {
@@ -1423,7 +1423,7 @@ static __init int vpif_probe(struct platform_device *pdev)
 {
 	struct vpif_subdev_info *subdevdata;
 	struct vpif_display_config *config;
-	int i, j = 0, k, q, m, err = 0;
+	int i, j, k, err;
 	struct i2c_adapter *i2c_adap;
 	struct common_obj *common;
 	struct channel_obj *ch;
@@ -1452,12 +1452,18 @@ static __init int vpif_probe(struct platform_device *pdev)
 			if (request_irq(i, vpif_channel_isr, IRQF_DISABLED,
 					"DM646x_Display",
 				(void *)(&vpif_obj.dev[k]->channel_id))) {
+				i--;
 				err = -EBUSY;
+				vpif_err("VPIF IRQ request failed\n");
 				goto vpif_int_err;
 			}
 		}
 		k++;
+		if (k >= VPIF_DISPLAY_MAX_DEVICES)
+			break;
 	}
+	if (k == 0)
+		return -ENODEV;
 
 	for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) {
 
@@ -1472,7 +1478,7 @@ static __init int vpif_probe(struct platform_device *pdev)
 				video_device_release(ch->video_dev);
 			}
 			err = -ENOMEM;
-			goto vpif_int_err;
+			goto alloc_vid_fail;
 		}
 
 		/* Initialize field of video device */
@@ -1489,13 +1495,13 @@ static __init int vpif_probe(struct platform_device *pdev)
 		ch->video_dev = vfd;
 	}
 
-	for (j = 0; j < VPIF_DISPLAY_MAX_DEVICES; j++) {
-		ch = vpif_obj.dev[j];
+	for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) {
+		ch = vpif_obj.dev[i];
 		/* Initialize field of the channel objects */
 		atomic_set(&ch->usrs, 0);
-		for (k = 0; k < VPIF_NUMOBJECTS; k++) {
-			ch->common[k].numbuffers = 0;
-			common = &ch->common[k];
+		for (j = 0; j < VPIF_NUMOBJECTS; j++) {
+			ch->common[j].numbuffers = 0;
+			common = &ch->common[j];
 			common->io_usrs = 0;
 			common->started = 0;
 			spin_lock_init(&common->irqlock);
@@ -1506,12 +1512,12 @@ static __init int vpif_probe(struct platform_device *pdev)
 			common->ctop_off = common->cbtm_off = 0;
 			common->cur_frm = common->next_frm = NULL;
 			memset(&common->fmt, 0, sizeof(common->fmt));
-			common->numbuffers = config_params.numbuffers[k];
+			common->numbuffers = config_params.numbuffers[j];
 
 		}
 		ch->initialized = 0;
-		ch->channel_id = j;
-		if (j < 2)
+		ch->channel_id = i;
+		if (i < 2)
 			ch->common[VPIF_VIDEO_INDEX].numbuffers =
 			    config_params.numbuffers[ch->channel_id];
 		else
@@ -1529,7 +1535,7 @@ static __init int vpif_probe(struct platform_device *pdev)
 				(int)ch, (int)&ch->video_dev);
 
 		err = video_register_device(ch->video_dev,
-					  VFL_TYPE_GRABBER, (j ? 3 : 2));
+					  VFL_TYPE_GRABBER, (i ? 3 : 2));
 		if (err < 0)
 			goto probe_out;
 
@@ -1548,18 +1554,18 @@ static __init int vpif_probe(struct platform_device *pdev)
 		goto probe_out;
 	}
 
-	for (i = 0; i < subdev_count; i++) {
-		vpif_obj.sd[i] = v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev,
-						i2c_adap, subdevdata[i].name,
-						&subdevdata[i].board_info,
+	for (j = 0; j < subdev_count; j++) {
+		vpif_obj.sd[j] = v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev,
+						i2c_adap, subdevdata[j].name,
+						&subdevdata[j].board_info,
 						NULL);
-		if (!vpif_obj.sd[i]) {
+		if (!vpif_obj.sd[j]) {
 			vpif_err("Error registering v4l2 subdevice\n");
 			goto probe_subdev_out;
 		}
 
-		if (vpif_obj.sd[i])
-			vpif_obj.sd[i]->grp_id = 1 << i;
+		if (vpif_obj.sd[j])
+			vpif_obj.sd[j]->grp_id = 1 << j;
 	}
 
 	return 0;
@@ -1567,20 +1573,36 @@ static __init int vpif_probe(struct platform_device *pdev)
 probe_subdev_out:
 	kfree(vpif_obj.sd);
 probe_out:
-	for (k = 0; k < j; k++) {
-		ch = vpif_obj.dev[k];
+	for (j = 0; j < i; j++) {
+		ch = vpif_obj.dev[j];
 		video_unregister_device(ch->video_dev);
 		video_device_release(ch->video_dev);
 		ch->video_dev = NULL;
 	}
+alloc_vid_fail:
+	while (k--) {
+		res = platform_get_resource(pdev, IORESOURCE_IRQ, k);
+		if (res != NULL)
+			break;
+		vpif_err("Couldn't free irqs for resource %d.\n", k);
+	}
+	if (res == NULL)
+		return err;
+	i = res->end;
 vpif_int_err:
 	v4l2_device_unregister(&vpif_obj.v4l2_dev);
-	vpif_err("VPIF IRQ request failed\n");
-	for (q = k; k >= 0; k--) {
-		for (m = i; m >= res->start; m--)
-			free_irq(m, (void *)(&vpif_obj.dev[k]->channel_id));
-		res = platform_get_resource(pdev, IORESOURCE_IRQ, k-1);
-		m = res->end;
+
+	for (j = i; j >= res->start; j--)
+		free_irq(j, (void *)(&vpif_obj.dev[k]->channel_id));
+
+	while (k--) {
+		res = platform_get_resource(pdev, IORESOURCE_IRQ, k);
+		if (res == NULL) {
+			vpif_err("Couldn't free irqs for resource %d.\n", k);
+			continue;
+		}
+		for (j =  res->end; j >= res->start; j--)
+			free_irq(j, (void *)(&vpif_obj.dev[k]->channel_id));
 	}
 
 	return err;
diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c
index 33c4fe2..2faa9d3 100644
--- a/drivers/net/davinci_emac.c
+++ b/drivers/net/davinci_emac.c
@@ -2369,12 +2369,12 @@ static int emac_devioctl(struct net_device *ndev, struct ifreq *ifrq, int cmd)
 static int emac_dev_open(struct net_device *ndev)
 {
 	struct device *emac_dev = &ndev->dev;
-	u32 rc, cnt, ch;
+	u32 cnt, ch;
 	int phy_addr;
 	struct resource *res;
-	int q, m;
-	int i = 0;
+	int i, j, k, err;
 	int k = 0;
+	int err;
 	struct emac_priv *priv = netdev_priv(ndev);
 
 	netif_carrier_off(ndev);
@@ -2398,15 +2398,15 @@ static int emac_dev_open(struct net_device *ndev)
 	emac_write(EMAC_MACHASH2, 0);
 
 	/* multi ch not supported - open 1 TX, 1RX ch by default */
-	rc = emac_init_txch(priv, EMAC_DEF_TX_CH);
-	if (0 != rc) {
+	err = emac_init_txch(priv, EMAC_DEF_TX_CH);
+	if (err) {
 		dev_err(emac_dev, "DaVinci EMAC: emac_init_txch() failed");
-		return rc;
+		return err;
 	}
-	rc = emac_init_rxch(priv, EMAC_DEF_RX_CH, priv->mac_addr);
-	if (0 != rc) {
+	err = emac_init_rxch(priv, EMAC_DEF_RX_CH, priv->mac_addr);
+	if (err) {
 		dev_err(emac_dev, "DaVinci EMAC: emac_init_rxch() failed");
-		return rc;
+		return err;
 	}
 
 	/* Request IRQ */
@@ -2414,11 +2414,17 @@ static int emac_dev_open(struct net_device *ndev)
 	while ((res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, k))) {
 		for (i = res->start; i <= res->end; i++) {
 			if (request_irq(i, emac_irq, IRQF_DISABLED,
-					ndev->name, ndev))
+					ndev->name, ndev)) {
+				i--;
+				err = -EBUSY;
+				dev_err(emac_dev, "DaVinci EMAC: request_irq() failed");
 				goto rollback;
+			}
 		}
 		k++;
 	}
+	if (k == 0)
+		return -ENODEV;
 
 	/* Start/Enable EMAC hardware */
 	emac_hw_enable(priv);
@@ -2436,7 +2442,8 @@ static int emac_dev_open(struct net_device *ndev)
 
 		if (!priv->phydev) {
 			printk(KERN_ERR "%s: no PHY found\n", ndev->name);
-			return -1;
+			err = -ENODEV;
+			goto phydev_error;
 		}
 
 		priv->phydev = phy_connect(ndev, dev_name(&priv->phydev->dev),
@@ -2445,7 +2452,8 @@ static int emac_dev_open(struct net_device *ndev)
 		if (IS_ERR(priv->phydev)) {
 			printk(KERN_ERR "%s: Could not attach to PHY\n",
 								ndev->name);
-			return PTR_ERR(priv->phydev);
+			err = PTR_ERR(priv->phydev);
+			goto phydev_error;
 		}
 
 		priv->link = 0;
@@ -2456,7 +2464,7 @@ static int emac_dev_open(struct net_device *ndev)
 			"(mii_bus:phy_addr=%s, id=%x)\n", ndev->name,
 			priv->phydev->drv->name, dev_name(&priv->phydev->dev),
 			priv->phydev->phy_id);
-	} else{
+	} else {
 		/* No PHY , fix the link, speed and duplex settings */
 		priv->link = 1;
 		priv->speed = SPEED_100;
@@ -2475,15 +2483,29 @@ static int emac_dev_open(struct net_device *ndev)
 
 	return 0;
 
+phydev_error:
+	while (k--) {
+		res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, k);
+		if (res != NULL)
+			break;
+		dev_err(emac_dev, "Couldn't free irqs for resource %d.\n", k);
+	}
+	if (res == NULL)
+		return err;
+	i = res->end;
 rollback:
-
-	dev_err(emac_dev, "DaVinci EMAC: request_irq() failed");
-
-	for (q = k; k >= 0; k--) {
-		for (m = i; m >= res->start; m--)
-			free_irq(m, ndev);
-		res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, k-1);
-		m = res->end;
+	for (j = i; j >= res->start; j--)
+		free_irq(j, ndev);
+
+	while (k--) {
+		res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, k);
+		if (res == NULL) {
+			dev_err(emac_dev, "Couldn't free irqs for resource %d.\n",
+					 k);
+			continue;
+		}
+		for (j = res->end; j >= res->start; j--)
+			free_irq(j, ndev);
 	}
 	return -EBUSY;
 }

^ permalink raw reply related	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2010-02-19 23:20 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-02-09 11:59 [PATCH] video_device: don't free_irq() an element past array vpif_obj.dev[] and fix test Roel Kluin
2010-02-18 16:31 ` Karicheri, Muralidharan
2010-02-18 20:02   ` roel kluin
2010-02-18 20:25     ` Karicheri, Muralidharan
2010-02-19 19:35       ` Roel Kluin
2010-02-19 19:50       ` Roel Kluin
2010-02-19 23:28         ` Roel Kluin

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox