[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]) {
|
||||
int match = 1;
|
||||
if (matches->type[0]) {
|
||||
match &= type
|
||||
&& !strcmp(matches->type, type);
|
||||
}
|
||||
if (matches->type[0])
|
||||
match &= !strcmp(matches->type, type);
|
||||
|
||||
if (matches->compat[0]) {
|
||||
match &= compat &&
|
||||
match &= len &&
|
||||
find_in_proplist(compat, matches->compat, len);
|
||||
}
|
||||
if (match)
|
||||
|
@ -205,15 +204,30 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
|
|||
const char *type, *compat;
|
||||
struct device_node *dp;
|
||||
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) {
|
||||
type = mdesc_get_property(hp, mp, "name", NULL);
|
||||
if (!type)
|
||||
type = mdesc_get_property(hp, mp, "name", &tlen);
|
||||
if (!type) {
|
||||
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);
|
||||
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);
|
||||
if (!vdev) {
|
||||
|
@ -222,8 +236,11 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
|
|||
}
|
||||
|
||||
vdev->mp = mp;
|
||||
vdev->type = type;
|
||||
vdev->compat = compat;
|
||||
memcpy(vdev->type, type, tlen);
|
||||
if (compat)
|
||||
memcpy(vdev->compat, compat, clen);
|
||||
else
|
||||
memset(vdev->compat, 0, sizeof(vdev->compat));
|
||||
vdev->compat_len = clen;
|
||||
|
||||
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_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,
|
||||
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_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 const char *mdesc_node_name(struct mdesc_handle *hp, u64 node);
|
||||
|
||||
extern void mdesc_update(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)));
|
||||
}
|
||||
|
||||
#define VIO_MAX_TYPE_LEN 64
|
||||
#define VIO_MAX_COMPAT_LEN 64
|
||||
|
||||
struct vio_dev {
|
||||
u64 mp;
|
||||
struct device_node *dp;
|
||||
|
||||
const char *type;
|
||||
const char *compat;
|
||||
char type[VIO_MAX_TYPE_LEN];
|
||||
char compat[VIO_MAX_COMPAT_LEN];
|
||||
int compat_len;
|
||||
|
||||
unsigned long channel_id;
|
||||
|
|
Loading…
Reference in a new issue