cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

sysfs.c (4386B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright (c) 2019 Hammerspace Inc
      4 */
      5
      6#include <linux/module.h>
      7#include <linux/kobject.h>
      8#include <linux/sysfs.h>
      9#include <linux/fs.h>
     10#include <linux/slab.h>
     11#include <linux/netdevice.h>
     12#include <linux/string.h>
     13#include <linux/nfs_fs.h>
     14#include <linux/rcupdate.h>
     15
     16#include "nfs4_fs.h"
     17#include "netns.h"
     18#include "sysfs.h"
     19
     20struct kobject *nfs_client_kobj;
     21static struct kset *nfs_client_kset;
     22
     23static void nfs_netns_object_release(struct kobject *kobj)
     24{
     25	kfree(kobj);
     26}
     27
     28static const struct kobj_ns_type_operations *nfs_netns_object_child_ns_type(
     29		struct kobject *kobj)
     30{
     31	return &net_ns_type_operations;
     32}
     33
     34static struct kobj_type nfs_netns_object_type = {
     35	.release = nfs_netns_object_release,
     36	.sysfs_ops = &kobj_sysfs_ops,
     37	.child_ns_type = nfs_netns_object_child_ns_type,
     38};
     39
     40static struct kobject *nfs_netns_object_alloc(const char *name,
     41		struct kset *kset, struct kobject *parent)
     42{
     43	struct kobject *kobj;
     44
     45	kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);
     46	if (kobj) {
     47		kobj->kset = kset;
     48		if (kobject_init_and_add(kobj, &nfs_netns_object_type,
     49					parent, "%s", name) == 0)
     50			return kobj;
     51		kobject_put(kobj);
     52	}
     53	return NULL;
     54}
     55
     56int nfs_sysfs_init(void)
     57{
     58	nfs_client_kset = kset_create_and_add("nfs", NULL, fs_kobj);
     59	if (!nfs_client_kset)
     60		return -ENOMEM;
     61	nfs_client_kobj = nfs_netns_object_alloc("net", nfs_client_kset, NULL);
     62	if  (!nfs_client_kobj) {
     63		kset_unregister(nfs_client_kset);
     64		nfs_client_kset = NULL;
     65		return -ENOMEM;
     66	}
     67	return 0;
     68}
     69
     70void nfs_sysfs_exit(void)
     71{
     72	kobject_put(nfs_client_kobj);
     73	kset_unregister(nfs_client_kset);
     74}
     75
     76static ssize_t nfs_netns_identifier_show(struct kobject *kobj,
     77		struct kobj_attribute *attr, char *buf)
     78{
     79	struct nfs_netns_client *c = container_of(kobj,
     80			struct nfs_netns_client,
     81			kobject);
     82	ssize_t ret;
     83
     84	rcu_read_lock();
     85	ret = scnprintf(buf, PAGE_SIZE, "%s\n", rcu_dereference(c->identifier));
     86	rcu_read_unlock();
     87	return ret;
     88}
     89
     90/* Strip trailing '\n' */
     91static size_t nfs_string_strip(const char *c, size_t len)
     92{
     93	while (len > 0 && c[len-1] == '\n')
     94		--len;
     95	return len;
     96}
     97
     98static ssize_t nfs_netns_identifier_store(struct kobject *kobj,
     99		struct kobj_attribute *attr,
    100		const char *buf, size_t count)
    101{
    102	struct nfs_netns_client *c = container_of(kobj,
    103			struct nfs_netns_client,
    104			kobject);
    105	const char *old;
    106	char *p;
    107	size_t len;
    108
    109	len = nfs_string_strip(buf, min_t(size_t, count, CONTAINER_ID_MAXLEN));
    110	if (!len)
    111		return 0;
    112	p = kmemdup_nul(buf, len, GFP_KERNEL);
    113	if (!p)
    114		return -ENOMEM;
    115	old = rcu_dereference_protected(xchg(&c->identifier, (char __rcu *)p), 1);
    116	if (old) {
    117		synchronize_rcu();
    118		kfree(old);
    119	}
    120	return count;
    121}
    122
    123static void nfs_netns_client_release(struct kobject *kobj)
    124{
    125	struct nfs_netns_client *c = container_of(kobj,
    126			struct nfs_netns_client,
    127			kobject);
    128
    129	kfree(rcu_dereference_raw(c->identifier));
    130	kfree(c);
    131}
    132
    133static const void *nfs_netns_client_namespace(struct kobject *kobj)
    134{
    135	return container_of(kobj, struct nfs_netns_client, kobject)->net;
    136}
    137
    138static struct kobj_attribute nfs_netns_client_id = __ATTR(identifier,
    139		0644, nfs_netns_identifier_show, nfs_netns_identifier_store);
    140
    141static struct attribute *nfs_netns_client_attrs[] = {
    142	&nfs_netns_client_id.attr,
    143	NULL,
    144};
    145ATTRIBUTE_GROUPS(nfs_netns_client);
    146
    147static struct kobj_type nfs_netns_client_type = {
    148	.release = nfs_netns_client_release,
    149	.default_groups = nfs_netns_client_groups,
    150	.sysfs_ops = &kobj_sysfs_ops,
    151	.namespace = nfs_netns_client_namespace,
    152};
    153
    154static struct nfs_netns_client *nfs_netns_client_alloc(struct kobject *parent,
    155		struct net *net)
    156{
    157	struct nfs_netns_client *p;
    158
    159	p = kzalloc(sizeof(*p), GFP_KERNEL);
    160	if (p) {
    161		p->net = net;
    162		p->kobject.kset = nfs_client_kset;
    163		if (kobject_init_and_add(&p->kobject, &nfs_netns_client_type,
    164					parent, "nfs_client") == 0)
    165			return p;
    166		kobject_put(&p->kobject);
    167	}
    168	return NULL;
    169}
    170
    171void nfs_netns_sysfs_setup(struct nfs_net *netns, struct net *net)
    172{
    173	struct nfs_netns_client *clp;
    174
    175	clp = nfs_netns_client_alloc(nfs_client_kobj, net);
    176	if (clp) {
    177		netns->nfs_client = clp;
    178		kobject_uevent(&clp->kobject, KOBJ_ADD);
    179	}
    180}
    181
    182void nfs_netns_sysfs_destroy(struct nfs_net *netns)
    183{
    184	struct nfs_netns_client *clp = netns->nfs_client;
    185
    186	if (clp) {
    187		kobject_uevent(&clp->kobject, KOBJ_REMOVE);
    188		kobject_del(&clp->kobject);
    189		kobject_put(&clp->kobject);
    190		netns->nfs_client = NULL;
    191	}
    192}