netclassid_cgroup.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  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_bh_held()));
  21. }
  22. EXPORT_SYMBOL_GPL(task_cls_state);
  23. static struct cgroup_subsys_state *
  24. cgrp_css_alloc(struct cgroup_subsys_state *parent_css)
  25. {
  26. struct cgroup_cls_state *cs;
  27. cs = kzalloc(sizeof(*cs), GFP_KERNEL);
  28. if (!cs)
  29. return ERR_PTR(-ENOMEM);
  30. return &cs->css;
  31. }
  32. static int cgrp_css_online(struct cgroup_subsys_state *css)
  33. {
  34. struct cgroup_cls_state *cs = css_cls_state(css);
  35. struct cgroup_cls_state *parent = css_cls_state(css->parent);
  36. if (parent)
  37. cs->classid = parent->classid;
  38. return 0;
  39. }
  40. static void cgrp_css_free(struct cgroup_subsys_state *css)
  41. {
  42. kfree(css_cls_state(css));
  43. }
  44. /*
  45. * To avoid freezing of sockets creation for tasks with big number of threads
  46. * and opened sockets lets release file_lock every 1000 iterated descriptors.
  47. * New sockets will already have been created with new classid.
  48. */
  49. struct update_classid_context {
  50. u32 classid;
  51. unsigned int batch;
  52. };
  53. #define UPDATE_CLASSID_BATCH 1000
  54. static int update_classid_sock(const void *v, struct file *file, unsigned int n)
  55. {
  56. struct update_classid_context *ctx = (void *)v;
  57. struct socket *sock = sock_from_file(file);
  58. if (sock)
  59. sock_cgroup_set_classid(&sock->sk->sk_cgrp_data, ctx->classid);
  60. if (--ctx->batch == 0) {
  61. ctx->batch = UPDATE_CLASSID_BATCH;
  62. return n + 1;
  63. }
  64. return 0;
  65. }
  66. static void update_classid_task(struct task_struct *p, u32 classid)
  67. {
  68. struct update_classid_context ctx = {
  69. .classid = classid,
  70. .batch = UPDATE_CLASSID_BATCH
  71. };
  72. unsigned int fd = 0;
  73. /* Only update the leader task, when many threads in this task,
  74. * so it can avoid the useless traversal.
  75. */
  76. if (p != p->group_leader)
  77. return;
  78. do {
  79. task_lock(p);
  80. fd = iterate_fd(p->files, fd, update_classid_sock, &ctx);
  81. task_unlock(p);
  82. cond_resched();
  83. } while (fd);
  84. }
  85. static void cgrp_attach(struct cgroup_taskset *tset)
  86. {
  87. struct cgroup_subsys_state *css;
  88. struct task_struct *p;
  89. cgroup_taskset_for_each(p, css, tset) {
  90. update_classid_task(p, css_cls_state(css)->classid);
  91. }
  92. }
  93. static u64 read_classid(struct cgroup_subsys_state *css, struct cftype *cft)
  94. {
  95. return css_cls_state(css)->classid;
  96. }
  97. static int write_classid(struct cgroup_subsys_state *css, struct cftype *cft,
  98. u64 value)
  99. {
  100. struct cgroup_cls_state *cs = css_cls_state(css);
  101. struct css_task_iter it;
  102. struct task_struct *p;
  103. cs->classid = (u32)value;
  104. css_task_iter_start(css, 0, &it);
  105. while ((p = css_task_iter_next(&it)))
  106. update_classid_task(p, cs->classid);
  107. css_task_iter_end(&it);
  108. return 0;
  109. }
  110. static struct cftype ss_files[] = {
  111. {
  112. .name = "classid",
  113. .read_u64 = read_classid,
  114. .write_u64 = write_classid,
  115. },
  116. { } /* terminate */
  117. };
  118. struct cgroup_subsys net_cls_cgrp_subsys = {
  119. .css_alloc = cgrp_css_alloc,
  120. .css_online = cgrp_css_online,
  121. .css_free = cgrp_css_free,
  122. .attach = cgrp_attach,
  123. .legacy_cftypes = ss_files,
  124. };