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 20 struct kobject *nfs_client_kobj; 21 static struct kset *nfs_client_kset; 22 23 static void nfs_netns_object_release(struct kobject *kobj) 24 { 25 kfree(kobj); 26 } 27 28 static 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 34 static 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 40 static 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 56 int 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 70 void nfs_sysfs_exit(void) 71 { 72 kobject_put(nfs_client_kobj); 73 kset_unregister(nfs_client_kset); 74 } 75 76 static 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 return scnprintf(buf, PAGE_SIZE, "%s\n", c->identifier); 83 } 84 85 /* Strip trailing '\n' */ 86 static size_t nfs_string_strip(const char *c, size_t len) 87 { 88 while (len > 0 && c[len-1] == '\n') 89 --len; 90 return len; 91 } 92 93 static ssize_t nfs_netns_identifier_store(struct kobject *kobj, 94 struct kobj_attribute *attr, 95 const char *buf, size_t count) 96 { 97 struct nfs_netns_client *c = container_of(kobj, 98 struct nfs_netns_client, 99 kobject); 100 const char *old; 101 char *p; 102 size_t len; 103 104 len = nfs_string_strip(buf, min_t(size_t, count, CONTAINER_ID_MAXLEN)); 105 if (!len) 106 return 0; 107 p = kmemdup_nul(buf, len, GFP_KERNEL); 108 if (!p) 109 return -ENOMEM; 110 old = xchg(&c->identifier, p); 111 if (old) { 112 synchronize_rcu(); 113 kfree(old); 114 } 115 return count; 116 } 117 118 static void nfs_netns_client_release(struct kobject *kobj) 119 { 120 struct nfs_netns_client *c = container_of(kobj, 121 struct nfs_netns_client, 122 kobject); 123 124 kfree(c->identifier); 125 kfree(c); 126 } 127 128 static const void *nfs_netns_client_namespace(struct kobject *kobj) 129 { 130 return container_of(kobj, struct nfs_netns_client, kobject)->net; 131 } 132 133 static struct kobj_attribute nfs_netns_client_id = __ATTR(identifier, 134 0644, nfs_netns_identifier_show, nfs_netns_identifier_store); 135 136 static struct attribute *nfs_netns_client_attrs[] = { 137 &nfs_netns_client_id.attr, 138 NULL, 139 }; 140 141 static struct kobj_type nfs_netns_client_type = { 142 .release = nfs_netns_client_release, 143 .default_attrs = nfs_netns_client_attrs, 144 .sysfs_ops = &kobj_sysfs_ops, 145 .namespace = nfs_netns_client_namespace, 146 }; 147 148 static struct nfs_netns_client *nfs_netns_client_alloc(struct kobject *parent, 149 struct net *net) 150 { 151 struct nfs_netns_client *p; 152 153 p = kzalloc(sizeof(*p), GFP_KERNEL); 154 if (p) { 155 p->net = net; 156 p->kobject.kset = nfs_client_kset; 157 if (kobject_init_and_add(&p->kobject, &nfs_netns_client_type, 158 parent, "nfs_client") == 0) 159 return p; 160 kobject_put(&p->kobject); 161 } 162 return NULL; 163 } 164 165 void nfs_netns_sysfs_setup(struct nfs_net *netns, struct net *net) 166 { 167 struct nfs_netns_client *clp; 168 169 clp = nfs_netns_client_alloc(nfs_client_kobj, net); 170 if (clp) { 171 netns->nfs_client = clp; 172 kobject_uevent(&clp->kobject, KOBJ_ADD); 173 } 174 } 175 176 void nfs_netns_sysfs_destroy(struct nfs_net *netns) 177 { 178 struct nfs_netns_client *clp = netns->nfs_client; 179 180 if (clp) { 181 kobject_uevent(&clp->kobject, KOBJ_REMOVE); 182 kobject_del(&clp->kobject); 183 kobject_put(&clp->kobject); 184 netns->nfs_client = NULL; 185 } 186 } 187