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                spin_lock(&cgroup_sk_update_lock);
  76                sock_cgroup_set_classid(&sock->sk->sk_cgrp_data, ctx->classid);
  77                spin_unlock(&cgroup_sk_update_lock);
  78        }
  79        if (--ctx->batch == 0) {
  80                ctx->batch = UPDATE_CLASSID_BATCH;
  81                return n + 1;
  82        }
  83        return 0;
  84}
  85
  86static void update_classid_task(struct task_struct *p, u32 classid)
  87{
  88        struct update_classid_context ctx = {
  89                .classid = classid,
  90                .batch = UPDATE_CLASSID_BATCH
  91        };
  92        unsigned int fd = 0;
  93
  94        do {
  95                task_lock(p);
  96                fd = iterate_fd(p->files, fd, update_classid_sock, &ctx);
  97                task_unlock(p);
  98                cond_resched();
  99        } while (fd);
 100}
 101
 102static void cgrp_attach(struct cgroup_taskset *tset)
 103{
 104        struct cgroup_subsys_state *css;
 105        struct task_struct *p;
 106
 107        cgroup_taskset_for_each(p, css, tset) {
 108                update_classid_task(p, css_cls_state(css)->classid);
 109        }
 110}
 111
 112static u64 read_classid(struct cgroup_subsys_state *css, struct cftype *cft)
 113{
 114        return css_cls_state(css)->classid;
 115}
 116
 117static int write_classid(struct cgroup_subsys_state *css, struct cftype *cft,
 118                         u64 value)
 119{
 120        struct cgroup_cls_state *cs = css_cls_state(css);
 121        struct css_task_iter it;
 122        struct task_struct *p;
 123
 124        cgroup_sk_alloc_disable();
 125
 126        cs->classid = (u32)value;
 127
 128        css_task_iter_start(css, 0, &it);
 129        while ((p = css_task_iter_next(&it)))
 130                update_classid_task(p, cs->classid);
 131        css_task_iter_end(&it);
 132
 133        return 0;
 134}
 135
 136static struct cftype ss_files[] = {
 137        {
 138                .name           = "classid",
 139                .read_u64       = read_classid,
 140                .write_u64      = write_classid,
 141        },
 142        { }     /* terminate */
 143};
 144
 145struct cgroup_subsys net_cls_cgrp_subsys = {
 146        .css_alloc              = cgrp_css_alloc,
 147        .css_online             = cgrp_css_online,
 148        .css_free               = cgrp_css_free,
 149        .attach                 = cgrp_attach,
 150        .legacy_cftypes         = ss_files,
 151};
 152