diff options
Diffstat (limited to 'drivers/gpu/drm/drm_fops.c')
-rw-r--r-- | drivers/gpu/drm/drm_fops.c | 44 |
1 files changed, 30 insertions, 14 deletions
diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c index 7ef1b673e1be..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,23 +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 | } | 154 | retcode = drm_setup(dev); |
141 | if (!retcode) { | 155 | if (retcode) |
142 | mutex_lock(&dev->struct_mutex); | 156 | goto err_undo; |
143 | if (dev->dev_mapping == NULL) | ||
144 | dev->dev_mapping = &inode->i_data; | ||
145 | /* ihold ensures nobody can remove inode with our i_data */ | ||
146 | ihold(container_of(dev->dev_mapping, struct inode, i_data)); | ||
147 | inode->i_mapping = dev->dev_mapping; | ||
148 | filp->f_mapping = dev->dev_mapping; | ||
149 | mutex_unlock(&dev->struct_mutex); | ||
150 | } | 157 | } |
158 | return 0; | ||
151 | 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--; | ||
152 | return retcode; | 168 | return retcode; |
153 | } | 169 | } |
154 | EXPORT_SYMBOL(drm_open); | 170 | EXPORT_SYMBOL(drm_open); |