Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

NFS: Add sysfs support for per-container identifier

In order to identify containers to the NFS client, we add a per-net
sysfs attribute that udev can fill with the appropriate identifier.
The identifier could be a unique hostname, but in most cases it
will probably be a persisted uuid.

Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>

+135
+4
fs/nfs/client.c
··· 49 49 #include "pnfs.h" 50 50 #include "nfs.h" 51 51 #include "netns.h" 52 + #include "sysfs.h" 52 53 53 54 #define NFSDBG_FACILITY NFSDBG_CLIENT 54 55 ··· 1073 1072 #endif 1074 1073 spin_lock_init(&nn->nfs_client_lock); 1075 1074 nn->boot_time = ktime_get_real(); 1075 + 1076 + nfs_netns_sysfs_setup(nn, net); 1076 1077 } 1077 1078 1078 1079 void nfs_clients_exit(struct net *net) 1079 1080 { 1080 1081 struct nfs_net *nn = net_generic(net, nfs_net_id); 1081 1082 1083 + nfs_netns_sysfs_destroy(nn); 1082 1084 nfs_cleanup_cb_ident_idr(net); 1083 1085 WARN_ON_ONCE(!list_empty(&nn->nfs_client_list)); 1084 1086 WARN_ON_ONCE(!list_empty(&nn->nfs_volume_list));
+3
fs/nfs/netns.h
··· 15 15 uint32_t major, minor; 16 16 }; 17 17 18 + struct nfs_netns_client; 19 + 18 20 struct nfs_net { 19 21 struct cache_detail *nfs_dns_resolve; 20 22 struct rpc_pipe *bl_device_pipe; ··· 31 29 unsigned short nfs_callback_tcpport6; 32 30 int cb_users[NFS4_MAX_MINOR_VERSION + 1]; 33 31 #endif 32 + struct nfs_netns_client *nfs_client; 34 33 spinlock_t nfs_client_lock; 35 34 ktime_t boot_time; 36 35 #ifdef CONFIG_PROC_FS
+118
fs/nfs/sysfs.c
··· 9 9 #include <linux/fs.h> 10 10 #include <linux/slab.h> 11 11 #include <linux/netdevice.h> 12 + #include <linux/string.h> 13 + #include <linux/nfs_fs.h> 14 + #include <linux/rcupdate.h> 12 15 16 + #include "nfs4_fs.h" 17 + #include "netns.h" 13 18 #include "sysfs.h" 14 19 15 20 struct kobject *nfs_client_kobj; ··· 71 66 { 72 67 kobject_put(nfs_client_kobj); 73 68 kset_unregister(nfs_client_kset); 69 + } 70 + 71 + static ssize_t nfs_netns_identifier_show(struct kobject *kobj, 72 + struct kobj_attribute *attr, char *buf) 73 + { 74 + struct nfs_netns_client *c = container_of(kobj, 75 + struct nfs_netns_client, 76 + kobject); 77 + return scnprintf(buf, PAGE_SIZE, "%s\n", c->identifier); 78 + } 79 + 80 + /* Strip trailing '\n' */ 81 + static size_t nfs_string_strip(const char *c, size_t len) 82 + { 83 + while (len > 0 && c[len-1] == '\n') 84 + --len; 85 + return len; 86 + } 87 + 88 + static ssize_t nfs_netns_identifier_store(struct kobject *kobj, 89 + struct kobj_attribute *attr, 90 + const char *buf, size_t count) 91 + { 92 + struct nfs_netns_client *c = container_of(kobj, 93 + struct nfs_netns_client, 94 + kobject); 95 + const char *old; 96 + char *p; 97 + size_t len; 98 + 99 + len = nfs_string_strip(buf, min_t(size_t, count, CONTAINER_ID_MAXLEN)); 100 + if (!len) 101 + return 0; 102 + p = kmemdup_nul(buf, len, GFP_KERNEL); 103 + if (!p) 104 + return -ENOMEM; 105 + old = xchg(&c->identifier, p); 106 + if (old) { 107 + synchronize_rcu(); 108 + kfree(old); 109 + } 110 + return count; 111 + } 112 + 113 + static void nfs_netns_client_release(struct kobject *kobj) 114 + { 115 + struct nfs_netns_client *c = container_of(kobj, 116 + struct nfs_netns_client, 117 + kobject); 118 + 119 + if (c->identifier) 120 + kfree(c->identifier); 121 + kfree(c); 122 + } 123 + 124 + static const void *nfs_netns_client_namespace(struct kobject *kobj) 125 + { 126 + return container_of(kobj, struct nfs_netns_client, kobject)->net; 127 + } 128 + 129 + static struct kobj_attribute nfs_netns_client_id = __ATTR(identifier, 130 + 0644, nfs_netns_identifier_show, nfs_netns_identifier_store); 131 + 132 + static struct attribute *nfs_netns_client_attrs[] = { 133 + &nfs_netns_client_id.attr, 134 + NULL, 135 + }; 136 + 137 + static struct kobj_type nfs_netns_client_type = { 138 + .release = nfs_netns_client_release, 139 + .default_attrs = nfs_netns_client_attrs, 140 + .sysfs_ops = &kobj_sysfs_ops, 141 + .namespace = nfs_netns_client_namespace, 142 + }; 143 + 144 + static struct nfs_netns_client *nfs_netns_client_alloc(struct kobject *parent, 145 + struct net *net) 146 + { 147 + struct nfs_netns_client *p; 148 + 149 + p = kzalloc(sizeof(*p), GFP_KERNEL); 150 + if (p) { 151 + p->net = net; 152 + p->kobject.kset = nfs_client_kset; 153 + if (kobject_init_and_add(&p->kobject, &nfs_netns_client_type, 154 + parent, "nfs_client") == 0) 155 + return p; 156 + kobject_put(&p->kobject); 157 + } 158 + return NULL; 159 + } 160 + 161 + void nfs_netns_sysfs_setup(struct nfs_net *netns, struct net *net) 162 + { 163 + struct nfs_netns_client *clp; 164 + 165 + clp = nfs_netns_client_alloc(nfs_client_kobj, net); 166 + if (clp) { 167 + netns->nfs_client = clp; 168 + kobject_uevent(&clp->kobject, KOBJ_ADD); 169 + } 170 + } 171 + 172 + void nfs_netns_sysfs_destroy(struct nfs_net *netns) 173 + { 174 + struct nfs_netns_client *clp = netns->nfs_client; 175 + 176 + if (clp) { 177 + kobject_uevent(&clp->kobject, KOBJ_REMOVE); 178 + kobject_del(&clp->kobject); 179 + kobject_put(&clp->kobject); 180 + netns->nfs_client = NULL; 181 + } 74 182 }
+10
fs/nfs/sysfs.h
··· 6 6 #ifndef __NFS_SYSFS_H 7 7 #define __NFS_SYSFS_H 8 8 9 + #define CONTAINER_ID_MAXLEN (64) 10 + 11 + struct nfs_netns_client { 12 + struct kobject kobject; 13 + struct net *net; 14 + const char *identifier; 15 + }; 9 16 10 17 extern struct kobject *nfs_client_kobj; 11 18 12 19 extern int nfs_sysfs_init(void); 13 20 extern void nfs_sysfs_exit(void); 21 + 22 + void nfs_netns_sysfs_setup(struct nfs_net *netns, struct net *net); 23 + void nfs_netns_sysfs_destroy(struct nfs_net *netns); 14 24 15 25 #endif