Commit 697cc9c8 authored by Daniel Vetter's avatar Daniel Vetter

drm: Simplify GETRESOURCES ioctl

Looping twice when we can do it once is silly. Also use a consistent
style. Note that there's a good race with the connector list walking,
since that is no longer protected by mode_config.mutex. But that's for
a later patch to fix.

v2: Actually try to not blow up, somehow I lost the hunk that checks
we don't copy too much. Noticed by Chris.

v3:
- squash all drm_mode_getresources cleanups into one
- use consistent style for walking objects (Chris)

v4:
- Use u64_to_user_ptr (Chris)
- Don't forget to copy the last connector (Chris)

v5: Chris was right ...

Cc: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/20161211192019.29603-1-daniel.vetter@ffwll.ch
parent 122020af
...@@ -84,17 +84,11 @@ int drm_mode_getresources(struct drm_device *dev, void *data, ...@@ -84,17 +84,11 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
struct drm_file *file_priv) struct drm_file *file_priv)
{ {
struct drm_mode_card_res *card_res = data; struct drm_mode_card_res *card_res = data;
struct list_head *lh;
struct drm_framebuffer *fb; struct drm_framebuffer *fb;
struct drm_connector *connector; struct drm_connector *connector;
struct drm_crtc *crtc; struct drm_crtc *crtc;
struct drm_encoder *encoder; struct drm_encoder *encoder;
int ret = 0; int count, ret = 0;
int connector_count = 0;
int crtc_count = 0;
int fb_count = 0;
int encoder_count = 0;
int copied = 0;
uint32_t __user *fb_id; uint32_t __user *fb_id;
uint32_t __user *crtc_id; uint32_t __user *crtc_id;
uint32_t __user *connector_id; uint32_t __user *connector_id;
...@@ -105,89 +99,62 @@ int drm_mode_getresources(struct drm_device *dev, void *data, ...@@ -105,89 +99,62 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
mutex_lock(&file_priv->fbs_lock); mutex_lock(&file_priv->fbs_lock);
/* count = 0;
* For the non-control nodes we need to limit the list of resources fb_id = u64_to_user_ptr(card_res->fb_id_ptr);
* by IDs in the group list for this node list_for_each_entry(fb, &file_priv->fbs, filp_head) {
*/ if (count < card_res->count_fbs &&
list_for_each(lh, &file_priv->fbs) put_user(fb->base.id, fb_id + count)) {
fb_count++; mutex_unlock(&file_priv->fbs_lock);
return -EFAULT;
/* handle this in 4 parts */
/* FBs */
if (card_res->count_fbs >= fb_count) {
copied = 0;
fb_id = (uint32_t __user *)(unsigned long)card_res->fb_id_ptr;
list_for_each_entry(fb, &file_priv->fbs, filp_head) {
if (put_user(fb->base.id, fb_id + copied)) {
mutex_unlock(&file_priv->fbs_lock);
return -EFAULT;
}
copied++;
} }
count++;
} }
card_res->count_fbs = fb_count; card_res->count_fbs = count;
mutex_unlock(&file_priv->fbs_lock); mutex_unlock(&file_priv->fbs_lock);
/* mode_config.mutex protects the connector list against e.g. DP MST /* mode_config.mutex protects the connector list against e.g. DP MST
* connector hot-adding. CRTC/Plane lists are invariant. */ * connector hot-adding. CRTC/Plane lists are invariant. */
mutex_lock(&dev->mode_config.mutex); mutex_lock(&dev->mode_config.mutex);
drm_for_each_crtc(crtc, dev)
crtc_count++;
drm_for_each_connector(connector, dev)
connector_count++;
drm_for_each_encoder(encoder, dev)
encoder_count++;
card_res->max_height = dev->mode_config.max_height; card_res->max_height = dev->mode_config.max_height;
card_res->min_height = dev->mode_config.min_height; card_res->min_height = dev->mode_config.min_height;
card_res->max_width = dev->mode_config.max_width; card_res->max_width = dev->mode_config.max_width;
card_res->min_width = dev->mode_config.min_width; card_res->min_width = dev->mode_config.min_width;
/* CRTCs */ count = 0;
if (card_res->count_crtcs >= crtc_count) { crtc_id = u64_to_user_ptr(card_res->crtc_id_ptr);
copied = 0; drm_for_each_crtc(crtc, dev) {
crtc_id = (uint32_t __user *)(unsigned long)card_res->crtc_id_ptr; if (count < card_res->count_crtcs &&
drm_for_each_crtc(crtc, dev) { put_user(crtc->base.id, crtc_id + count)) {
if (put_user(crtc->base.id, crtc_id + copied)) { ret = -EFAULT;
ret = -EFAULT; goto out;
goto out;
}
copied++;
} }
count++;
} }
card_res->count_crtcs = crtc_count; card_res->count_crtcs = count;
/* Encoders */ count = 0;
if (card_res->count_encoders >= encoder_count) { encoder_id = u64_to_user_ptr(card_res->encoder_id_ptr);
copied = 0; drm_for_each_encoder(encoder, dev) {
encoder_id = (uint32_t __user *)(unsigned long)card_res->encoder_id_ptr; if (count < card_res->count_encoders &&
drm_for_each_encoder(encoder, dev) { put_user(encoder->base.id, encoder_id + count)) {
if (put_user(encoder->base.id, encoder_id + ret = -EFAULT;
copied)) { goto out;
ret = -EFAULT;
goto out;
}
copied++;
} }
count++;
} }
card_res->count_encoders = encoder_count; card_res->count_encoders = count;
/* Connectors */ count = 0;
if (card_res->count_connectors >= connector_count) { connector_id = u64_to_user_ptr(card_res->connector_id_ptr);
copied = 0; drm_for_each_connector(connector, dev) {
connector_id = (uint32_t __user *)(unsigned long)card_res->connector_id_ptr; if (count < card_res->count_connectors &&
drm_for_each_connector(connector, dev) { put_user(connector->base.id, connector_id + count)) {
if (put_user(connector->base.id, ret = -EFAULT;
connector_id + copied)) { goto out;
ret = -EFAULT;
goto out;
}
copied++;
} }
count++;
} }
card_res->count_connectors = connector_count; card_res->count_connectors = count;
out: out:
mutex_unlock(&dev->mode_config.mutex); mutex_unlock(&dev->mode_config.mutex);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment