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_dbg_core(dev, "%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_dbg_core(dev, "%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_dbg_lease(dev,
278 "Attempt to set lessee %d as master\n",
279 file_priv->master->lessee_id);
280 ret = -EINVAL;
281 goto out_unlock;
282 }
283
284 drm_set_master(dev, file_priv, false);
285out_unlock:
286 mutex_unlock(&dev->master_mutex);
287 return ret;
288}
289
290static void drm_drop_master(struct drm_device *dev,
291 struct drm_file *fpriv)
292{
293 if (dev->driver->master_drop)
294 dev->driver->master_drop(dev, fpriv);
295 drm_master_put(&dev->master);
296}
297
298int drm_dropmaster_ioctl(struct drm_device *dev, void *data,
299 struct drm_file *file_priv)
300{
301 int ret;
302
303 mutex_lock(&dev->master_mutex);
304
305 ret = drm_master_check_perm(dev, file_priv);
306 if (ret)
307 goto out_unlock;
308
309 if (!drm_is_current_master_locked(file_priv)) {
310 ret = -EINVAL;
311 goto out_unlock;
312 }
313
314 if (!dev->master) {
315 ret = -EINVAL;
316 goto out_unlock;
317 }
318
319 if (file_priv->master->lessor != NULL) {
320 drm_dbg_lease(dev,
321 "Attempt to drop lessee %d as master\n",
322 file_priv->master->lessee_id);
323 ret = -EINVAL;
324 goto out_unlock;
325 }
326
327 drm_drop_master(dev, file_priv);
328out_unlock:
329 mutex_unlock(&dev->master_mutex);
330 return ret;
331}
332
333int drm_master_open(struct drm_file *file_priv)
334{
335 struct drm_device *dev = file_priv->minor->dev;
336 int ret = 0;
337
338
339
340
341 mutex_lock(&dev->master_mutex);
342 if (!dev->master) {
343 ret = drm_new_set_master(dev, file_priv);
344 } else {
345 spin_lock(&file_priv->master_lookup_lock);
346 file_priv->master = drm_master_get(dev->master);
347 spin_unlock(&file_priv->master_lookup_lock);
348 }
349 mutex_unlock(&dev->master_mutex);
350
351 return ret;
352}
353
354void drm_master_release(struct drm_file *file_priv)
355{
356 struct drm_device *dev = file_priv->minor->dev;
357 struct drm_master *master;
358
359 mutex_lock(&dev->master_mutex);
360 master = file_priv->master;
361 if (file_priv->magic)
362 idr_remove(&file_priv->master->magic_map, file_priv->magic);
363
364 if (!drm_is_current_master_locked(file_priv))
365 goto out;
366
367 drm_legacy_lock_master_cleanup(dev, master);
368
369 if (dev->master == file_priv->master)
370 drm_drop_master(dev, file_priv);
371out:
372 if (drm_core_check_feature(dev, DRIVER_MODESET) && file_priv->is_master) {
373
374
375
376 drm_lease_revoke(master);
377 }
378
379
380 if (file_priv->master)
381 drm_master_put(&file_priv->master);
382 mutex_unlock(&dev->master_mutex);
383}
384
385
386
387
388
389
390
391struct drm_master *drm_master_get(struct drm_master *master)
392{
393 kref_get(&master->refcount);
394 return master;
395}
396EXPORT_SYMBOL(drm_master_get);
397
398
399
400
401
402
403
404
405
406
407
408struct drm_master *drm_file_get_master(struct drm_file *file_priv)
409{
410 struct drm_master *master = NULL;
411
412 spin_lock(&file_priv->master_lookup_lock);
413 if (!file_priv->master)
414 goto unlock;
415 master = drm_master_get(file_priv->master);
416
417unlock:
418 spin_unlock(&file_priv->master_lookup_lock);
419 return master;
420}
421EXPORT_SYMBOL(drm_file_get_master);
422
423static void drm_master_destroy(struct kref *kref)
424{
425 struct drm_master *master = container_of(kref, struct drm_master, refcount);
426 struct drm_device *dev = master->dev;
427
428 if (drm_core_check_feature(dev, DRIVER_MODESET))
429 drm_lease_destroy(master);
430
431 drm_legacy_master_rmmaps(dev, master);
432
433 idr_destroy(&master->magic_map);
434 idr_destroy(&master->leases);
435 idr_destroy(&master->lessee_idr);
436
437 kfree(master->unique);
438 kfree(master);
439}
440
441
442
443
444
445
446
447void drm_master_put(struct drm_master **master)
448{
449 kref_put(&(*master)->refcount, drm_master_destroy);
450 *master = NULL;
451}
452EXPORT_SYMBOL(drm_master_put);
453
454
455bool drm_master_internal_acquire(struct drm_device *dev)
456{
457 mutex_lock(&dev->master_mutex);
458 if (dev->master) {
459 mutex_unlock(&dev->master_mutex);
460 return false;
461 }
462
463 return true;
464}
465EXPORT_SYMBOL(drm_master_internal_acquire);
466
467
468void drm_master_internal_release(struct drm_device *dev)
469{
470 mutex_unlock(&dev->master_mutex);
471}
472EXPORT_SYMBOL(drm_master_internal_release);
473