netclassid_cgroup.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * net/core/netclassid_cgroup.c Classid Cgroupfs Handling
  4. *
  5. * Authors: Thomas Graf <tgraf@suug.ch>
  6. */
  7. #include <linux/slab.h>
  8. #include <linux/cgroup.h>
  9. #include <linux/fdtable.h>
  10. #include <linux/sched/task.h>
  11. #include <net/cls_cgroup.h>
  12. #include <net/sock.h>
  13. static inline struct cgroup_cls_state *css_cls_state(struct cgroup_subsys_state *css)
  14. {
  15. return css ? container_of(css, struct cgroup_cls_state, css) : NULL;
  16. }
  17. struct cgroup_cls_state *task_cls_state(struct task_struct *p)
  18. {
  19. return css_cls_state(task_css_check(p, net_cls_cgrp_id,
  20. rcu_read_lock_held() ||
  21. rcu_read_lock_bh_held() ||
  22. rcu_read_lock_trace_held()));
  23. }
  24. EXPORT_SYMBOL_GPL(task_cls_state);
  25. static struct cgroup_subsys_state *
  26. cgrp_css_alloc(struct cgroup_subsys_state *parent_css)
  27. {
  28. struct cgroup_cls_state *cs;
  29. cs = kzalloc_obj(*cs);
  30. if (!cs)
  31. return ERR_PTR(-ENOMEM);
  32. return &cs->css;
  33. }
  34. static int cgrp_css_online(struct cgroup_subsys_state *css)
  35. {
  36. struct cgroup_cls_state *cs = css_cls_state(css);
  37. struct cgroup_cls_state *parent = css_cls_state(css->parent);
  38. if (parent)
  39. cs->classid = parent->classid;
  40. return 0;
  41. }
  42. static void cgrp_css_free(struct cgroup_subsys_state *css)
  43. {
  44. kfree(css_cls_state(css));
  45. }
  46. /*
  47. * To avoid freezing of sockets creation for tasks with big number of threads
  48. * and opened sockets lets release file_lock every 1000 iterated descriptors.
  49. * New sockets will already have been created with new classid.
  50. */
  51. struct update_classid_context {
  52. u32 classid;
  53. unsigned int batch;
  54. };
  55. #define UPDATE_CLASSID_BATCH 1000
  56. static int update_classid_sock(const void *v, struct file *file, unsigned int n)
  57. {
  58. struct update_classid_context *ctx = (void *)v;
  59. struct socket *sock = sock_from_file(file);
  60. if (sock)
  61. sock_cgroup_set_classid(&sock->sk->sk_cgrp_data, ctx->classid);
  62. if (--ctx->batch == 0) {
  63. ctx->batch = UPDATE_CLASSID_BATCH;
  64. return n + 1;
  65. }
  66. return 0;
  67. }
  68. static void update_classid_task(struct task_struct *p, u32 classid)
  69. {
  70. struct update_classid_context ctx = {
  71. .classid = classid,
  72. .batch = UPDATE_CLASSID_BATCH
  73. };
  74. unsigned int fd = 0;
  75. /* Only update the leader task, when many threads in this task,
  76. * so it can avoid the useless traversal.
  77. */
  78. if (!thread_group_leader(p))
  79. return;
  80. do {
  81. task_lock(p);
  82. fd = iterate_fd(p->files, fd, update_classid_sock, &ctx);
  83. task_unlock(p);
  84. cond_resched();
  85. } while (fd);
  86. }
  87. static void cgrp_attach(struct cgroup_taskset *tset)
  88. {
  89. struct cgroup_subsys_state *css;
  90. struct task_struct *p;
  91. cgroup_taskset_for_each(p, css, tset) {
  92. update_classid_task(p, css_cls_state(css)->classid);
  93. }
  94. }
  95. static u64 read_classid(struct cgroup_subsys_state *css, struct cftype *cft)
  96. {
  97. return css_cls_state(css)->classid;
  98. }
  99. static int write_classid(struct cgroup_subsys_state *css, struct cftype *cft,
  100. u64 value)
  101. {
  102. struct cgroup_cls_state *cs = css_cls_state(css);
  103. struct css_task_iter it;
  104. struct task_struct *p;
  105. cs->classid = (u32)value;
  106. css_task_iter_start(css, 0, &it);
  107. while ((p = css_task_iter_next(&it)))
  108. update_classid_task(p, cs->classid);
  109. css_task_iter_end(&it);
  110. return 0;
  111. }
  112. static struct cftype ss_files[] = {
  113. {
  114. .name = "classid",
  115. .read_u64 = read_classid,
  116. .write_u64 = write_classid,
  117. },
  118. { } /* terminate */
  119. };
  120. struct cgroup_subsys net_cls_cgrp_subsys = {
  121. .css_alloc = cgrp_css_alloc,
  122. .css_online = cgrp_css_online,
  123. .css_free = cgrp_css_free,
  124. .attach = cgrp_attach,
  125. .legacy_cftypes = ss_files,
  126. };