drm_lease.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753
  1. /*
  2. * Copyright © 2017 Keith Packard <keithp@keithp.com>
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful, but
  10. * WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * General Public License for more details.
  13. */
  14. #include <drm/drmP.h>
  15. #include "drm_internal.h"
  16. #include "drm_legacy.h"
  17. #include "drm_crtc_internal.h"
  18. #include <drm/drm_lease.h>
  19. #include <drm/drm_auth.h>
  20. #include <drm/drm_crtc_helper.h>
  21. #define drm_for_each_lessee(lessee, lessor) \
  22. list_for_each_entry((lessee), &(lessor)->lessees, lessee_list)
  23. static uint64_t drm_lease_idr_object;
  24. /**
  25. * drm_lease_owner - return ancestor owner drm_master
  26. * @master: drm_master somewhere within tree of lessees and lessors
  27. *
  28. * RETURN:
  29. *
  30. * drm_master at the top of the tree (i.e, with lessor NULL
  31. */
  32. struct drm_master *drm_lease_owner(struct drm_master *master)
  33. {
  34. while (master->lessor != NULL)
  35. master = master->lessor;
  36. return master;
  37. }
  38. EXPORT_SYMBOL(drm_lease_owner);
  39. /**
  40. * _drm_find_lessee - find lessee by id (idr_mutex held)
  41. * @master: drm_master of lessor
  42. * @lessee_id: id
  43. *
  44. * RETURN:
  45. *
  46. * drm_master of the lessee if valid, NULL otherwise
  47. */
  48. static struct drm_master*
  49. _drm_find_lessee(struct drm_master *master, int lessee_id)
  50. {
  51. lockdep_assert_held(&master->dev->mode_config.idr_mutex);
  52. return idr_find(&drm_lease_owner(master)->lessee_idr, lessee_id);
  53. }
  54. /**
  55. * _drm_lease_held_master - check to see if an object is leased (or owned) by master (idr_mutex held)
  56. * @master: the master to check the lease status of
  57. * @id: the id to check
  58. *
  59. * Checks if the specified master holds a lease on the object. Return
  60. * value:
  61. *
  62. * true 'master' holds a lease on (or owns) the object
  63. * false 'master' does not hold a lease.
  64. */
  65. static int _drm_lease_held_master(struct drm_master *master, int id)
  66. {
  67. lockdep_assert_held(&master->dev->mode_config.idr_mutex);
  68. if (master->lessor)
  69. return idr_find(&master->leases, id) != NULL;
  70. return true;
  71. }
  72. /**
  73. * _drm_has_leased - check to see if an object has been leased (idr_mutex held)
  74. * @master: the master to check the lease status of
  75. * @id: the id to check
  76. *
  77. * Checks if any lessee of 'master' holds a lease on 'id'. Return
  78. * value:
  79. *
  80. * true Some lessee holds a lease on the object.
  81. * false No lessee has a lease on the object.
  82. */
  83. static bool _drm_has_leased(struct drm_master *master, int id)
  84. {
  85. struct drm_master *lessee;
  86. lockdep_assert_held(&master->dev->mode_config.idr_mutex);
  87. drm_for_each_lessee(lessee, master)
  88. if (_drm_lease_held_master(lessee, id))
  89. return true;
  90. return false;
  91. }
  92. /**
  93. * _drm_lease_held - check drm_mode_object lease status (idr_mutex held)
  94. * @file_priv: the master drm_file
  95. * @id: the object id
  96. *
  97. * Checks if the specified master holds a lease on the object. Return
  98. * value:
  99. *
  100. * true 'master' holds a lease on (or owns) the object
  101. * false 'master' does not hold a lease.
  102. */
  103. bool _drm_lease_held(struct drm_file *file_priv, int id)
  104. {
  105. if (file_priv == NULL || file_priv->master == NULL)
  106. return true;
  107. return _drm_lease_held_master(file_priv->master, id);
  108. }
  109. EXPORT_SYMBOL(_drm_lease_held);
  110. /**
  111. * drm_lease_held - check drm_mode_object lease status (idr_mutex not held)
  112. * @file_priv: the master drm_file
  113. * @id: the object id
  114. *
  115. * Checks if the specified master holds a lease on the object. Return
  116. * value:
  117. *
  118. * true 'master' holds a lease on (or owns) the object
  119. * false 'master' does not hold a lease.
  120. */
  121. bool drm_lease_held(struct drm_file *file_priv, int id)
  122. {
  123. struct drm_master *master;
  124. bool ret;
  125. if (file_priv == NULL || file_priv->master == NULL)
  126. return true;
  127. master = file_priv->master;
  128. mutex_lock(&master->dev->mode_config.idr_mutex);
  129. ret = _drm_lease_held_master(master, id);
  130. mutex_unlock(&master->dev->mode_config.idr_mutex);
  131. return ret;
  132. }
  133. EXPORT_SYMBOL(drm_lease_held);
  134. /**
  135. * drm_lease_filter_crtcs - restricted crtc set to leased values (idr_mutex not held)
  136. * @file_priv: requestor file
  137. * @crtcs_in: bitmask of crtcs to check
  138. *
  139. * Reconstructs a crtc mask based on the crtcs which are visible
  140. * through the specified file.
  141. */
  142. uint32_t drm_lease_filter_crtcs(struct drm_file *file_priv, uint32_t crtcs_in)
  143. {
  144. struct drm_master *master;
  145. struct drm_device *dev;
  146. struct drm_crtc *crtc;
  147. int count_in, count_out;
  148. uint32_t crtcs_out = 0;
  149. if (file_priv == NULL || file_priv->master == NULL)
  150. return crtcs_in;
  151. master = file_priv->master;
  152. dev = master->dev;
  153. count_in = count_out = 0;
  154. mutex_lock(&master->dev->mode_config.idr_mutex);
  155. list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
  156. if (_drm_lease_held_master(master, crtc->base.id)) {
  157. uint32_t mask_in = 1ul << count_in;
  158. if ((crtcs_in & mask_in) != 0) {
  159. uint32_t mask_out = 1ul << count_out;
  160. crtcs_out |= mask_out;
  161. }
  162. count_out++;
  163. }
  164. count_in++;
  165. }
  166. mutex_unlock(&master->dev->mode_config.idr_mutex);
  167. return crtcs_out;
  168. }
  169. EXPORT_SYMBOL(drm_lease_filter_crtcs);
  170. /*
  171. * drm_lease_create - create a new drm_master with leased objects (idr_mutex not held)
  172. * @lessor: lease holder (or owner) of objects
  173. * @leases: objects to lease to the new drm_master
  174. *
  175. * Uses drm_master_create to allocate a new drm_master, then checks to
  176. * make sure all of the desired objects can be leased, atomically
  177. * leasing them to the new drmmaster.
  178. *
  179. * ERR_PTR(-EACCESS) some other master holds the title to any object
  180. * ERR_PTR(-ENOENT) some object is not a valid DRM object for this device
  181. * ERR_PTR(-EBUSY) some other lessee holds title to this object
  182. * ERR_PTR(-EEXIST) same object specified more than once in the provided list
  183. * ERR_PTR(-ENOMEM) allocation failed
  184. */
  185. static struct drm_master *drm_lease_create(struct drm_master *lessor, struct idr *leases)
  186. {
  187. struct drm_device *dev = lessor->dev;
  188. int error;
  189. struct drm_master *lessee;
  190. int object;
  191. int id;
  192. void *entry;
  193. DRM_DEBUG_LEASE("lessor %d\n", lessor->lessee_id);
  194. lessee = drm_master_create(lessor->dev);
  195. if (!lessee) {
  196. DRM_DEBUG_LEASE("drm_master_create failed\n");
  197. return ERR_PTR(-ENOMEM);
  198. }
  199. mutex_lock(&dev->mode_config.idr_mutex);
  200. idr_for_each_entry(leases, entry, object) {
  201. error = 0;
  202. if (!idr_find(&dev->mode_config.crtc_idr, object))
  203. error = -ENOENT;
  204. else if (!_drm_lease_held_master(lessor, object))
  205. error = -EACCES;
  206. else if (_drm_has_leased(lessor, object))
  207. error = -EBUSY;
  208. if (error != 0) {
  209. DRM_DEBUG_LEASE("object %d failed %d\n", object, error);
  210. goto out_lessee;
  211. }
  212. }
  213. /* Insert the new lessee into the tree */
  214. id = idr_alloc(&(drm_lease_owner(lessor)->lessee_idr), lessee, 1, 0, GFP_KERNEL);
  215. if (id < 0) {
  216. error = id;
  217. goto out_lessee;
  218. }
  219. lessee->lessee_id = id;
  220. lessee->lessor = drm_master_get(lessor);
  221. list_add_tail(&lessee->lessee_list, &lessor->lessees);
  222. /* Move the leases over */
  223. lessee->leases = *leases;
  224. DRM_DEBUG_LEASE("new lessee %d %p, lessor %d %p\n", lessee->lessee_id, lessee, lessor->lessee_id, lessor);
  225. mutex_unlock(&dev->mode_config.idr_mutex);
  226. return lessee;
  227. out_lessee:
  228. mutex_unlock(&dev->mode_config.idr_mutex);
  229. drm_master_put(&lessee);
  230. return ERR_PTR(error);
  231. }
  232. /**
  233. * drm_lease_destroy - a master is going away (idr_mutex not held)
  234. * @master: the drm_master being destroyed
  235. *
  236. * All lessees will have been destroyed as they
  237. * hold a reference on their lessor. Notify any
  238. * lessor for this master so that it can check
  239. * the list of lessees.
  240. */
  241. void drm_lease_destroy(struct drm_master *master)
  242. {
  243. struct drm_device *dev = master->dev;
  244. mutex_lock(&dev->mode_config.idr_mutex);
  245. DRM_DEBUG_LEASE("drm_lease_destroy %d\n", master->lessee_id);
  246. /* This master is referenced by all lessees, hence it cannot be destroyed
  247. * until all of them have been
  248. */
  249. WARN_ON(!list_empty(&master->lessees));
  250. /* Remove this master from the lessee idr in the owner */
  251. if (master->lessee_id != 0) {
  252. DRM_DEBUG_LEASE("remove master %d from device list of lessees\n", master->lessee_id);
  253. idr_remove(&(drm_lease_owner(master)->lessee_idr), master->lessee_id);
  254. }
  255. /* Remove this master from any lessee list it may be on */
  256. list_del(&master->lessee_list);
  257. mutex_unlock(&dev->mode_config.idr_mutex);
  258. if (master->lessor) {
  259. /* Tell the master to check the lessee list */
  260. drm_sysfs_lease_event(dev);
  261. drm_master_put(&master->lessor);
  262. }
  263. DRM_DEBUG_LEASE("drm_lease_destroy done %d\n", master->lessee_id);
  264. }
  265. /**
  266. * _drm_lease_revoke - revoke access to all leased objects (idr_mutex held)
  267. * @top: the master losing its lease
  268. */
  269. static void _drm_lease_revoke(struct drm_master *top)
  270. {
  271. int object;
  272. void *entry;
  273. struct drm_master *master = top;
  274. lockdep_assert_held(&top->dev->mode_config.idr_mutex);
  275. /*
  276. * Walk the tree starting at 'top' emptying all leases. Because
  277. * the tree is fully connected, we can do this without recursing
  278. */
  279. for (;;) {
  280. DRM_DEBUG_LEASE("revoke leases for %p %d\n", master, master->lessee_id);
  281. /* Evacuate the lease */
  282. idr_for_each_entry(&master->leases, entry, object)
  283. idr_remove(&master->leases, object);
  284. /* Depth-first list walk */
  285. /* Down */
  286. if (!list_empty(&master->lessees)) {
  287. master = list_first_entry(&master->lessees, struct drm_master, lessee_list);
  288. } else {
  289. /* Up */
  290. while (master != top && master == list_last_entry(&master->lessor->lessees, struct drm_master, lessee_list))
  291. master = master->lessor;
  292. if (master == top)
  293. break;
  294. /* Over */
  295. master = list_next_entry(master, lessee_list);
  296. }
  297. }
  298. }
  299. /**
  300. * drm_lease_revoke - revoke access to all leased objects (idr_mutex not held)
  301. * @top: the master losing its lease
  302. */
  303. void drm_lease_revoke(struct drm_master *top)
  304. {
  305. mutex_lock(&top->dev->mode_config.idr_mutex);
  306. _drm_lease_revoke(top);
  307. mutex_unlock(&top->dev->mode_config.idr_mutex);
  308. }
  309. static int validate_lease(struct drm_device *dev,
  310. struct drm_file *lessor_priv,
  311. int object_count,
  312. struct drm_mode_object **objects)
  313. {
  314. int o;
  315. int has_crtc = -1;
  316. int has_connector = -1;
  317. int has_plane = -1;
  318. /* we want to confirm that there is at least one crtc, plane
  319. connector object. */
  320. for (o = 0; o < object_count; o++) {
  321. if (objects[o]->type == DRM_MODE_OBJECT_CRTC && has_crtc == -1) {
  322. has_crtc = o;
  323. }
  324. if (objects[o]->type == DRM_MODE_OBJECT_CONNECTOR && has_connector == -1)
  325. has_connector = o;
  326. if (lessor_priv->universal_planes) {
  327. if (objects[o]->type == DRM_MODE_OBJECT_PLANE && has_plane == -1)
  328. has_plane = o;
  329. }
  330. }
  331. if (has_crtc == -1 || has_connector == -1)
  332. return -EINVAL;
  333. if (lessor_priv->universal_planes && has_plane == -1)
  334. return -EINVAL;
  335. return 0;
  336. }
  337. static int fill_object_idr(struct drm_device *dev,
  338. struct drm_file *lessor_priv,
  339. struct idr *leases,
  340. int object_count,
  341. u32 *object_ids)
  342. {
  343. struct drm_mode_object **objects;
  344. u32 o;
  345. int ret;
  346. objects = kcalloc(object_count, sizeof(struct drm_mode_object *),
  347. GFP_KERNEL);
  348. if (!objects)
  349. return -ENOMEM;
  350. /* step one - get references to all the mode objects
  351. and check for validity. */
  352. for (o = 0; o < object_count; o++) {
  353. if ((int) object_ids[o] < 0) {
  354. ret = -EINVAL;
  355. goto out_free_objects;
  356. }
  357. objects[o] = drm_mode_object_find(dev, lessor_priv,
  358. object_ids[o],
  359. DRM_MODE_OBJECT_ANY);
  360. if (!objects[o]) {
  361. ret = -ENOENT;
  362. goto out_free_objects;
  363. }
  364. if (!drm_mode_object_lease_required(objects[o]->type)) {
  365. ret = -EINVAL;
  366. goto out_free_objects;
  367. }
  368. }
  369. ret = validate_lease(dev, lessor_priv, object_count, objects);
  370. if (ret)
  371. goto out_free_objects;
  372. /* add their IDs to the lease request - taking into account
  373. universal planes */
  374. for (o = 0; o < object_count; o++) {
  375. struct drm_mode_object *obj = objects[o];
  376. u32 object_id = objects[o]->id;
  377. DRM_DEBUG_LEASE("Adding object %d to lease\n", object_id);
  378. /*
  379. * We're using an IDR to hold the set of leased
  380. * objects, but we don't need to point at the object's
  381. * data structure from the lease as the main crtc_idr
  382. * will be used to actually find that. Instead, all we
  383. * really want is a 'leased/not-leased' result, for
  384. * which any non-NULL pointer will work fine.
  385. */
  386. ret = idr_alloc(leases, &drm_lease_idr_object , object_id, object_id + 1, GFP_KERNEL);
  387. if (ret < 0) {
  388. DRM_DEBUG_LEASE("Object %d cannot be inserted into leases (%d)\n",
  389. object_id, ret);
  390. goto out_free_objects;
  391. }
  392. if (obj->type == DRM_MODE_OBJECT_CRTC && !lessor_priv->universal_planes) {
  393. struct drm_crtc *crtc = obj_to_crtc(obj);
  394. ret = idr_alloc(leases, &drm_lease_idr_object, crtc->primary->base.id, crtc->primary->base.id + 1, GFP_KERNEL);
  395. if (ret < 0) {
  396. DRM_DEBUG_LEASE("Object primary plane %d cannot be inserted into leases (%d)\n",
  397. object_id, ret);
  398. goto out_free_objects;
  399. }
  400. if (crtc->cursor) {
  401. ret = idr_alloc(leases, &drm_lease_idr_object, crtc->cursor->base.id, crtc->cursor->base.id + 1, GFP_KERNEL);
  402. if (ret < 0) {
  403. DRM_DEBUG_LEASE("Object cursor plane %d cannot be inserted into leases (%d)\n",
  404. object_id, ret);
  405. goto out_free_objects;
  406. }
  407. }
  408. }
  409. }
  410. ret = 0;
  411. out_free_objects:
  412. for (o = 0; o < object_count; o++) {
  413. if (objects[o])
  414. drm_mode_object_put(objects[o]);
  415. }
  416. kfree(objects);
  417. return ret;
  418. }
  419. /**
  420. * drm_mode_create_lease_ioctl - create a new lease
  421. * @dev: the drm device
  422. * @data: pointer to struct drm_mode_create_lease
  423. * @lessor_priv: the file being manipulated
  424. *
  425. * The master associated with the specified file will have a lease
  426. * created containing the objects specified in the ioctl structure.
  427. * A file descriptor will be allocated for that and returned to the
  428. * application.
  429. */
  430. int drm_mode_create_lease_ioctl(struct drm_device *dev,
  431. void *data, struct drm_file *lessor_priv)
  432. {
  433. struct drm_mode_create_lease *cl = data;
  434. size_t object_count;
  435. int ret = 0;
  436. struct idr leases;
  437. struct drm_master *lessor = lessor_priv->master;
  438. struct drm_master *lessee = NULL;
  439. struct file *lessee_file = NULL;
  440. struct file *lessor_file = lessor_priv->filp;
  441. struct drm_file *lessee_priv;
  442. int fd = -1;
  443. uint32_t *object_ids;
  444. /* Can't lease without MODESET */
  445. if (!drm_core_check_feature(dev, DRIVER_MODESET))
  446. return -EOPNOTSUPP;
  447. /* Do not allow sub-leases */
  448. if (lessor->lessor)
  449. return -EINVAL;
  450. /* need some objects */
  451. if (cl->object_count == 0)
  452. return -EINVAL;
  453. if (cl->flags && (cl->flags & ~(O_CLOEXEC | O_NONBLOCK)))
  454. return -EINVAL;
  455. object_count = cl->object_count;
  456. object_ids = memdup_user(u64_to_user_ptr(cl->object_ids), object_count * sizeof(__u32));
  457. if (IS_ERR(object_ids))
  458. return PTR_ERR(object_ids);
  459. idr_init(&leases);
  460. /* fill and validate the object idr */
  461. ret = fill_object_idr(dev, lessor_priv, &leases,
  462. object_count, object_ids);
  463. kfree(object_ids);
  464. if (ret) {
  465. idr_destroy(&leases);
  466. return ret;
  467. }
  468. /* Allocate a file descriptor for the lease */
  469. fd = get_unused_fd_flags(cl->flags & (O_CLOEXEC | O_NONBLOCK));
  470. if (fd < 0) {
  471. idr_destroy(&leases);
  472. return fd;
  473. }
  474. DRM_DEBUG_LEASE("Creating lease\n");
  475. lessee = drm_lease_create(lessor, &leases);
  476. if (IS_ERR(lessee)) {
  477. ret = PTR_ERR(lessee);
  478. goto out_leases;
  479. }
  480. /* Clone the lessor file to create a new file for us */
  481. DRM_DEBUG_LEASE("Allocating lease file\n");
  482. lessee_file = file_clone_open(lessor_file);
  483. if (IS_ERR(lessee_file)) {
  484. ret = PTR_ERR(lessee_file);
  485. goto out_lessee;
  486. }
  487. lessee_priv = lessee_file->private_data;
  488. /* Change the file to a master one */
  489. drm_master_put(&lessee_priv->master);
  490. lessee_priv->master = lessee;
  491. lessee_priv->is_master = 1;
  492. lessee_priv->authenticated = 1;
  493. /* Pass fd back to userspace */
  494. DRM_DEBUG_LEASE("Returning fd %d id %d\n", fd, lessee->lessee_id);
  495. cl->fd = fd;
  496. cl->lessee_id = lessee->lessee_id;
  497. /* Hook up the fd */
  498. fd_install(fd, lessee_file);
  499. DRM_DEBUG_LEASE("drm_mode_create_lease_ioctl succeeded\n");
  500. return 0;
  501. out_lessee:
  502. drm_master_put(&lessee);
  503. out_leases:
  504. put_unused_fd(fd);
  505. idr_destroy(&leases);
  506. DRM_DEBUG_LEASE("drm_mode_create_lease_ioctl failed: %d\n", ret);
  507. return ret;
  508. }
  509. /**
  510. * drm_mode_list_lessees_ioctl - list lessee ids
  511. * @dev: the drm device
  512. * @data: pointer to struct drm_mode_list_lessees
  513. * @lessor_priv: the file being manipulated
  514. *
  515. * Starting from the master associated with the specified file,
  516. * the master with the provided lessee_id is found, and then
  517. * an array of lessee ids associated with leases from that master
  518. * are returned.
  519. */
  520. int drm_mode_list_lessees_ioctl(struct drm_device *dev,
  521. void *data, struct drm_file *lessor_priv)
  522. {
  523. struct drm_mode_list_lessees *arg = data;
  524. __u32 __user *lessee_ids = (__u32 __user *) (uintptr_t) (arg->lessees_ptr);
  525. __u32 count_lessees = arg->count_lessees;
  526. struct drm_master *lessor = lessor_priv->master, *lessee;
  527. int count;
  528. int ret = 0;
  529. if (arg->pad)
  530. return -EINVAL;
  531. /* Can't lease without MODESET */
  532. if (!drm_core_check_feature(dev, DRIVER_MODESET))
  533. return -EOPNOTSUPP;
  534. DRM_DEBUG_LEASE("List lessees for %d\n", lessor->lessee_id);
  535. mutex_lock(&dev->mode_config.idr_mutex);
  536. count = 0;
  537. drm_for_each_lessee(lessee, lessor) {
  538. /* Only list un-revoked leases */
  539. if (!idr_is_empty(&lessee->leases)) {
  540. if (count_lessees > count) {
  541. DRM_DEBUG_LEASE("Add lessee %d\n", lessee->lessee_id);
  542. ret = put_user(lessee->lessee_id, lessee_ids + count);
  543. if (ret)
  544. break;
  545. }
  546. count++;
  547. }
  548. }
  549. DRM_DEBUG_LEASE("Lessor leases to %d\n", count);
  550. if (ret == 0)
  551. arg->count_lessees = count;
  552. mutex_unlock(&dev->mode_config.idr_mutex);
  553. return ret;
  554. }
  555. /**
  556. * drm_mode_get_lease_ioctl - list leased objects
  557. * @dev: the drm device
  558. * @data: pointer to struct drm_mode_get_lease
  559. * @lessee_priv: the file being manipulated
  560. *
  561. * Return the list of leased objects for the specified lessee
  562. */
  563. int drm_mode_get_lease_ioctl(struct drm_device *dev,
  564. void *data, struct drm_file *lessee_priv)
  565. {
  566. struct drm_mode_get_lease *arg = data;
  567. __u32 __user *object_ids = (__u32 __user *) (uintptr_t) (arg->objects_ptr);
  568. __u32 count_objects = arg->count_objects;
  569. struct drm_master *lessee = lessee_priv->master;
  570. struct idr *object_idr;
  571. int count;
  572. void *entry;
  573. int object;
  574. int ret = 0;
  575. if (arg->pad)
  576. return -EINVAL;
  577. /* Can't lease without MODESET */
  578. if (!drm_core_check_feature(dev, DRIVER_MODESET))
  579. return -EOPNOTSUPP;
  580. DRM_DEBUG_LEASE("get lease for %d\n", lessee->lessee_id);
  581. mutex_lock(&dev->mode_config.idr_mutex);
  582. if (lessee->lessor == NULL)
  583. /* owner can use all objects */
  584. object_idr = &lessee->dev->mode_config.crtc_idr;
  585. else
  586. /* lessee can only use allowed object */
  587. object_idr = &lessee->leases;
  588. count = 0;
  589. idr_for_each_entry(object_idr, entry, object) {
  590. if (count_objects > count) {
  591. DRM_DEBUG_LEASE("adding object %d\n", object);
  592. ret = put_user(object, object_ids + count);
  593. if (ret)
  594. break;
  595. }
  596. count++;
  597. }
  598. DRM_DEBUG("lease holds %d objects\n", count);
  599. if (ret == 0)
  600. arg->count_objects = count;
  601. mutex_unlock(&dev->mode_config.idr_mutex);
  602. return ret;
  603. }
  604. /**
  605. * drm_mode_revoke_lease_ioctl - revoke lease
  606. * @dev: the drm device
  607. * @data: pointer to struct drm_mode_revoke_lease
  608. * @lessor_priv: the file being manipulated
  609. *
  610. * This removes all of the objects from the lease without
  611. * actually getting rid of the lease itself; that way all
  612. * references to it still work correctly
  613. */
  614. int drm_mode_revoke_lease_ioctl(struct drm_device *dev,
  615. void *data, struct drm_file *lessor_priv)
  616. {
  617. struct drm_mode_revoke_lease *arg = data;
  618. struct drm_master *lessor = lessor_priv->master;
  619. struct drm_master *lessee;
  620. int ret = 0;
  621. DRM_DEBUG_LEASE("revoke lease for %d\n", arg->lessee_id);
  622. /* Can't lease without MODESET */
  623. if (!drm_core_check_feature(dev, DRIVER_MODESET))
  624. return -EOPNOTSUPP;
  625. mutex_lock(&dev->mode_config.idr_mutex);
  626. lessee = _drm_find_lessee(lessor, arg->lessee_id);
  627. /* No such lessee */
  628. if (!lessee) {
  629. ret = -ENOENT;
  630. goto fail;
  631. }
  632. /* Lease is not held by lessor */
  633. if (lessee->lessor != lessor) {
  634. ret = -EACCES;
  635. goto fail;
  636. }
  637. _drm_lease_revoke(lessee);
  638. fail:
  639. mutex_unlock(&dev->mode_config.idr_mutex);
  640. return ret;
  641. }