1996bc4f4STrond Myklebust // SPDX-License-Identifier: GPL-2.0 2996bc4f4STrond Myklebust /* 3996bc4f4STrond Myklebust * Copyright (c) 2019 Hammerspace Inc 4996bc4f4STrond Myklebust */ 5996bc4f4STrond Myklebust 6996bc4f4STrond Myklebust #include <linux/module.h> 7996bc4f4STrond Myklebust #include <linux/kobject.h> 8996bc4f4STrond Myklebust #include <linux/sysfs.h> 9996bc4f4STrond Myklebust #include <linux/fs.h> 10996bc4f4STrond Myklebust #include <linux/slab.h> 11996bc4f4STrond Myklebust #include <linux/netdevice.h> 12bf11fbdbSTrond Myklebust #include <linux/string.h> 13bf11fbdbSTrond Myklebust #include <linux/nfs_fs.h> 14bf11fbdbSTrond Myklebust #include <linux/rcupdate.h> 15996bc4f4STrond Myklebust 16bf11fbdbSTrond Myklebust #include "nfs4_fs.h" 17bf11fbdbSTrond Myklebust #include "netns.h" 18996bc4f4STrond Myklebust #include "sysfs.h" 19996bc4f4STrond Myklebust 20d5082aceSBenjamin Coddington struct kobject *nfs_net_kobj; 218b18a2edSBenjamin Coddington static struct kset *nfs_kset; 22996bc4f4STrond Myklebust 23996bc4f4STrond Myklebust static void nfs_netns_object_release(struct kobject *kobj) 24996bc4f4STrond Myklebust { 25996bc4f4STrond Myklebust kfree(kobj); 26996bc4f4STrond Myklebust } 27996bc4f4STrond Myklebust 28*943aef2dSBenjamin Coddington static void nfs_kset_release(struct kobject *kobj) 29*943aef2dSBenjamin Coddington { 30*943aef2dSBenjamin Coddington struct kset *kset = container_of(kobj, struct kset, kobj); 31*943aef2dSBenjamin Coddington kfree(kset); 32*943aef2dSBenjamin Coddington } 33*943aef2dSBenjamin Coddington 34996bc4f4STrond Myklebust static const struct kobj_ns_type_operations *nfs_netns_object_child_ns_type( 3502a476d9SGreg Kroah-Hartman const struct kobject *kobj) 36996bc4f4STrond Myklebust { 37996bc4f4STrond Myklebust return &net_ns_type_operations; 38996bc4f4STrond Myklebust } 39996bc4f4STrond Myklebust 40*943aef2dSBenjamin Coddington static struct kobj_type nfs_kset_type = { 41*943aef2dSBenjamin Coddington .release = nfs_kset_release, 42*943aef2dSBenjamin Coddington .sysfs_ops = &kobj_sysfs_ops, 43*943aef2dSBenjamin Coddington }; 44*943aef2dSBenjamin Coddington 45996bc4f4STrond Myklebust static struct kobj_type nfs_netns_object_type = { 46996bc4f4STrond Myklebust .release = nfs_netns_object_release, 47996bc4f4STrond Myklebust .sysfs_ops = &kobj_sysfs_ops, 48996bc4f4STrond Myklebust .child_ns_type = nfs_netns_object_child_ns_type, 49996bc4f4STrond Myklebust }; 50996bc4f4STrond Myklebust 51996bc4f4STrond Myklebust static struct kobject *nfs_netns_object_alloc(const char *name, 52996bc4f4STrond Myklebust struct kset *kset, struct kobject *parent) 53996bc4f4STrond Myklebust { 54996bc4f4STrond Myklebust struct kobject *kobj; 55996bc4f4STrond Myklebust 56996bc4f4STrond Myklebust kobj = kzalloc(sizeof(*kobj), GFP_KERNEL); 57996bc4f4STrond Myklebust if (kobj) { 58996bc4f4STrond Myklebust kobj->kset = kset; 59996bc4f4STrond Myklebust if (kobject_init_and_add(kobj, &nfs_netns_object_type, 60996bc4f4STrond Myklebust parent, "%s", name) == 0) 61996bc4f4STrond Myklebust return kobj; 62996bc4f4STrond Myklebust kobject_put(kobj); 63996bc4f4STrond Myklebust } 64996bc4f4STrond Myklebust return NULL; 65996bc4f4STrond Myklebust } 66996bc4f4STrond Myklebust 67996bc4f4STrond Myklebust int nfs_sysfs_init(void) 68996bc4f4STrond Myklebust { 69*943aef2dSBenjamin Coddington int ret; 70*943aef2dSBenjamin Coddington 71*943aef2dSBenjamin Coddington nfs_kset = kzalloc(sizeof(*nfs_kset), GFP_KERNEL); 728b18a2edSBenjamin Coddington if (!nfs_kset) 73996bc4f4STrond Myklebust return -ENOMEM; 74*943aef2dSBenjamin Coddington 75*943aef2dSBenjamin Coddington ret = kobject_set_name(&nfs_kset->kobj, "nfs"); 76*943aef2dSBenjamin Coddington if (ret) { 77*943aef2dSBenjamin Coddington kfree(nfs_kset); 78*943aef2dSBenjamin Coddington return ret; 79*943aef2dSBenjamin Coddington } 80*943aef2dSBenjamin Coddington 81*943aef2dSBenjamin Coddington nfs_kset->kobj.parent = fs_kobj; 82*943aef2dSBenjamin Coddington nfs_kset->kobj.ktype = &nfs_kset_type; 83*943aef2dSBenjamin Coddington nfs_kset->kobj.kset = NULL; 84*943aef2dSBenjamin Coddington 85*943aef2dSBenjamin Coddington ret = kset_register(nfs_kset); 86*943aef2dSBenjamin Coddington if (ret) { 87*943aef2dSBenjamin Coddington kfree(nfs_kset); 88*943aef2dSBenjamin Coddington return ret; 89*943aef2dSBenjamin Coddington } 90*943aef2dSBenjamin Coddington 91d5082aceSBenjamin Coddington nfs_net_kobj = nfs_netns_object_alloc("net", nfs_kset, NULL); 92d5082aceSBenjamin Coddington if (!nfs_net_kobj) { 938b18a2edSBenjamin Coddington kset_unregister(nfs_kset); 94*943aef2dSBenjamin Coddington kfree(nfs_kset); 95996bc4f4STrond Myklebust return -ENOMEM; 96996bc4f4STrond Myklebust } 97996bc4f4STrond Myklebust return 0; 98996bc4f4STrond Myklebust } 99996bc4f4STrond Myklebust 100996bc4f4STrond Myklebust void nfs_sysfs_exit(void) 101996bc4f4STrond Myklebust { 102d5082aceSBenjamin Coddington kobject_put(nfs_net_kobj); 1038b18a2edSBenjamin Coddington kset_unregister(nfs_kset); 104996bc4f4STrond Myklebust } 105bf11fbdbSTrond Myklebust 106bf11fbdbSTrond Myklebust static ssize_t nfs_netns_identifier_show(struct kobject *kobj, 107bf11fbdbSTrond Myklebust struct kobj_attribute *attr, char *buf) 108bf11fbdbSTrond Myklebust { 109bf11fbdbSTrond Myklebust struct nfs_netns_client *c = container_of(kobj, 110bf11fbdbSTrond Myklebust struct nfs_netns_client, 111bf11fbdbSTrond Myklebust kobject); 112094eca37STrond Myklebust ssize_t ret; 113094eca37STrond Myklebust 114094eca37STrond Myklebust rcu_read_lock(); 11519cdc8faSye xingchen ret = sysfs_emit(buf, "%s\n", rcu_dereference(c->identifier)); 116094eca37STrond Myklebust rcu_read_unlock(); 117094eca37STrond Myklebust return ret; 118bf11fbdbSTrond Myklebust } 119bf11fbdbSTrond Myklebust 120bf11fbdbSTrond Myklebust /* Strip trailing '\n' */ 121bf11fbdbSTrond Myklebust static size_t nfs_string_strip(const char *c, size_t len) 122bf11fbdbSTrond Myklebust { 123bf11fbdbSTrond Myklebust while (len > 0 && c[len-1] == '\n') 124bf11fbdbSTrond Myklebust --len; 125bf11fbdbSTrond Myklebust return len; 126bf11fbdbSTrond Myklebust } 127bf11fbdbSTrond Myklebust 128bf11fbdbSTrond Myklebust static ssize_t nfs_netns_identifier_store(struct kobject *kobj, 129bf11fbdbSTrond Myklebust struct kobj_attribute *attr, 130bf11fbdbSTrond Myklebust const char *buf, size_t count) 131bf11fbdbSTrond Myklebust { 132bf11fbdbSTrond Myklebust struct nfs_netns_client *c = container_of(kobj, 133bf11fbdbSTrond Myklebust struct nfs_netns_client, 134bf11fbdbSTrond Myklebust kobject); 135bf11fbdbSTrond Myklebust const char *old; 136bf11fbdbSTrond Myklebust char *p; 137bf11fbdbSTrond Myklebust size_t len; 138bf11fbdbSTrond Myklebust 139bf11fbdbSTrond Myklebust len = nfs_string_strip(buf, min_t(size_t, count, CONTAINER_ID_MAXLEN)); 140bf11fbdbSTrond Myklebust if (!len) 141bf11fbdbSTrond Myklebust return 0; 142bf11fbdbSTrond Myklebust p = kmemdup_nul(buf, len, GFP_KERNEL); 143bf11fbdbSTrond Myklebust if (!p) 144bf11fbdbSTrond Myklebust return -ENOMEM; 145094eca37STrond Myklebust old = rcu_dereference_protected(xchg(&c->identifier, (char __rcu *)p), 1); 146bf11fbdbSTrond Myklebust if (old) { 147bf11fbdbSTrond Myklebust synchronize_rcu(); 148bf11fbdbSTrond Myklebust kfree(old); 149bf11fbdbSTrond Myklebust } 150bf11fbdbSTrond Myklebust return count; 151bf11fbdbSTrond Myklebust } 152bf11fbdbSTrond Myklebust 153bf11fbdbSTrond Myklebust static void nfs_netns_client_release(struct kobject *kobj) 154bf11fbdbSTrond Myklebust { 155bf11fbdbSTrond Myklebust struct nfs_netns_client *c = container_of(kobj, 156bf11fbdbSTrond Myklebust struct nfs_netns_client, 157bf11fbdbSTrond Myklebust kobject); 158bf11fbdbSTrond Myklebust 159094eca37STrond Myklebust kfree(rcu_dereference_raw(c->identifier)); 160bf11fbdbSTrond Myklebust kfree(c); 161bf11fbdbSTrond Myklebust } 162bf11fbdbSTrond Myklebust 16302a476d9SGreg Kroah-Hartman static const void *nfs_netns_client_namespace(const struct kobject *kobj) 164bf11fbdbSTrond Myklebust { 165bf11fbdbSTrond Myklebust return container_of(kobj, struct nfs_netns_client, kobject)->net; 166bf11fbdbSTrond Myklebust } 167bf11fbdbSTrond Myklebust 168bf11fbdbSTrond Myklebust static struct kobj_attribute nfs_netns_client_id = __ATTR(identifier, 169bf11fbdbSTrond Myklebust 0644, nfs_netns_identifier_show, nfs_netns_identifier_store); 170bf11fbdbSTrond Myklebust 171bf11fbdbSTrond Myklebust static struct attribute *nfs_netns_client_attrs[] = { 172bf11fbdbSTrond Myklebust &nfs_netns_client_id.attr, 173bf11fbdbSTrond Myklebust NULL, 174bf11fbdbSTrond Myklebust }; 17501f34245SGreg Kroah-Hartman ATTRIBUTE_GROUPS(nfs_netns_client); 176bf11fbdbSTrond Myklebust 177bf11fbdbSTrond Myklebust static struct kobj_type nfs_netns_client_type = { 178bf11fbdbSTrond Myklebust .release = nfs_netns_client_release, 17901f34245SGreg Kroah-Hartman .default_groups = nfs_netns_client_groups, 180bf11fbdbSTrond Myklebust .sysfs_ops = &kobj_sysfs_ops, 181bf11fbdbSTrond Myklebust .namespace = nfs_netns_client_namespace, 182bf11fbdbSTrond Myklebust }; 183bf11fbdbSTrond Myklebust 184bf11fbdbSTrond Myklebust static struct nfs_netns_client *nfs_netns_client_alloc(struct kobject *parent, 185bf11fbdbSTrond Myklebust struct net *net) 186bf11fbdbSTrond Myklebust { 187bf11fbdbSTrond Myklebust struct nfs_netns_client *p; 188bf11fbdbSTrond Myklebust 189bf11fbdbSTrond Myklebust p = kzalloc(sizeof(*p), GFP_KERNEL); 190bf11fbdbSTrond Myklebust if (p) { 191bf11fbdbSTrond Myklebust p->net = net; 1928b18a2edSBenjamin Coddington p->kobject.kset = nfs_kset; 193bf11fbdbSTrond Myklebust if (kobject_init_and_add(&p->kobject, &nfs_netns_client_type, 194bf11fbdbSTrond Myklebust parent, "nfs_client") == 0) 195bf11fbdbSTrond Myklebust return p; 196bf11fbdbSTrond Myklebust kobject_put(&p->kobject); 197bf11fbdbSTrond Myklebust } 198bf11fbdbSTrond Myklebust return NULL; 199bf11fbdbSTrond Myklebust } 200bf11fbdbSTrond Myklebust 201bf11fbdbSTrond Myklebust void nfs_netns_sysfs_setup(struct nfs_net *netns, struct net *net) 202bf11fbdbSTrond Myklebust { 203bf11fbdbSTrond Myklebust struct nfs_netns_client *clp; 204bf11fbdbSTrond Myklebust 205d5082aceSBenjamin Coddington clp = nfs_netns_client_alloc(nfs_net_kobj, net); 206bf11fbdbSTrond Myklebust if (clp) { 207bf11fbdbSTrond Myklebust netns->nfs_client = clp; 208bf11fbdbSTrond Myklebust kobject_uevent(&clp->kobject, KOBJ_ADD); 209bf11fbdbSTrond Myklebust } 210bf11fbdbSTrond Myklebust } 211bf11fbdbSTrond Myklebust 212bf11fbdbSTrond Myklebust void nfs_netns_sysfs_destroy(struct nfs_net *netns) 213bf11fbdbSTrond Myklebust { 214bf11fbdbSTrond Myklebust struct nfs_netns_client *clp = netns->nfs_client; 215bf11fbdbSTrond Myklebust 216bf11fbdbSTrond Myklebust if (clp) { 217bf11fbdbSTrond Myklebust kobject_uevent(&clp->kobject, KOBJ_REMOVE); 218bf11fbdbSTrond Myklebust kobject_del(&clp->kobject); 219bf11fbdbSTrond Myklebust kobject_put(&clp->kobject); 220bf11fbdbSTrond Myklebust netns->nfs_client = NULL; 221bf11fbdbSTrond Myklebust } 222bf11fbdbSTrond Myklebust } 223