1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (c) 2020 Anna Schumaker <Anna.Schumaker@Netapp.com> 4 */ 5 #include <linux/sunrpc/clnt.h> 6 #include <linux/kobject.h> 7 #include <linux/sunrpc/addr.h> 8 9 #include "sysfs.h" 10 11 struct xprt_addr { 12 const char *addr; 13 struct rcu_head rcu; 14 }; 15 16 static void free_xprt_addr(struct rcu_head *head) 17 { 18 struct xprt_addr *addr = container_of(head, struct xprt_addr, rcu); 19 20 kfree(addr->addr); 21 kfree(addr); 22 } 23 24 static struct kset *rpc_sunrpc_kset; 25 static struct kobject *rpc_sunrpc_client_kobj, *rpc_sunrpc_xprt_switch_kobj; 26 27 static void rpc_sysfs_object_release(struct kobject *kobj) 28 { 29 kfree(kobj); 30 } 31 32 static const struct kobj_ns_type_operations * 33 rpc_sysfs_object_child_ns_type(struct kobject *kobj) 34 { 35 return &net_ns_type_operations; 36 } 37 38 static struct kobj_type rpc_sysfs_object_type = { 39 .release = rpc_sysfs_object_release, 40 .sysfs_ops = &kobj_sysfs_ops, 41 .child_ns_type = rpc_sysfs_object_child_ns_type, 42 }; 43 44 static struct kobject *rpc_sysfs_object_alloc(const char *name, 45 struct kset *kset, 46 struct kobject *parent) 47 { 48 struct kobject *kobj; 49 50 kobj = kzalloc(sizeof(*kobj), GFP_KERNEL); 51 if (kobj) { 52 kobj->kset = kset; 53 if (kobject_init_and_add(kobj, &rpc_sysfs_object_type, 54 parent, "%s", name) == 0) 55 return kobj; 56 kobject_put(kobj); 57 } 58 return NULL; 59 } 60 61 static inline struct rpc_xprt * 62 rpc_sysfs_xprt_kobj_get_xprt(struct kobject *kobj) 63 { 64 struct rpc_sysfs_xprt *x = container_of(kobj, 65 struct rpc_sysfs_xprt, kobject); 66 67 return xprt_get(x->xprt); 68 } 69 70 static ssize_t rpc_sysfs_xprt_dstaddr_show(struct kobject *kobj, 71 struct kobj_attribute *attr, 72 char *buf) 73 { 74 struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj); 75 ssize_t ret; 76 77 if (!xprt) 78 return 0; 79 ret = sprintf(buf, "%s\n", xprt->address_strings[RPC_DISPLAY_ADDR]); 80 xprt_put(xprt); 81 return ret + 1; 82 } 83 84 static ssize_t rpc_sysfs_xprt_info_show(struct kobject *kobj, 85 struct kobj_attribute *attr, 86 char *buf) 87 { 88 struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj); 89 ssize_t ret; 90 91 if (!xprt) 92 return 0; 93 94 ret = sprintf(buf, "last_used=%lu\ncur_cong=%lu\ncong_win=%lu\n" 95 "max_num_slots=%u\nmin_num_slots=%u\nnum_reqs=%u\n" 96 "binding_q_len=%u\nsending_q_len=%u\npending_q_len=%u\n" 97 "backlog_q_len=%u\n", xprt->last_used, xprt->cong, 98 xprt->cwnd, xprt->max_reqs, xprt->min_reqs, 99 xprt->num_reqs, xprt->binding.qlen, xprt->sending.qlen, 100 xprt->pending.qlen, xprt->backlog.qlen); 101 xprt_put(xprt); 102 return ret + 1; 103 } 104 105 static ssize_t rpc_sysfs_xprt_dstaddr_store(struct kobject *kobj, 106 struct kobj_attribute *attr, 107 const char *buf, size_t count) 108 { 109 struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj); 110 struct sockaddr *saddr; 111 char *dst_addr; 112 int port; 113 struct xprt_addr *saved_addr; 114 size_t buf_len; 115 116 if (!xprt) 117 return 0; 118 if (!(xprt->xprt_class->ident == XPRT_TRANSPORT_TCP || 119 xprt->xprt_class->ident == XPRT_TRANSPORT_RDMA)) { 120 xprt_put(xprt); 121 return -EOPNOTSUPP; 122 } 123 124 if (wait_on_bit_lock(&xprt->state, XPRT_LOCKED, TASK_KILLABLE)) { 125 count = -EINTR; 126 goto out_put; 127 } 128 saddr = (struct sockaddr *)&xprt->addr; 129 port = rpc_get_port(saddr); 130 131 /* buf_len is the len until the first occurence of either 132 * '\n' or '\0' 133 */ 134 buf_len = strcspn(buf, "\n"); 135 136 dst_addr = kstrndup(buf, buf_len, GFP_KERNEL); 137 if (!dst_addr) 138 goto out_err; 139 saved_addr = kzalloc(sizeof(*saved_addr), GFP_KERNEL); 140 if (!saved_addr) 141 goto out_err_free; 142 saved_addr->addr = 143 rcu_dereference_raw(xprt->address_strings[RPC_DISPLAY_ADDR]); 144 rcu_assign_pointer(xprt->address_strings[RPC_DISPLAY_ADDR], dst_addr); 145 call_rcu(&saved_addr->rcu, free_xprt_addr); 146 xprt->addrlen = rpc_pton(xprt->xprt_net, buf, buf_len, saddr, 147 sizeof(*saddr)); 148 rpc_set_port(saddr, port); 149 150 xprt_force_disconnect(xprt); 151 out: 152 xprt_release_write(xprt, NULL); 153 out_put: 154 xprt_put(xprt); 155 return count; 156 out_err_free: 157 kfree(dst_addr); 158 out_err: 159 count = -ENOMEM; 160 goto out; 161 } 162 163 int rpc_sysfs_init(void) 164 { 165 rpc_sunrpc_kset = kset_create_and_add("sunrpc", NULL, kernel_kobj); 166 if (!rpc_sunrpc_kset) 167 return -ENOMEM; 168 rpc_sunrpc_client_kobj = 169 rpc_sysfs_object_alloc("rpc-clients", rpc_sunrpc_kset, NULL); 170 if (!rpc_sunrpc_client_kobj) 171 goto err_client; 172 rpc_sunrpc_xprt_switch_kobj = 173 rpc_sysfs_object_alloc("xprt-switches", rpc_sunrpc_kset, NULL); 174 if (!rpc_sunrpc_xprt_switch_kobj) 175 goto err_switch; 176 return 0; 177 err_switch: 178 kobject_put(rpc_sunrpc_client_kobj); 179 rpc_sunrpc_client_kobj = NULL; 180 err_client: 181 kset_unregister(rpc_sunrpc_kset); 182 rpc_sunrpc_kset = NULL; 183 return -ENOMEM; 184 } 185 186 static void rpc_sysfs_client_release(struct kobject *kobj) 187 { 188 struct rpc_sysfs_client *c; 189 190 c = container_of(kobj, struct rpc_sysfs_client, kobject); 191 kfree(c); 192 } 193 194 static void rpc_sysfs_xprt_switch_release(struct kobject *kobj) 195 { 196 struct rpc_sysfs_xprt_switch *xprt_switch; 197 198 xprt_switch = container_of(kobj, struct rpc_sysfs_xprt_switch, kobject); 199 kfree(xprt_switch); 200 } 201 202 static void rpc_sysfs_xprt_release(struct kobject *kobj) 203 { 204 struct rpc_sysfs_xprt *xprt; 205 206 xprt = container_of(kobj, struct rpc_sysfs_xprt, kobject); 207 kfree(xprt); 208 } 209 210 static const void *rpc_sysfs_client_namespace(struct kobject *kobj) 211 { 212 return container_of(kobj, struct rpc_sysfs_client, kobject)->net; 213 } 214 215 static const void *rpc_sysfs_xprt_switch_namespace(struct kobject *kobj) 216 { 217 return container_of(kobj, struct rpc_sysfs_xprt_switch, kobject)->net; 218 } 219 220 static const void *rpc_sysfs_xprt_namespace(struct kobject *kobj) 221 { 222 return container_of(kobj, struct rpc_sysfs_xprt, 223 kobject)->xprt->xprt_net; 224 } 225 226 static struct kobj_attribute rpc_sysfs_xprt_dstaddr = __ATTR(dstaddr, 227 0644, rpc_sysfs_xprt_dstaddr_show, rpc_sysfs_xprt_dstaddr_store); 228 229 static struct kobj_attribute rpc_sysfs_xprt_info = __ATTR(xprt_info, 230 0444, rpc_sysfs_xprt_info_show, NULL); 231 232 static struct attribute *rpc_sysfs_xprt_attrs[] = { 233 &rpc_sysfs_xprt_dstaddr.attr, 234 &rpc_sysfs_xprt_info.attr, 235 NULL, 236 }; 237 238 static struct kobj_type rpc_sysfs_client_type = { 239 .release = rpc_sysfs_client_release, 240 .sysfs_ops = &kobj_sysfs_ops, 241 .namespace = rpc_sysfs_client_namespace, 242 }; 243 244 static struct kobj_type rpc_sysfs_xprt_switch_type = { 245 .release = rpc_sysfs_xprt_switch_release, 246 .sysfs_ops = &kobj_sysfs_ops, 247 .namespace = rpc_sysfs_xprt_switch_namespace, 248 }; 249 250 static struct kobj_type rpc_sysfs_xprt_type = { 251 .release = rpc_sysfs_xprt_release, 252 .default_attrs = rpc_sysfs_xprt_attrs, 253 .sysfs_ops = &kobj_sysfs_ops, 254 .namespace = rpc_sysfs_xprt_namespace, 255 }; 256 257 void rpc_sysfs_exit(void) 258 { 259 kobject_put(rpc_sunrpc_client_kobj); 260 kobject_put(rpc_sunrpc_xprt_switch_kobj); 261 kset_unregister(rpc_sunrpc_kset); 262 } 263 264 static struct rpc_sysfs_client *rpc_sysfs_client_alloc(struct kobject *parent, 265 struct net *net, 266 int clid) 267 { 268 struct rpc_sysfs_client *p; 269 270 p = kzalloc(sizeof(*p), GFP_KERNEL); 271 if (p) { 272 p->net = net; 273 p->kobject.kset = rpc_sunrpc_kset; 274 if (kobject_init_and_add(&p->kobject, &rpc_sysfs_client_type, 275 parent, "clnt-%d", clid) == 0) 276 return p; 277 kobject_put(&p->kobject); 278 } 279 return NULL; 280 } 281 282 static struct rpc_sysfs_xprt_switch * 283 rpc_sysfs_xprt_switch_alloc(struct kobject *parent, 284 struct rpc_xprt_switch *xprt_switch, 285 struct net *net, 286 gfp_t gfp_flags) 287 { 288 struct rpc_sysfs_xprt_switch *p; 289 290 p = kzalloc(sizeof(*p), gfp_flags); 291 if (p) { 292 p->net = net; 293 p->kobject.kset = rpc_sunrpc_kset; 294 if (kobject_init_and_add(&p->kobject, 295 &rpc_sysfs_xprt_switch_type, 296 parent, "switch-%d", 297 xprt_switch->xps_id) == 0) 298 return p; 299 kobject_put(&p->kobject); 300 } 301 return NULL; 302 } 303 304 static struct rpc_sysfs_xprt *rpc_sysfs_xprt_alloc(struct kobject *parent, 305 struct rpc_xprt *xprt, 306 gfp_t gfp_flags) 307 { 308 struct rpc_sysfs_xprt *p; 309 310 p = kzalloc(sizeof(*p), gfp_flags); 311 if (!p) 312 goto out; 313 p->kobject.kset = rpc_sunrpc_kset; 314 if (kobject_init_and_add(&p->kobject, &rpc_sysfs_xprt_type, 315 parent, "xprt-%d-%s", xprt->id, 316 xprt->address_strings[RPC_DISPLAY_PROTO]) == 0) 317 return p; 318 kobject_put(&p->kobject); 319 out: 320 return NULL; 321 } 322 323 void rpc_sysfs_client_setup(struct rpc_clnt *clnt, 324 struct rpc_xprt_switch *xprt_switch, 325 struct net *net) 326 { 327 struct rpc_sysfs_client *rpc_client; 328 329 rpc_client = rpc_sysfs_client_alloc(rpc_sunrpc_client_kobj, 330 net, clnt->cl_clid); 331 if (rpc_client) { 332 char name[] = "switch"; 333 struct rpc_sysfs_xprt_switch *xswitch = 334 (struct rpc_sysfs_xprt_switch *)xprt_switch->xps_sysfs; 335 int ret; 336 337 clnt->cl_sysfs = rpc_client; 338 rpc_client->clnt = clnt; 339 rpc_client->xprt_switch = xprt_switch; 340 kobject_uevent(&rpc_client->kobject, KOBJ_ADD); 341 ret = sysfs_create_link_nowarn(&rpc_client->kobject, 342 &xswitch->kobject, name); 343 if (ret) 344 pr_warn("can't create link to %s in sysfs (%d)\n", 345 name, ret); 346 } 347 } 348 349 void rpc_sysfs_xprt_switch_setup(struct rpc_xprt_switch *xprt_switch, 350 struct rpc_xprt *xprt, 351 gfp_t gfp_flags) 352 { 353 struct rpc_sysfs_xprt_switch *rpc_xprt_switch; 354 struct net *net; 355 356 if (xprt_switch->xps_net) 357 net = xprt_switch->xps_net; 358 else 359 net = xprt->xprt_net; 360 rpc_xprt_switch = 361 rpc_sysfs_xprt_switch_alloc(rpc_sunrpc_xprt_switch_kobj, 362 xprt_switch, net, gfp_flags); 363 if (rpc_xprt_switch) { 364 xprt_switch->xps_sysfs = rpc_xprt_switch; 365 rpc_xprt_switch->xprt_switch = xprt_switch; 366 rpc_xprt_switch->xprt = xprt; 367 kobject_uevent(&rpc_xprt_switch->kobject, KOBJ_ADD); 368 } 369 } 370 371 void rpc_sysfs_xprt_setup(struct rpc_xprt_switch *xprt_switch, 372 struct rpc_xprt *xprt, 373 gfp_t gfp_flags) 374 { 375 struct rpc_sysfs_xprt *rpc_xprt; 376 struct rpc_sysfs_xprt_switch *switch_obj = 377 (struct rpc_sysfs_xprt_switch *)xprt_switch->xps_sysfs; 378 379 rpc_xprt = rpc_sysfs_xprt_alloc(&switch_obj->kobject, xprt, gfp_flags); 380 if (rpc_xprt) { 381 xprt->xprt_sysfs = rpc_xprt; 382 rpc_xprt->xprt = xprt; 383 kobject_uevent(&rpc_xprt->kobject, KOBJ_ADD); 384 } 385 } 386 387 void rpc_sysfs_client_destroy(struct rpc_clnt *clnt) 388 { 389 struct rpc_sysfs_client *rpc_client = clnt->cl_sysfs; 390 391 if (rpc_client) { 392 char name[] = "switch"; 393 394 sysfs_remove_link(&rpc_client->kobject, name); 395 kobject_uevent(&rpc_client->kobject, KOBJ_REMOVE); 396 kobject_del(&rpc_client->kobject); 397 kobject_put(&rpc_client->kobject); 398 clnt->cl_sysfs = NULL; 399 } 400 } 401 402 void rpc_sysfs_xprt_switch_destroy(struct rpc_xprt_switch *xprt_switch) 403 { 404 struct rpc_sysfs_xprt_switch *rpc_xprt_switch = xprt_switch->xps_sysfs; 405 406 if (rpc_xprt_switch) { 407 kobject_uevent(&rpc_xprt_switch->kobject, KOBJ_REMOVE); 408 kobject_del(&rpc_xprt_switch->kobject); 409 kobject_put(&rpc_xprt_switch->kobject); 410 xprt_switch->xps_sysfs = NULL; 411 } 412 } 413 414 void rpc_sysfs_xprt_destroy(struct rpc_xprt *xprt) 415 { 416 struct rpc_sysfs_xprt *rpc_xprt = xprt->xprt_sysfs; 417 418 if (rpc_xprt) { 419 kobject_uevent(&rpc_xprt->kobject, KOBJ_REMOVE); 420 kobject_del(&rpc_xprt->kobject); 421 kobject_put(&rpc_xprt->kobject); 422 xprt->xprt_sysfs = NULL; 423 } 424 } 425