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