[SPARC64]: Fix MD property lifetime bugs.
Property values cannot be referenced outside of mdesc_grab()/mdesc_release() pairs. The only major offender was the VIO bus layer, easily fixed. Add some commentary to mdesc.h describing these rules. Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
43fdf27470
commit
83292e0a9c
@ -44,12 +44,11 @@ static const struct vio_device_id *vio_match_device(
|
|||||||
|
|
||||||
while (matches->type[0] || matches->compat[0]) {
|
while (matches->type[0] || matches->compat[0]) {
|
||||||
int match = 1;
|
int match = 1;
|
||||||
if (matches->type[0]) {
|
if (matches->type[0])
|
||||||
match &= type
|
match &= !strcmp(matches->type, type);
|
||||||
&& !strcmp(matches->type, type);
|
|
||||||
}
|
|
||||||
if (matches->compat[0]) {
|
if (matches->compat[0]) {
|
||||||
match &= compat &&
|
match &= len &&
|
||||||
find_in_proplist(compat, matches->compat, len);
|
find_in_proplist(compat, matches->compat, len);
|
||||||
}
|
}
|
||||||
if (match)
|
if (match)
|
||||||
@ -205,15 +204,30 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
|
|||||||
const char *type, *compat;
|
const char *type, *compat;
|
||||||
struct device_node *dp;
|
struct device_node *dp;
|
||||||
struct vio_dev *vdev;
|
struct vio_dev *vdev;
|
||||||
int err, clen;
|
int err, tlen, clen;
|
||||||
|
|
||||||
type = mdesc_get_property(hp, mp, "device-type", NULL);
|
type = mdesc_get_property(hp, mp, "device-type", &tlen);
|
||||||
if (!type) {
|
if (!type) {
|
||||||
type = mdesc_get_property(hp, mp, "name", NULL);
|
type = mdesc_get_property(hp, mp, "name", &tlen);
|
||||||
if (!type)
|
if (!type) {
|
||||||
type = mdesc_node_name(hp, mp);
|
type = mdesc_node_name(hp, mp);
|
||||||
|
tlen = strlen(type) + 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if (tlen > VIO_MAX_TYPE_LEN) {
|
||||||
|
printk(KERN_ERR "VIO: Type string [%s] is too long.\n",
|
||||||
|
type);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
compat = mdesc_get_property(hp, mp, "device-type", &clen);
|
compat = mdesc_get_property(hp, mp, "device-type", &clen);
|
||||||
|
if (!compat) {
|
||||||
|
clen = 0;
|
||||||
|
} else if (clen > VIO_MAX_COMPAT_LEN) {
|
||||||
|
printk(KERN_ERR "VIO: Compat len %d for [%s] is too long.\n",
|
||||||
|
clen, type);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
|
vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
|
||||||
if (!vdev) {
|
if (!vdev) {
|
||||||
@ -222,8 +236,11 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
|
|||||||
}
|
}
|
||||||
|
|
||||||
vdev->mp = mp;
|
vdev->mp = mp;
|
||||||
vdev->type = type;
|
memcpy(vdev->type, type, tlen);
|
||||||
vdev->compat = compat;
|
if (compat)
|
||||||
|
memcpy(vdev->compat, compat, clen);
|
||||||
|
else
|
||||||
|
memset(vdev->compat, 0, sizeof(vdev->compat));
|
||||||
vdev->compat_len = clen;
|
vdev->compat_len = clen;
|
||||||
|
|
||||||
vdev->channel_id = ~0UL;
|
vdev->channel_id = ~0UL;
|
||||||
|
@ -23,8 +23,28 @@ extern u64 mdesc_node_by_name(struct mdesc_handle *handle,
|
|||||||
(__node) != MDESC_NODE_NULL; \
|
(__node) != MDESC_NODE_NULL; \
|
||||||
__node = mdesc_node_by_name(__hdl, __node, __name))
|
__node = mdesc_node_by_name(__hdl, __node, __name))
|
||||||
|
|
||||||
|
/* Access to property values returned from mdesc_get_property() are
|
||||||
|
* only valid inside of a mdesc_grab()/mdesc_release() sequence.
|
||||||
|
* Once mdesc_release() is called, the memory backed up by these
|
||||||
|
* pointers may reference freed up memory.
|
||||||
|
*
|
||||||
|
* Therefore callers must make copies of any property values
|
||||||
|
* they need.
|
||||||
|
*
|
||||||
|
* These same rules apply to mdesc_node_name().
|
||||||
|
*/
|
||||||
extern const void *mdesc_get_property(struct mdesc_handle *handle,
|
extern const void *mdesc_get_property(struct mdesc_handle *handle,
|
||||||
u64 node, const char *name, int *lenp);
|
u64 node, const char *name, int *lenp);
|
||||||
|
extern const char *mdesc_node_name(struct mdesc_handle *hp, u64 node);
|
||||||
|
|
||||||
|
/* MD arc iteration, the standard sequence is:
|
||||||
|
*
|
||||||
|
* unsigned long arc;
|
||||||
|
* mdesc_for_each_arc(arc, handle, node, MDESC_ARC_TYPE_{FWD,BACK}) {
|
||||||
|
* unsigned long target = mdesc_arc_target(handle, arc);
|
||||||
|
* ...
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
|
||||||
#define MDESC_ARC_TYPE_FWD "fwd"
|
#define MDESC_ARC_TYPE_FWD "fwd"
|
||||||
#define MDESC_ARC_TYPE_BACK "back"
|
#define MDESC_ARC_TYPE_BACK "back"
|
||||||
@ -38,8 +58,6 @@ extern u64 mdesc_next_arc(struct mdesc_handle *handle, u64 from,
|
|||||||
|
|
||||||
extern u64 mdesc_arc_target(struct mdesc_handle *hp, u64 arc);
|
extern u64 mdesc_arc_target(struct mdesc_handle *hp, u64 arc);
|
||||||
|
|
||||||
extern const char *mdesc_node_name(struct mdesc_handle *hp, u64 node);
|
|
||||||
|
|
||||||
extern void mdesc_update(void);
|
extern void mdesc_update(void);
|
||||||
|
|
||||||
extern void sun4v_mdesc_init(void);
|
extern void sun4v_mdesc_init(void);
|
||||||
|
@ -264,12 +264,15 @@ static inline u32 vio_dring_avail(struct vio_dring_state *dr,
|
|||||||
((dr->prod - dr->cons) & (ring_size - 1)));
|
((dr->prod - dr->cons) & (ring_size - 1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define VIO_MAX_TYPE_LEN 64
|
||||||
|
#define VIO_MAX_COMPAT_LEN 64
|
||||||
|
|
||||||
struct vio_dev {
|
struct vio_dev {
|
||||||
u64 mp;
|
u64 mp;
|
||||||
struct device_node *dp;
|
struct device_node *dp;
|
||||||
|
|
||||||
const char *type;
|
char type[VIO_MAX_TYPE_LEN];
|
||||||
const char *compat;
|
char compat[VIO_MAX_COMPAT_LEN];
|
||||||
int compat_len;
|
int compat_len;
|
||||||
|
|
||||||
unsigned long channel_id;
|
unsigned long channel_id;
|
||||||
|
Loading…
Reference in New Issue
Block a user