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 208b18a2edSBenjamin Coddington static struct kset *nfs_kset; 21996bc4f4STrond Myklebust 22943aef2dSBenjamin Coddington static void nfs_kset_release(struct kobject *kobj) 23943aef2dSBenjamin Coddington { 24943aef2dSBenjamin Coddington struct kset *kset = container_of(kobj, struct kset, kobj); 25943aef2dSBenjamin Coddington kfree(kset); 26943aef2dSBenjamin Coddington } 27943aef2dSBenjamin Coddington 28996bc4f4STrond Myklebust static const struct kobj_ns_type_operations *nfs_netns_object_child_ns_type( 2902a476d9SGreg Kroah-Hartman const struct kobject *kobj) 30996bc4f4STrond Myklebust { 31996bc4f4STrond Myklebust return &net_ns_type_operations; 32996bc4f4STrond Myklebust } 33996bc4f4STrond Myklebust 34943aef2dSBenjamin Coddington static struct kobj_type nfs_kset_type = { 35943aef2dSBenjamin Coddington .release = nfs_kset_release, 36943aef2dSBenjamin Coddington .sysfs_ops = &kobj_sysfs_ops, 37996bc4f4STrond Myklebust .child_ns_type = nfs_netns_object_child_ns_type, 38996bc4f4STrond Myklebust }; 39996bc4f4STrond Myklebust 40996bc4f4STrond Myklebust int nfs_sysfs_init(void) 41996bc4f4STrond Myklebust { 42943aef2dSBenjamin Coddington int ret; 43943aef2dSBenjamin Coddington 44943aef2dSBenjamin Coddington nfs_kset = kzalloc(sizeof(*nfs_kset), GFP_KERNEL); 458b18a2edSBenjamin Coddington if (!nfs_kset) 46996bc4f4STrond Myklebust return -ENOMEM; 47943aef2dSBenjamin Coddington 48943aef2dSBenjamin Coddington ret = kobject_set_name(&nfs_kset->kobj, "nfs"); 49943aef2dSBenjamin Coddington if (ret) { 50943aef2dSBenjamin Coddington kfree(nfs_kset); 51943aef2dSBenjamin Coddington return ret; 52943aef2dSBenjamin Coddington } 53943aef2dSBenjamin Coddington 54943aef2dSBenjamin Coddington nfs_kset->kobj.parent = fs_kobj; 55943aef2dSBenjamin Coddington nfs_kset->kobj.ktype = &nfs_kset_type; 56943aef2dSBenjamin Coddington nfs_kset->kobj.kset = NULL; 57943aef2dSBenjamin Coddington 58943aef2dSBenjamin Coddington ret = kset_register(nfs_kset); 59943aef2dSBenjamin Coddington if (ret) { 60943aef2dSBenjamin Coddington kfree(nfs_kset); 61943aef2dSBenjamin Coddington return ret; 62943aef2dSBenjamin Coddington } 63943aef2dSBenjamin Coddington 64996bc4f4STrond Myklebust return 0; 65996bc4f4STrond Myklebust } 66996bc4f4STrond Myklebust 67996bc4f4STrond Myklebust void nfs_sysfs_exit(void) 68996bc4f4STrond Myklebust { 698b18a2edSBenjamin Coddington kset_unregister(nfs_kset); 70996bc4f4STrond Myklebust } 71bf11fbdbSTrond Myklebust 72bf11fbdbSTrond Myklebust static ssize_t nfs_netns_identifier_show(struct kobject *kobj, 73bf11fbdbSTrond Myklebust struct kobj_attribute *attr, char *buf) 74bf11fbdbSTrond Myklebust { 75bf11fbdbSTrond Myklebust struct nfs_netns_client *c = container_of(kobj, 76bf11fbdbSTrond Myklebust struct nfs_netns_client, 77bf11fbdbSTrond Myklebust kobject); 78094eca37STrond Myklebust ssize_t ret; 79094eca37STrond Myklebust 80094eca37STrond Myklebust rcu_read_lock(); 8119cdc8faSye xingchen ret = sysfs_emit(buf, "%s\n", rcu_dereference(c->identifier)); 82094eca37STrond Myklebust rcu_read_unlock(); 83094eca37STrond Myklebust return ret; 84bf11fbdbSTrond Myklebust } 85bf11fbdbSTrond Myklebust 86bf11fbdbSTrond Myklebust /* Strip trailing '\n' */ 87bf11fbdbSTrond Myklebust static size_t nfs_string_strip(const char *c, size_t len) 88bf11fbdbSTrond Myklebust { 89bf11fbdbSTrond Myklebust while (len > 0 && c[len-1] == '\n') 90bf11fbdbSTrond Myklebust --len; 91bf11fbdbSTrond Myklebust return len; 92bf11fbdbSTrond Myklebust } 93bf11fbdbSTrond Myklebust 94bf11fbdbSTrond Myklebust static ssize_t nfs_netns_identifier_store(struct kobject *kobj, 95bf11fbdbSTrond Myklebust struct kobj_attribute *attr, 96bf11fbdbSTrond Myklebust const char *buf, size_t count) 97bf11fbdbSTrond Myklebust { 98bf11fbdbSTrond Myklebust struct nfs_netns_client *c = container_of(kobj, 99bf11fbdbSTrond Myklebust struct nfs_netns_client, 100bf11fbdbSTrond Myklebust kobject); 101bf11fbdbSTrond Myklebust const char *old; 102bf11fbdbSTrond Myklebust char *p; 103bf11fbdbSTrond Myklebust size_t len; 104bf11fbdbSTrond Myklebust 105bf11fbdbSTrond Myklebust len = nfs_string_strip(buf, min_t(size_t, count, CONTAINER_ID_MAXLEN)); 106bf11fbdbSTrond Myklebust if (!len) 107bf11fbdbSTrond Myklebust return 0; 108bf11fbdbSTrond Myklebust p = kmemdup_nul(buf, len, GFP_KERNEL); 109bf11fbdbSTrond Myklebust if (!p) 110bf11fbdbSTrond Myklebust return -ENOMEM; 111094eca37STrond Myklebust old = rcu_dereference_protected(xchg(&c->identifier, (char __rcu *)p), 1); 112bf11fbdbSTrond Myklebust if (old) { 113bf11fbdbSTrond Myklebust synchronize_rcu(); 114bf11fbdbSTrond Myklebust kfree(old); 115bf11fbdbSTrond Myklebust } 116bf11fbdbSTrond Myklebust return count; 117bf11fbdbSTrond Myklebust } 118bf11fbdbSTrond Myklebust 119bf11fbdbSTrond Myklebust static void nfs_netns_client_release(struct kobject *kobj) 120bf11fbdbSTrond Myklebust { 121bf11fbdbSTrond Myklebust struct nfs_netns_client *c = container_of(kobj, 122bf11fbdbSTrond Myklebust struct nfs_netns_client, 123bf11fbdbSTrond Myklebust kobject); 124bf11fbdbSTrond Myklebust 125094eca37STrond Myklebust kfree(rcu_dereference_raw(c->identifier)); 126bf11fbdbSTrond Myklebust } 127bf11fbdbSTrond Myklebust 12802a476d9SGreg Kroah-Hartman static const void *nfs_netns_client_namespace(const struct kobject *kobj) 129bf11fbdbSTrond Myklebust { 130bf11fbdbSTrond Myklebust return container_of(kobj, struct nfs_netns_client, kobject)->net; 131bf11fbdbSTrond Myklebust } 132bf11fbdbSTrond Myklebust 133bf11fbdbSTrond Myklebust static struct kobj_attribute nfs_netns_client_id = __ATTR(identifier, 134bf11fbdbSTrond Myklebust 0644, nfs_netns_identifier_show, nfs_netns_identifier_store); 135bf11fbdbSTrond Myklebust 136bf11fbdbSTrond Myklebust static struct attribute *nfs_netns_client_attrs[] = { 137bf11fbdbSTrond Myklebust &nfs_netns_client_id.attr, 138bf11fbdbSTrond Myklebust NULL, 139bf11fbdbSTrond Myklebust }; 14001f34245SGreg Kroah-Hartman ATTRIBUTE_GROUPS(nfs_netns_client); 141bf11fbdbSTrond Myklebust 142bf11fbdbSTrond Myklebust static struct kobj_type nfs_netns_client_type = { 143bf11fbdbSTrond Myklebust .release = nfs_netns_client_release, 14401f34245SGreg Kroah-Hartman .default_groups = nfs_netns_client_groups, 145bf11fbdbSTrond Myklebust .sysfs_ops = &kobj_sysfs_ops, 146bf11fbdbSTrond Myklebust .namespace = nfs_netns_client_namespace, 147bf11fbdbSTrond Myklebust }; 148bf11fbdbSTrond Myklebust 149*e96f9268SBenjamin Coddington static void nfs_netns_object_release(struct kobject *kobj) 150*e96f9268SBenjamin Coddington { 151*e96f9268SBenjamin Coddington struct nfs_netns_client *c = container_of(kobj, 152*e96f9268SBenjamin Coddington struct nfs_netns_client, 153*e96f9268SBenjamin Coddington nfs_net_kobj); 154*e96f9268SBenjamin Coddington kfree(c); 155*e96f9268SBenjamin Coddington } 156*e96f9268SBenjamin Coddington 157*e96f9268SBenjamin Coddington static const void *nfs_netns_namespace(const struct kobject *kobj) 158*e96f9268SBenjamin Coddington { 159*e96f9268SBenjamin Coddington return container_of(kobj, struct nfs_netns_client, nfs_net_kobj)->net; 160*e96f9268SBenjamin Coddington } 161*e96f9268SBenjamin Coddington 162*e96f9268SBenjamin Coddington static struct kobj_type nfs_netns_object_type = { 163*e96f9268SBenjamin Coddington .release = nfs_netns_object_release, 164*e96f9268SBenjamin Coddington .sysfs_ops = &kobj_sysfs_ops, 165*e96f9268SBenjamin Coddington .namespace = nfs_netns_namespace, 166*e96f9268SBenjamin Coddington }; 167*e96f9268SBenjamin Coddington 168bf11fbdbSTrond Myklebust static struct nfs_netns_client *nfs_netns_client_alloc(struct kobject *parent, 169bf11fbdbSTrond Myklebust struct net *net) 170bf11fbdbSTrond Myklebust { 171bf11fbdbSTrond Myklebust struct nfs_netns_client *p; 172bf11fbdbSTrond Myklebust 173bf11fbdbSTrond Myklebust p = kzalloc(sizeof(*p), GFP_KERNEL); 174bf11fbdbSTrond Myklebust if (p) { 175bf11fbdbSTrond Myklebust p->net = net; 1768b18a2edSBenjamin Coddington p->kobject.kset = nfs_kset; 177*e96f9268SBenjamin Coddington p->nfs_net_kobj.kset = nfs_kset; 178*e96f9268SBenjamin Coddington 179*e96f9268SBenjamin Coddington if (kobject_init_and_add(&p->nfs_net_kobj, &nfs_netns_object_type, 180*e96f9268SBenjamin Coddington parent, "net") != 0) { 181*e96f9268SBenjamin Coddington kobject_put(&p->nfs_net_kobj); 182*e96f9268SBenjamin Coddington return NULL; 183*e96f9268SBenjamin Coddington } 184*e96f9268SBenjamin Coddington 185bf11fbdbSTrond Myklebust if (kobject_init_and_add(&p->kobject, &nfs_netns_client_type, 186*e96f9268SBenjamin Coddington &p->nfs_net_kobj, "nfs_client") == 0) 187bf11fbdbSTrond Myklebust return p; 188*e96f9268SBenjamin Coddington 189bf11fbdbSTrond Myklebust kobject_put(&p->kobject); 190bf11fbdbSTrond Myklebust } 191bf11fbdbSTrond Myklebust return NULL; 192bf11fbdbSTrond Myklebust } 193bf11fbdbSTrond Myklebust 194bf11fbdbSTrond Myklebust void nfs_netns_sysfs_setup(struct nfs_net *netns, struct net *net) 195bf11fbdbSTrond Myklebust { 196bf11fbdbSTrond Myklebust struct nfs_netns_client *clp; 197bf11fbdbSTrond Myklebust 198*e96f9268SBenjamin Coddington clp = nfs_netns_client_alloc(&nfs_kset->kobj, net); 199bf11fbdbSTrond Myklebust if (clp) { 200bf11fbdbSTrond Myklebust netns->nfs_client = clp; 201bf11fbdbSTrond Myklebust kobject_uevent(&clp->kobject, KOBJ_ADD); 202bf11fbdbSTrond Myklebust } 203bf11fbdbSTrond Myklebust } 204bf11fbdbSTrond Myklebust 205bf11fbdbSTrond Myklebust void nfs_netns_sysfs_destroy(struct nfs_net *netns) 206bf11fbdbSTrond Myklebust { 207bf11fbdbSTrond Myklebust struct nfs_netns_client *clp = netns->nfs_client; 208bf11fbdbSTrond Myklebust 209bf11fbdbSTrond Myklebust if (clp) { 210bf11fbdbSTrond Myklebust kobject_uevent(&clp->kobject, KOBJ_REMOVE); 211bf11fbdbSTrond Myklebust kobject_del(&clp->kobject); 212bf11fbdbSTrond Myklebust kobject_put(&clp->kobject); 213*e96f9268SBenjamin Coddington kobject_del(&clp->nfs_net_kobj); 214*e96f9268SBenjamin Coddington kobject_put(&clp->nfs_net_kobj); 215bf11fbdbSTrond Myklebust netns->nfs_client = NULL; 216bf11fbdbSTrond Myklebust } 217bf11fbdbSTrond Myklebust } 218