1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31#include <linux/slab.h>
32
33#include <drm/drm_auth.h>
34#include <drm/drm_drv.h>
35#include <drm/drm_file.h>
36#include <drm/drm_lease.h>
37#include <drm/drm_print.h>
38
39#include "drm_internal.h"
40#include "drm_legacy.h"
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64static bool drm_is_current_master_locked(struct drm_file *fpriv)
65{
66 lockdep_assert_once(lockdep_is_held(&fpriv->master_lookup_lock) ||
67 lockdep_is_held(&fpriv->minor->dev->master_mutex));
68
69 return fpriv->is_master && drm_lease_owner(fpriv->master) == fpriv->minor->dev->master;
70}
71
72
73
74
75
76
77
78
79
80
81
82bool drm_is_current_master(struct drm_file *fpriv)
83{
84 bool ret;
85
86 spin_lock(&fpriv->master_lookup_lock);
87 ret = drm_is_current_master_locked(fpriv);
88 spin_unlock(&fpriv->master_lookup_lock);
89
90 return ret;
91}
92EXPORT_SYMBOL(drm_is_current_master);
93
94int drm_getmagic(struct drm_device *dev, void *data, struct drm_file *file_priv)
95{
96 struct drm_auth *auth = data;
97 int ret = 0;
98
99 mutex_lock(&dev->master_mutex);
100 if (!file_priv->magic) {
101 ret = idr_alloc(&file_priv->master->magic_map, file_priv,
102 1, 0, GFP_KERNEL);
103 if (ret >= 0)
104 file_priv->magic = ret;
105 }
106 auth->magic = file_priv->magic;
107 mutex_unlock(&dev->master_mutex);
108
109 DRM_DEBUG("%u\n", auth->magic);
110
111 return ret < 0 ? ret : 0;
112}
113
114int drm_authmagic(struct drm_device *dev, void *data,
115 struct drm_file *file_priv)
116{
117 struct drm_auth *auth = data;
118 struct drm_file *file;
119
120 DRM_DEBUG("%u\n", auth->magic);
121
122 mutex_lock(&dev->master_mutex);
123 file = idr_find(&file_priv->master->magic_map, auth->magic);
124 if (file) {
125 file->authenticated = 1;
126 idr_replace(&file_priv->master->magic_map, NULL, auth->magic);
127 }
128 mutex_unlock(&dev->master_mutex);
129
130 return file ? 0 : -EINVAL;
131}
132
133struct drm_master *drm_master_create(struct drm_device *dev)
134{
135 struct drm_master *master;
136
137 master = kzalloc(sizeof(*master), GFP_KERNEL);
138 if (!master)
139 return NULL;
140
141 kref_init(&master->refcount);
142 drm_master_legacy_init(master);
143 idr_init(&master->magic_map);
144 master->dev = dev;
145
146
147 INIT_LIST_HEAD(&master->lessees);
148 INIT_LIST_HEAD(&master->lessee_list);
149 idr_init(&master->leases);
150 idr_init(&master->lessee_idr);
151
152 return master;
153}
154
155static void drm_set_master(struct drm_device *dev, struct drm_file *fpriv,
156 bool new_master)
157{
158 dev->master = drm_master_get(fpriv->master);
159 if (dev->driver->master_set)
160 dev->driver->master_set(dev, fpriv, new_master);
161
162 fpriv->was_master = true;
163}
164
165static int drm_new_set_master(struct drm_device *dev, struct drm_file *fpriv)
166{
167 struct drm_master *old_master;
168 struct drm_master *new_master;
169
170 lockdep_assert_held_once(&dev->master_mutex);
171
172 WARN_ON(fpriv->is_master);
173 old_master = fpriv->master;
174 new_master = drm_master_create(dev);
175 if (!new_master)
176 return -ENOMEM;
177 spin_lock(&fpriv->master_lookup_lock);
178 fpriv->master = new_master;
179 spin_unlock(&fpriv->master_lookup_lock);
180
181 fpriv->is_master = 1;
182 fpriv->authenticated = 1;
183
184 drm_set_master(dev, fpriv, true);
185
186 if (old_master)
187 drm_master_put(&old_master);
188
189 return 0;
190}
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235static int
236drm_master_check_perm(struct drm_device *dev, struct drm_file *file_priv)
237{
238 if (file_priv->pid == task_pid(current) && file_priv->was_master)
239 return 0;
240
241 if (!capable(CAP_SYS_ADMIN))
242 return -EACCES;
243
244 return 0;
245}
246
247int drm_setmaster_ioctl(struct drm_device *dev, void *data,
248 struct drm_file *file_priv)
249{
250 int ret;
251
252 mutex_lock(&dev->master_mutex);
253
254 ret = drm_master_check_perm(dev, file_priv);
255 if (ret)
256 goto out_unlock;
257
258 if (drm_is_current_master_locked(file_priv))
259 goto out_unlock;
260
261 if (dev->master) {
262 ret = -EBUSY;
263 goto out_unlock;
264 }
265
266 if (!file_priv->master) {
267 ret = -EINVAL;
268 goto out_unlock;
269 }
270
271 if (!file_priv->is_master) {
272 ret = drm_new_set_master(dev, file_priv);
273 goto out_unlock;
274 }
275
276 if (file_priv->master->lessor != NULL) {
277 DRM_DEBUG_LEASE("Attempt to set lessee %d as master\n", file_priv->master->lessee_id);
278 ret = -EINVAL;
279 goto out_unlock;
280 }
281
282 drm_set_master(dev, file_priv, false);
283out_unlock:
284 mutex_unlock(&dev->master_mutex);
285 return ret;
286}
287
288static void drm_drop_master(struct drm_device *dev,
289 struct drm_file *fpriv)
290{
291 if (dev->driver->master_drop)
292 dev->driver->master_drop(dev, fpriv);
293 drm_master_put(&dev->master);
294}
295
296int drm_dropmaster_ioctl(struct drm_device *dev, void *data,
297 struct drm_file *file_priv)
298{
299 int ret;
300
301 mutex_lock(&dev->master_mutex);
302
303 ret = drm_master_check_perm(dev, file_priv);
304 if (ret)
305 goto out_unlock;
306
307 if (!drm_is_current_master_locked(file_priv)) {
308 ret = -EINVAL;
309 goto out_unlock;
310 }
311
312 if (!dev->master) {
313 ret = -EINVAL;
314 goto out_unlock;
315 }
316
317 if (file_priv->master->lessor != NULL) {
318 DRM_DEBUG_LEASE("Attempt to drop lessee %d as master\n", file_priv->master->lessee_id);
319 ret = -EINVAL;
320 goto out_unlock;
321 }
322
323 drm_drop_master(dev, file_priv);
324out_unlock:
325 mutex_unlock(&dev->master_mutex);
326 return ret;
327}
328
329int drm_master_open(struct drm_file *file_priv)
330{
331 struct drm_device *dev = file_priv->minor->dev;
332 int ret = 0;
333
334
335
336
337 mutex_lock(&dev->master_mutex);
338 if (!dev->master) {
339 ret = drm_new_set_master(dev, file_priv);
340 } else {
341 spin_lock(&file_priv->master_lookup_lock);
342 file_priv->master = drm_master_get(dev->master);
343 spin_unlock(&file_priv->master_lookup_lock);
344 }
345 mutex_unlock(&dev->master_mutex);
346
347 return ret;
348}
349
350void drm_master_release(struct drm_file *file_priv)
351{
352 struct drm_device *dev = file_priv->minor->dev;
353 struct drm_master *master;
354
355 mutex_lock(&dev->master_mutex);
356 master = file_priv->master;
357 if (file_priv->magic)
358 idr_remove(&file_priv->master->magic_map, file_priv->magic);
359
360 if (!drm_is_current_master_locked(file_priv))
361 goto out;
362
363 drm_legacy_lock_master_cleanup(dev, master);
364
365 if (dev->master == file_priv->master)
366 drm_drop_master(dev, file_priv);
367out:
368 if (drm_core_check_feature(dev, DRIVER_MODESET) && file_priv->is_master) {
369
370
371
372 drm_lease_revoke(master);
373 }
374
375
376 if (file_priv->master)
377 drm_master_put(&file_priv->master);
378 mutex_unlock(&dev->master_mutex);
379}
380
381
382
383
384
385
386
387struct drm_master *drm_master_get(struct drm_master *master)
388{
389 kref_get(&master->refcount);
390 return master;
391}
392EXPORT_SYMBOL(drm_master_get);
393
394
395
396
397
398
399
400
401
402
403
404struct drm_master *drm_file_get_master(struct drm_file *file_priv)
405{
406 struct drm_master *master = NULL;
407
408 spin_lock(&file_priv->master_lookup_lock);
409 if (!file_priv->master)
410 goto unlock;
411 master = drm_master_get(file_priv->master);
412
413unlock:
414 spin_unlock(&file_priv->master_lookup_lock);
415 return master;
416}
417EXPORT_SYMBOL(drm_file_get_master);
418
419static void drm_master_destroy(struct kref *kref)
420{
421 struct drm_master *master = container_of(kref, struct drm_master, refcount);
422 struct drm_device *dev = master->dev;
423
424 if (drm_core_check_feature(dev, DRIVER_MODESET))
425 drm_lease_destroy(master);
426
427 drm_legacy_master_rmmaps(dev, master);
428
429 idr_destroy(&master->magic_map);
430 idr_destroy(&master->leases);
431 idr_destroy(&master->lessee_idr);
432
433 kfree(master->unique);
434 kfree(master);
435}
436
437
438
439
440
441
442
443void drm_master_put(struct drm_master **master)
444{
445 kref_put(&(*master)->refcount, drm_master_destroy);
446 *master = NULL;
447}
448EXPORT_SYMBOL(drm_master_put);
449
450
451bool drm_master_internal_acquire(struct drm_device *dev)
452{
453 mutex_lock(&dev->master_mutex);
454 if (dev->master) {
455 mutex_unlock(&dev->master_mutex);
456 return false;
457 }
458
459 return true;
460}
461EXPORT_SYMBOL(drm_master_internal_acquire);
462
463
464void drm_master_internal_release(struct drm_device *dev)
465{
466 mutex_unlock(&dev->master_mutex);
467}
468EXPORT_SYMBOL(drm_master_internal_release);
469