diff options
author | Ilija Hadzic <ilijahadzic@gmail.com> | 2012-10-29 13:35:01 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2012-11-06 19:51:15 -0500 |
commit | fdb40a08ef7bc970899c3a1f471165f9c22763a1 (patch) | |
tree | 70426eb405d29964713c9954cb116027152f8a8a /drivers | |
parent | 0f1cb1bd94a9c967cd4ad3de51cfdabe61eb5dcc (diff) |
drm: set dev_mapping before calling drm_open_helper
Some drivers (specifically vmwgfx) look at dev_mapping
in their open hook, so we have to set dev->dev_mapping
earlier in the process.
Reference:
http://lists.freedesktop.org/archives/dri-devel/2012-October/029420.html
Signed-off-by: Ilija Hadzic <ihadzic@research.bell-labs.com>
Reported-by: Thomas Hellstrom <thellstrom@vmware.com>
Cc: stable@vger.kernel.org
Reviewed-by: Thomas Hellstrom <thellstrom@vmware.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpu/drm/drm_fops.c | 47 |
1 files changed, 30 insertions, 17 deletions
diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c index af68eca44abe..133b4132983e 100644 --- a/drivers/gpu/drm/drm_fops.c +++ b/drivers/gpu/drm/drm_fops.c | |||
@@ -121,6 +121,8 @@ int drm_open(struct inode *inode, struct file *filp) | |||
121 | int minor_id = iminor(inode); | 121 | int minor_id = iminor(inode); |
122 | struct drm_minor *minor; | 122 | struct drm_minor *minor; |
123 | int retcode = 0; | 123 | int retcode = 0; |
124 | int need_setup = 0; | ||
125 | struct address_space *old_mapping; | ||
124 | 126 | ||
125 | minor = idr_find(&drm_minors_idr, minor_id); | 127 | minor = idr_find(&drm_minors_idr, minor_id); |
126 | if (!minor) | 128 | if (!minor) |
@@ -132,26 +134,37 @@ int drm_open(struct inode *inode, struct file *filp) | |||
132 | if (drm_device_is_unplugged(dev)) | 134 | if (drm_device_is_unplugged(dev)) |
133 | return -ENODEV; | 135 | return -ENODEV; |
134 | 136 | ||
137 | if (!dev->open_count++) | ||
138 | need_setup = 1; | ||
139 | mutex_lock(&dev->struct_mutex); | ||
140 | old_mapping = dev->dev_mapping; | ||
141 | if (old_mapping == NULL) | ||
142 | dev->dev_mapping = &inode->i_data; | ||
143 | /* ihold ensures nobody can remove inode with our i_data */ | ||
144 | ihold(container_of(dev->dev_mapping, struct inode, i_data)); | ||
145 | inode->i_mapping = dev->dev_mapping; | ||
146 | filp->f_mapping = dev->dev_mapping; | ||
147 | mutex_unlock(&dev->struct_mutex); | ||
148 | |||
135 | retcode = drm_open_helper(inode, filp, dev); | 149 | retcode = drm_open_helper(inode, filp, dev); |
136 | if (!retcode) { | 150 | if (retcode) |
137 | atomic_inc(&dev->counts[_DRM_STAT_OPENS]); | 151 | goto err_undo; |
138 | if (!dev->open_count++) { | 152 | atomic_inc(&dev->counts[_DRM_STAT_OPENS]); |
139 | retcode = drm_setup(dev); | 153 | if (need_setup) { |
140 | if (retcode) | 154 | retcode = drm_setup(dev); |
141 | dev->open_count--; | 155 | if (retcode) |
142 | } | 156 | goto err_undo; |
143 | } | ||
144 | if (!retcode) { | ||
145 | mutex_lock(&dev->struct_mutex); | ||
146 | if (dev->dev_mapping == NULL) | ||
147 | dev->dev_mapping = &inode->i_data; | ||
148 | /* ihold ensures nobody can remove inode with our i_data */ | ||
149 | ihold(container_of(dev->dev_mapping, struct inode, i_data)); | ||
150 | inode->i_mapping = dev->dev_mapping; | ||
151 | filp->f_mapping = dev->dev_mapping; | ||
152 | mutex_unlock(&dev->struct_mutex); | ||
153 | } | 157 | } |
158 | return 0; | ||
154 | 159 | ||
160 | err_undo: | ||
161 | mutex_lock(&dev->struct_mutex); | ||
162 | filp->f_mapping = old_mapping; | ||
163 | inode->i_mapping = old_mapping; | ||
164 | iput(container_of(dev->dev_mapping, struct inode, i_data)); | ||
165 | dev->dev_mapping = old_mapping; | ||
166 | mutex_unlock(&dev->struct_mutex); | ||
167 | dev->open_count--; | ||
155 | return retcode; | 168 | return retcode; |
156 | } | 169 | } |
157 | EXPORT_SYMBOL(drm_open); | 170 | EXPORT_SYMBOL(drm_open); |