Skip to content

Commit 002752a

Browse files
andy-shevrafaeljw
authored andcommitted
device property: Allow error pointer to be passed to fwnode APIs
Some of the fwnode APIs might return an error pointer instead of NULL or valid fwnode handle. The result of such API call may be considered optional and hence the test for it is usually done in a form of fwnode = fwnode_find_reference(...); if (IS_ERR(fwnode)) ...error handling... Nevertheless the resulting fwnode may have bumped the reference count and hence caller of the above API is obliged to call fwnode_handle_put(). Since fwnode may be not valid either as NULL or error pointer the check has to be performed there. This approach uglifies the code and adds a point of making a mistake, i.e. forgetting about error point case. To prevent this, allow an error pointer to be passed to the fwnode APIs. Fixes: 83b34af ("device property: Introduce fwnode_find_reference()") Reported-by: Nuno Sá <nuno.sa@analog.com> Tested-by: Nuno Sá <nuno.sa@analog.com> Acked-by: Nuno Sá <nuno.sa@analog.com> Reviewed-by: Sakari Ailus <sakari.ailus@linux.intel.com> Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Tested-by: Michael Walle <michael@walle.cc> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
1 parent 3bd561e commit 002752a

File tree

2 files changed

+56
-43
lines changed

2 files changed

+56
-43
lines changed

drivers/base/property.c

Lines changed: 51 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,14 @@ bool fwnode_property_present(const struct fwnode_handle *fwnode,
4747
{
4848
bool ret;
4949

50+
if (IS_ERR_OR_NULL(fwnode))
51+
return false;
52+
5053
ret = fwnode_call_bool_op(fwnode, property_present, propname);
51-
if (ret == false && !IS_ERR_OR_NULL(fwnode) &&
52-
!IS_ERR_OR_NULL(fwnode->secondary))
53-
ret = fwnode_call_bool_op(fwnode->secondary, property_present,
54-
propname);
55-
return ret;
54+
if (ret)
55+
return ret;
56+
57+
return fwnode_call_bool_op(fwnode->secondary, property_present, propname);
5658
}
5759
EXPORT_SYMBOL_GPL(fwnode_property_present);
5860

@@ -232,15 +234,16 @@ static int fwnode_property_read_int_array(const struct fwnode_handle *fwnode,
232234
{
233235
int ret;
234236

237+
if (IS_ERR_OR_NULL(fwnode))
238+
return -EINVAL;
239+
235240
ret = fwnode_call_int_op(fwnode, property_read_int_array, propname,
236241
elem_size, val, nval);
237-
if (ret == -EINVAL && !IS_ERR_OR_NULL(fwnode) &&
238-
!IS_ERR_OR_NULL(fwnode->secondary))
239-
ret = fwnode_call_int_op(
240-
fwnode->secondary, property_read_int_array, propname,
241-
elem_size, val, nval);
242+
if (ret != -EINVAL)
243+
return ret;
242244

243-
return ret;
245+
return fwnode_call_int_op(fwnode->secondary, property_read_int_array, propname,
246+
elem_size, val, nval);
244247
}
245248

246249
/**
@@ -371,14 +374,16 @@ int fwnode_property_read_string_array(const struct fwnode_handle *fwnode,
371374
{
372375
int ret;
373376

377+
if (IS_ERR_OR_NULL(fwnode))
378+
return -EINVAL;
379+
374380
ret = fwnode_call_int_op(fwnode, property_read_string_array, propname,
375381
val, nval);
376-
if (ret == -EINVAL && !IS_ERR_OR_NULL(fwnode) &&
377-
!IS_ERR_OR_NULL(fwnode->secondary))
378-
ret = fwnode_call_int_op(fwnode->secondary,
379-
property_read_string_array, propname,
380-
val, nval);
381-
return ret;
382+
if (ret != -EINVAL)
383+
return ret;
384+
385+
return fwnode_call_int_op(fwnode->secondary, property_read_string_array, propname,
386+
val, nval);
382387
}
383388
EXPORT_SYMBOL_GPL(fwnode_property_read_string_array);
384389

@@ -480,15 +485,19 @@ int fwnode_property_get_reference_args(const struct fwnode_handle *fwnode,
480485
{
481486
int ret;
482487

488+
if (IS_ERR_OR_NULL(fwnode))
489+
return -ENOENT;
490+
483491
ret = fwnode_call_int_op(fwnode, get_reference_args, prop, nargs_prop,
484492
nargs, index, args);
493+
if (ret == 0)
494+
return ret;
485495

486-
if (ret < 0 && !IS_ERR_OR_NULL(fwnode) &&
487-
!IS_ERR_OR_NULL(fwnode->secondary))
488-
ret = fwnode_call_int_op(fwnode->secondary, get_reference_args,
489-
prop, nargs_prop, nargs, index, args);
496+
if (IS_ERR_OR_NULL(fwnode->secondary))
497+
return ret;
490498

491-
return ret;
499+
return fwnode_call_int_op(fwnode->secondary, get_reference_args, prop, nargs_prop,
500+
nargs, index, args);
492501
}
493502
EXPORT_SYMBOL_GPL(fwnode_property_get_reference_args);
494503

@@ -635,12 +644,13 @@ EXPORT_SYMBOL_GPL(fwnode_count_parents);
635644
struct fwnode_handle *fwnode_get_nth_parent(struct fwnode_handle *fwnode,
636645
unsigned int depth)
637646
{
638-
unsigned int i;
639-
640647
fwnode_handle_get(fwnode);
641648

642-
for (i = 0; i < depth && fwnode; i++)
649+
do {
650+
if (depth-- == 0)
651+
break;
643652
fwnode = fwnode_get_next_parent(fwnode);
653+
} while (fwnode);
644654

645655
return fwnode;
646656
}
@@ -659,17 +669,17 @@ EXPORT_SYMBOL_GPL(fwnode_get_nth_parent);
659669
bool fwnode_is_ancestor_of(struct fwnode_handle *test_ancestor,
660670
struct fwnode_handle *test_child)
661671
{
662-
if (!test_ancestor)
672+
if (IS_ERR_OR_NULL(test_ancestor))
663673
return false;
664674

665675
fwnode_handle_get(test_child);
666-
while (test_child) {
676+
do {
667677
if (test_child == test_ancestor) {
668678
fwnode_handle_put(test_child);
669679
return true;
670680
}
671681
test_child = fwnode_get_next_parent(test_child);
672-
}
682+
} while (test_child);
673683
return false;
674684
}
675685

@@ -698,7 +708,7 @@ fwnode_get_next_available_child_node(const struct fwnode_handle *fwnode,
698708
{
699709
struct fwnode_handle *next_child = child;
700710

701-
if (!fwnode)
711+
if (IS_ERR_OR_NULL(fwnode))
702712
return NULL;
703713

704714
do {
@@ -722,16 +732,16 @@ struct fwnode_handle *device_get_next_child_node(struct device *dev,
722732
const struct fwnode_handle *fwnode = dev_fwnode(dev);
723733
struct fwnode_handle *next;
724734

735+
if (IS_ERR_OR_NULL(fwnode))
736+
return NULL;
737+
725738
/* Try to find a child in primary fwnode */
726739
next = fwnode_get_next_child_node(fwnode, child);
727740
if (next)
728741
return next;
729742

730743
/* When no more children in primary, continue with secondary */
731-
if (fwnode && !IS_ERR_OR_NULL(fwnode->secondary))
732-
next = fwnode_get_next_child_node(fwnode->secondary, child);
733-
734-
return next;
744+
return fwnode_get_next_child_node(fwnode->secondary, child);
735745
}
736746
EXPORT_SYMBOL_GPL(device_get_next_child_node);
737747

@@ -798,6 +808,9 @@ EXPORT_SYMBOL_GPL(fwnode_handle_put);
798808
*/
799809
bool fwnode_device_is_available(const struct fwnode_handle *fwnode)
800810
{
811+
if (IS_ERR_OR_NULL(fwnode))
812+
return false;
813+
801814
if (!fwnode_has_op(fwnode, device_is_available))
802815
return true;
803816

@@ -958,14 +971,14 @@ fwnode_graph_get_next_endpoint(const struct fwnode_handle *fwnode,
958971
parent = fwnode_graph_get_port_parent(prev);
959972
else
960973
parent = fwnode;
974+
if (IS_ERR_OR_NULL(parent))
975+
return NULL;
961976

962977
ep = fwnode_call_ptr_op(parent, graph_get_next_endpoint, prev);
978+
if (ep)
979+
return ep;
963980

964-
if (IS_ERR_OR_NULL(ep) &&
965-
!IS_ERR_OR_NULL(parent) && !IS_ERR_OR_NULL(parent->secondary))
966-
ep = fwnode_graph_get_next_endpoint(parent->secondary, NULL);
967-
968-
return ep;
981+
return fwnode_graph_get_next_endpoint(parent->secondary, NULL);
969982
}
970983
EXPORT_SYMBOL_GPL(fwnode_graph_get_next_endpoint);
971984

include/linux/fwnode.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -153,12 +153,12 @@ struct fwnode_operations {
153153
int (*add_links)(struct fwnode_handle *fwnode);
154154
};
155155

156-
#define fwnode_has_op(fwnode, op) \
157-
((fwnode) && (fwnode)->ops && (fwnode)->ops->op)
156+
#define fwnode_has_op(fwnode, op) \
157+
(!IS_ERR_OR_NULL(fwnode) && (fwnode)->ops && (fwnode)->ops->op)
158+
158159
#define fwnode_call_int_op(fwnode, op, ...) \
159-
(fwnode ? (fwnode_has_op(fwnode, op) ? \
160-
(fwnode)->ops->op(fwnode, ## __VA_ARGS__) : -ENXIO) : \
161-
-EINVAL)
160+
(fwnode_has_op(fwnode, op) ? \
161+
(fwnode)->ops->op(fwnode, ## __VA_ARGS__) : (IS_ERR_OR_NULL(fwnode) ? -EINVAL : -ENXIO))
162162

163163
#define fwnode_call_bool_op(fwnode, op, ...) \
164164
(fwnode_has_op(fwnode, op) ? \

0 commit comments

Comments
 (0)