Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (c) 2019 Hammerspace Inc
0004  */
0005 
0006 #include <linux/module.h>
0007 #include <linux/kobject.h>
0008 #include <linux/sysfs.h>
0009 #include <linux/fs.h>
0010 #include <linux/slab.h>
0011 #include <linux/netdevice.h>
0012 #include <linux/string.h>
0013 #include <linux/nfs_fs.h>
0014 #include <linux/rcupdate.h>
0015 
0016 #include "nfs4_fs.h"
0017 #include "netns.h"
0018 #include "sysfs.h"
0019 
0020 struct kobject *nfs_client_kobj;
0021 static struct kset *nfs_client_kset;
0022 
0023 static void nfs_netns_object_release(struct kobject *kobj)
0024 {
0025     kfree(kobj);
0026 }
0027 
0028 static const struct kobj_ns_type_operations *nfs_netns_object_child_ns_type(
0029         struct kobject *kobj)
0030 {
0031     return &net_ns_type_operations;
0032 }
0033 
0034 static struct kobj_type nfs_netns_object_type = {
0035     .release = nfs_netns_object_release,
0036     .sysfs_ops = &kobj_sysfs_ops,
0037     .child_ns_type = nfs_netns_object_child_ns_type,
0038 };
0039 
0040 static struct kobject *nfs_netns_object_alloc(const char *name,
0041         struct kset *kset, struct kobject *parent)
0042 {
0043     struct kobject *kobj;
0044 
0045     kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);
0046     if (kobj) {
0047         kobj->kset = kset;
0048         if (kobject_init_and_add(kobj, &nfs_netns_object_type,
0049                     parent, "%s", name) == 0)
0050             return kobj;
0051         kobject_put(kobj);
0052     }
0053     return NULL;
0054 }
0055 
0056 int nfs_sysfs_init(void)
0057 {
0058     nfs_client_kset = kset_create_and_add("nfs", NULL, fs_kobj);
0059     if (!nfs_client_kset)
0060         return -ENOMEM;
0061     nfs_client_kobj = nfs_netns_object_alloc("net", nfs_client_kset, NULL);
0062     if  (!nfs_client_kobj) {
0063         kset_unregister(nfs_client_kset);
0064         nfs_client_kset = NULL;
0065         return -ENOMEM;
0066     }
0067     return 0;
0068 }
0069 
0070 void nfs_sysfs_exit(void)
0071 {
0072     kobject_put(nfs_client_kobj);
0073     kset_unregister(nfs_client_kset);
0074 }
0075 
0076 static ssize_t nfs_netns_identifier_show(struct kobject *kobj,
0077         struct kobj_attribute *attr, char *buf)
0078 {
0079     struct nfs_netns_client *c = container_of(kobj,
0080             struct nfs_netns_client,
0081             kobject);
0082     ssize_t ret;
0083 
0084     rcu_read_lock();
0085     ret = scnprintf(buf, PAGE_SIZE, "%s\n", rcu_dereference(c->identifier));
0086     rcu_read_unlock();
0087     return ret;
0088 }
0089 
0090 /* Strip trailing '\n' */
0091 static size_t nfs_string_strip(const char *c, size_t len)
0092 {
0093     while (len > 0 && c[len-1] == '\n')
0094         --len;
0095     return len;
0096 }
0097 
0098 static ssize_t nfs_netns_identifier_store(struct kobject *kobj,
0099         struct kobj_attribute *attr,
0100         const char *buf, size_t count)
0101 {
0102     struct nfs_netns_client *c = container_of(kobj,
0103             struct nfs_netns_client,
0104             kobject);
0105     const char *old;
0106     char *p;
0107     size_t len;
0108 
0109     len = nfs_string_strip(buf, min_t(size_t, count, CONTAINER_ID_MAXLEN));
0110     if (!len)
0111         return 0;
0112     p = kmemdup_nul(buf, len, GFP_KERNEL);
0113     if (!p)
0114         return -ENOMEM;
0115     old = rcu_dereference_protected(xchg(&c->identifier, (char __rcu *)p), 1);
0116     if (old) {
0117         synchronize_rcu();
0118         kfree(old);
0119     }
0120     return count;
0121 }
0122 
0123 static void nfs_netns_client_release(struct kobject *kobj)
0124 {
0125     struct nfs_netns_client *c = container_of(kobj,
0126             struct nfs_netns_client,
0127             kobject);
0128 
0129     kfree(rcu_dereference_raw(c->identifier));
0130     kfree(c);
0131 }
0132 
0133 static const void *nfs_netns_client_namespace(struct kobject *kobj)
0134 {
0135     return container_of(kobj, struct nfs_netns_client, kobject)->net;
0136 }
0137 
0138 static struct kobj_attribute nfs_netns_client_id = __ATTR(identifier,
0139         0644, nfs_netns_identifier_show, nfs_netns_identifier_store);
0140 
0141 static struct attribute *nfs_netns_client_attrs[] = {
0142     &nfs_netns_client_id.attr,
0143     NULL,
0144 };
0145 ATTRIBUTE_GROUPS(nfs_netns_client);
0146 
0147 static struct kobj_type nfs_netns_client_type = {
0148     .release = nfs_netns_client_release,
0149     .default_groups = nfs_netns_client_groups,
0150     .sysfs_ops = &kobj_sysfs_ops,
0151     .namespace = nfs_netns_client_namespace,
0152 };
0153 
0154 static struct nfs_netns_client *nfs_netns_client_alloc(struct kobject *parent,
0155         struct net *net)
0156 {
0157     struct nfs_netns_client *p;
0158 
0159     p = kzalloc(sizeof(*p), GFP_KERNEL);
0160     if (p) {
0161         p->net = net;
0162         p->kobject.kset = nfs_client_kset;
0163         if (kobject_init_and_add(&p->kobject, &nfs_netns_client_type,
0164                     parent, "nfs_client") == 0)
0165             return p;
0166         kobject_put(&p->kobject);
0167     }
0168     return NULL;
0169 }
0170 
0171 void nfs_netns_sysfs_setup(struct nfs_net *netns, struct net *net)
0172 {
0173     struct nfs_netns_client *clp;
0174 
0175     clp = nfs_netns_client_alloc(nfs_client_kobj, net);
0176     if (clp) {
0177         netns->nfs_client = clp;
0178         kobject_uevent(&clp->kobject, KOBJ_ADD);
0179     }
0180 }
0181 
0182 void nfs_netns_sysfs_destroy(struct nfs_net *netns)
0183 {
0184     struct nfs_netns_client *clp = netns->nfs_client;
0185 
0186     if (clp) {
0187         kobject_uevent(&clp->kobject, KOBJ_REMOVE);
0188         kobject_del(&clp->kobject);
0189         kobject_put(&clp->kobject);
0190         netns->nfs_client = NULL;
0191     }
0192 }