sysfs.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626
  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. #include <linux/sunrpc/xprtsock.h>
  9. #include "sysfs.h"
  10. struct xprt_addr {
  11. const char *addr;
  12. struct rcu_head rcu;
  13. };
  14. static void free_xprt_addr(struct rcu_head *head)
  15. {
  16. struct xprt_addr *addr = container_of(head, struct xprt_addr, rcu);
  17. kfree(addr->addr);
  18. kfree(addr);
  19. }
  20. static struct kset *rpc_sunrpc_kset;
  21. static struct kobject *rpc_sunrpc_client_kobj, *rpc_sunrpc_xprt_switch_kobj;
  22. static void rpc_sysfs_object_release(struct kobject *kobj)
  23. {
  24. kfree(kobj);
  25. }
  26. static const struct kobj_ns_type_operations *
  27. rpc_sysfs_object_child_ns_type(struct kobject *kobj)
  28. {
  29. return &net_ns_type_operations;
  30. }
  31. static struct kobj_type rpc_sysfs_object_type = {
  32. .release = rpc_sysfs_object_release,
  33. .sysfs_ops = &kobj_sysfs_ops,
  34. .child_ns_type = rpc_sysfs_object_child_ns_type,
  35. };
  36. static struct kobject *rpc_sysfs_object_alloc(const char *name,
  37. struct kset *kset,
  38. struct kobject *parent)
  39. {
  40. struct kobject *kobj;
  41. kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);
  42. if (kobj) {
  43. kobj->kset = kset;
  44. if (kobject_init_and_add(kobj, &rpc_sysfs_object_type,
  45. parent, "%s", name) == 0)
  46. return kobj;
  47. kobject_put(kobj);
  48. }
  49. return NULL;
  50. }
  51. static inline struct rpc_xprt *
  52. rpc_sysfs_xprt_kobj_get_xprt(struct kobject *kobj)
  53. {
  54. struct rpc_sysfs_xprt *x = container_of(kobj,
  55. struct rpc_sysfs_xprt, kobject);
  56. return xprt_get(x->xprt);
  57. }
  58. static inline struct rpc_xprt_switch *
  59. rpc_sysfs_xprt_kobj_get_xprt_switch(struct kobject *kobj)
  60. {
  61. struct rpc_sysfs_xprt *x = container_of(kobj,
  62. struct rpc_sysfs_xprt, kobject);
  63. return xprt_switch_get(x->xprt_switch);
  64. }
  65. static inline struct rpc_xprt_switch *
  66. rpc_sysfs_xprt_switch_kobj_get_xprt(struct kobject *kobj)
  67. {
  68. struct rpc_sysfs_xprt_switch *x = container_of(kobj,
  69. struct rpc_sysfs_xprt_switch, kobject);
  70. return xprt_switch_get(x->xprt_switch);
  71. }
  72. static ssize_t rpc_sysfs_xprt_dstaddr_show(struct kobject *kobj,
  73. struct kobj_attribute *attr,
  74. char *buf)
  75. {
  76. struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
  77. ssize_t ret;
  78. if (!xprt) {
  79. ret = sprintf(buf, "<closed>\n");
  80. goto out;
  81. }
  82. ret = sprintf(buf, "%s\n", xprt->address_strings[RPC_DISPLAY_ADDR]);
  83. xprt_put(xprt);
  84. out:
  85. return ret;
  86. }
  87. static ssize_t rpc_sysfs_xprt_srcaddr_show(struct kobject *kobj,
  88. struct kobj_attribute *attr,
  89. char *buf)
  90. {
  91. struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
  92. size_t buflen = PAGE_SIZE;
  93. ssize_t ret;
  94. if (!xprt || !xprt_connected(xprt)) {
  95. ret = sprintf(buf, "<closed>\n");
  96. } else if (xprt->ops->get_srcaddr) {
  97. ret = xprt->ops->get_srcaddr(xprt, buf, buflen);
  98. if (ret > 0) {
  99. if (ret < buflen - 1) {
  100. buf[ret] = '\n';
  101. ret++;
  102. buf[ret] = '\0';
  103. }
  104. } else
  105. ret = sprintf(buf, "<closed>\n");
  106. } else
  107. ret = sprintf(buf, "<not a socket>\n");
  108. xprt_put(xprt);
  109. return ret;
  110. }
  111. static ssize_t rpc_sysfs_xprt_info_show(struct kobject *kobj,
  112. struct kobj_attribute *attr, char *buf)
  113. {
  114. struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
  115. unsigned short srcport = 0;
  116. size_t buflen = PAGE_SIZE;
  117. ssize_t ret;
  118. if (!xprt || !xprt_connected(xprt)) {
  119. ret = sprintf(buf, "<closed>\n");
  120. goto out;
  121. }
  122. if (xprt->ops->get_srcport)
  123. srcport = xprt->ops->get_srcport(xprt);
  124. ret = snprintf(buf, buflen,
  125. "last_used=%lu\ncur_cong=%lu\ncong_win=%lu\n"
  126. "max_num_slots=%u\nmin_num_slots=%u\nnum_reqs=%u\n"
  127. "binding_q_len=%u\nsending_q_len=%u\npending_q_len=%u\n"
  128. "backlog_q_len=%u\nmain_xprt=%d\nsrc_port=%u\n"
  129. "tasks_queuelen=%ld\ndst_port=%s\n",
  130. xprt->last_used, xprt->cong, xprt->cwnd, xprt->max_reqs,
  131. xprt->min_reqs, xprt->num_reqs, xprt->binding.qlen,
  132. xprt->sending.qlen, xprt->pending.qlen,
  133. xprt->backlog.qlen, xprt->main, srcport,
  134. atomic_long_read(&xprt->queuelen),
  135. xprt->address_strings[RPC_DISPLAY_PORT]);
  136. out:
  137. xprt_put(xprt);
  138. return ret;
  139. }
  140. static ssize_t rpc_sysfs_xprt_state_show(struct kobject *kobj,
  141. struct kobj_attribute *attr,
  142. char *buf)
  143. {
  144. struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
  145. ssize_t ret;
  146. int locked, connected, connecting, close_wait, bound, binding,
  147. closing, congested, cwnd_wait, write_space, offline, remove;
  148. if (!(xprt && xprt->state)) {
  149. ret = sprintf(buf, "state=CLOSED\n");
  150. } else {
  151. locked = test_bit(XPRT_LOCKED, &xprt->state);
  152. connected = test_bit(XPRT_CONNECTED, &xprt->state);
  153. connecting = test_bit(XPRT_CONNECTING, &xprt->state);
  154. close_wait = test_bit(XPRT_CLOSE_WAIT, &xprt->state);
  155. bound = test_bit(XPRT_BOUND, &xprt->state);
  156. binding = test_bit(XPRT_BINDING, &xprt->state);
  157. closing = test_bit(XPRT_CLOSING, &xprt->state);
  158. congested = test_bit(XPRT_CONGESTED, &xprt->state);
  159. cwnd_wait = test_bit(XPRT_CWND_WAIT, &xprt->state);
  160. write_space = test_bit(XPRT_WRITE_SPACE, &xprt->state);
  161. offline = test_bit(XPRT_OFFLINE, &xprt->state);
  162. remove = test_bit(XPRT_REMOVE, &xprt->state);
  163. ret = sprintf(buf, "state=%s %s %s %s %s %s %s %s %s %s %s %s\n",
  164. locked ? "LOCKED" : "",
  165. connected ? "CONNECTED" : "",
  166. connecting ? "CONNECTING" : "",
  167. close_wait ? "CLOSE_WAIT" : "",
  168. bound ? "BOUND" : "",
  169. binding ? "BOUNDING" : "",
  170. closing ? "CLOSING" : "",
  171. congested ? "CONGESTED" : "",
  172. cwnd_wait ? "CWND_WAIT" : "",
  173. write_space ? "WRITE_SPACE" : "",
  174. offline ? "OFFLINE" : "",
  175. remove ? "REMOVE" : "");
  176. }
  177. xprt_put(xprt);
  178. return ret;
  179. }
  180. static ssize_t rpc_sysfs_xprt_switch_info_show(struct kobject *kobj,
  181. struct kobj_attribute *attr,
  182. char *buf)
  183. {
  184. struct rpc_xprt_switch *xprt_switch =
  185. rpc_sysfs_xprt_switch_kobj_get_xprt(kobj);
  186. ssize_t ret;
  187. if (!xprt_switch)
  188. return 0;
  189. ret = sprintf(buf, "num_xprts=%u\nnum_active=%u\n"
  190. "num_unique_destaddr=%u\nqueue_len=%ld\n",
  191. xprt_switch->xps_nxprts, xprt_switch->xps_nactive,
  192. xprt_switch->xps_nunique_destaddr_xprts,
  193. atomic_long_read(&xprt_switch->xps_queuelen));
  194. xprt_switch_put(xprt_switch);
  195. return ret;
  196. }
  197. static ssize_t rpc_sysfs_xprt_dstaddr_store(struct kobject *kobj,
  198. struct kobj_attribute *attr,
  199. const char *buf, size_t count)
  200. {
  201. struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
  202. struct sockaddr *saddr;
  203. char *dst_addr;
  204. int port;
  205. struct xprt_addr *saved_addr;
  206. size_t buf_len;
  207. if (!xprt)
  208. return 0;
  209. if (!(xprt->xprt_class->ident == XPRT_TRANSPORT_TCP ||
  210. xprt->xprt_class->ident == XPRT_TRANSPORT_RDMA)) {
  211. xprt_put(xprt);
  212. return -EOPNOTSUPP;
  213. }
  214. if (wait_on_bit_lock(&xprt->state, XPRT_LOCKED, TASK_KILLABLE)) {
  215. count = -EINTR;
  216. goto out_put;
  217. }
  218. saddr = (struct sockaddr *)&xprt->addr;
  219. port = rpc_get_port(saddr);
  220. /* buf_len is the len until the first occurence of either
  221. * '\n' or '\0'
  222. */
  223. buf_len = strcspn(buf, "\n");
  224. dst_addr = kstrndup(buf, buf_len, GFP_KERNEL);
  225. if (!dst_addr)
  226. goto out_err;
  227. saved_addr = kzalloc(sizeof(*saved_addr), GFP_KERNEL);
  228. if (!saved_addr)
  229. goto out_err_free;
  230. saved_addr->addr =
  231. rcu_dereference_raw(xprt->address_strings[RPC_DISPLAY_ADDR]);
  232. rcu_assign_pointer(xprt->address_strings[RPC_DISPLAY_ADDR], dst_addr);
  233. call_rcu(&saved_addr->rcu, free_xprt_addr);
  234. xprt->addrlen = rpc_pton(xprt->xprt_net, buf, buf_len, saddr,
  235. sizeof(*saddr));
  236. rpc_set_port(saddr, port);
  237. xprt_force_disconnect(xprt);
  238. out:
  239. xprt_release_write(xprt, NULL);
  240. out_put:
  241. xprt_put(xprt);
  242. return count;
  243. out_err_free:
  244. kfree(dst_addr);
  245. out_err:
  246. count = -ENOMEM;
  247. goto out;
  248. }
  249. static ssize_t rpc_sysfs_xprt_state_change(struct kobject *kobj,
  250. struct kobj_attribute *attr,
  251. const char *buf, size_t count)
  252. {
  253. struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
  254. int offline = 0, online = 0, remove = 0;
  255. struct rpc_xprt_switch *xps = rpc_sysfs_xprt_kobj_get_xprt_switch(kobj);
  256. if (!xprt || !xps) {
  257. count = 0;
  258. goto out_put;
  259. }
  260. if (!strncmp(buf, "offline", 7))
  261. offline = 1;
  262. else if (!strncmp(buf, "online", 6))
  263. online = 1;
  264. else if (!strncmp(buf, "remove", 6))
  265. remove = 1;
  266. else {
  267. count = -EINVAL;
  268. goto out_put;
  269. }
  270. if (wait_on_bit_lock(&xprt->state, XPRT_LOCKED, TASK_KILLABLE)) {
  271. count = -EINTR;
  272. goto out_put;
  273. }
  274. if (xprt->main) {
  275. count = -EINVAL;
  276. goto release_tasks;
  277. }
  278. if (offline) {
  279. xprt_set_offline_locked(xprt, xps);
  280. } else if (online) {
  281. xprt_set_online_locked(xprt, xps);
  282. } else if (remove) {
  283. if (test_bit(XPRT_OFFLINE, &xprt->state))
  284. xprt_delete_locked(xprt, xps);
  285. else
  286. count = -EINVAL;
  287. }
  288. release_tasks:
  289. xprt_release_write(xprt, NULL);
  290. out_put:
  291. xprt_put(xprt);
  292. xprt_switch_put(xps);
  293. return count;
  294. }
  295. int rpc_sysfs_init(void)
  296. {
  297. rpc_sunrpc_kset = kset_create_and_add("sunrpc", NULL, kernel_kobj);
  298. if (!rpc_sunrpc_kset)
  299. return -ENOMEM;
  300. rpc_sunrpc_client_kobj =
  301. rpc_sysfs_object_alloc("rpc-clients", rpc_sunrpc_kset, NULL);
  302. if (!rpc_sunrpc_client_kobj)
  303. goto err_client;
  304. rpc_sunrpc_xprt_switch_kobj =
  305. rpc_sysfs_object_alloc("xprt-switches", rpc_sunrpc_kset, NULL);
  306. if (!rpc_sunrpc_xprt_switch_kobj)
  307. goto err_switch;
  308. return 0;
  309. err_switch:
  310. kobject_put(rpc_sunrpc_client_kobj);
  311. rpc_sunrpc_client_kobj = NULL;
  312. err_client:
  313. kset_unregister(rpc_sunrpc_kset);
  314. rpc_sunrpc_kset = NULL;
  315. return -ENOMEM;
  316. }
  317. static void rpc_sysfs_client_release(struct kobject *kobj)
  318. {
  319. struct rpc_sysfs_client *c;
  320. c = container_of(kobj, struct rpc_sysfs_client, kobject);
  321. kfree(c);
  322. }
  323. static void rpc_sysfs_xprt_switch_release(struct kobject *kobj)
  324. {
  325. struct rpc_sysfs_xprt_switch *xprt_switch;
  326. xprt_switch = container_of(kobj, struct rpc_sysfs_xprt_switch, kobject);
  327. kfree(xprt_switch);
  328. }
  329. static void rpc_sysfs_xprt_release(struct kobject *kobj)
  330. {
  331. struct rpc_sysfs_xprt *xprt;
  332. xprt = container_of(kobj, struct rpc_sysfs_xprt, kobject);
  333. kfree(xprt);
  334. }
  335. static const void *rpc_sysfs_client_namespace(struct kobject *kobj)
  336. {
  337. return container_of(kobj, struct rpc_sysfs_client, kobject)->net;
  338. }
  339. static const void *rpc_sysfs_xprt_switch_namespace(struct kobject *kobj)
  340. {
  341. return container_of(kobj, struct rpc_sysfs_xprt_switch, kobject)->net;
  342. }
  343. static const void *rpc_sysfs_xprt_namespace(struct kobject *kobj)
  344. {
  345. return container_of(kobj, struct rpc_sysfs_xprt,
  346. kobject)->xprt->xprt_net;
  347. }
  348. static struct kobj_attribute rpc_sysfs_xprt_dstaddr = __ATTR(dstaddr,
  349. 0644, rpc_sysfs_xprt_dstaddr_show, rpc_sysfs_xprt_dstaddr_store);
  350. static struct kobj_attribute rpc_sysfs_xprt_srcaddr = __ATTR(srcaddr,
  351. 0644, rpc_sysfs_xprt_srcaddr_show, NULL);
  352. static struct kobj_attribute rpc_sysfs_xprt_info = __ATTR(xprt_info,
  353. 0444, rpc_sysfs_xprt_info_show, NULL);
  354. static struct kobj_attribute rpc_sysfs_xprt_change_state = __ATTR(xprt_state,
  355. 0644, rpc_sysfs_xprt_state_show, rpc_sysfs_xprt_state_change);
  356. static struct attribute *rpc_sysfs_xprt_attrs[] = {
  357. &rpc_sysfs_xprt_dstaddr.attr,
  358. &rpc_sysfs_xprt_srcaddr.attr,
  359. &rpc_sysfs_xprt_info.attr,
  360. &rpc_sysfs_xprt_change_state.attr,
  361. NULL,
  362. };
  363. ATTRIBUTE_GROUPS(rpc_sysfs_xprt);
  364. static struct kobj_attribute rpc_sysfs_xprt_switch_info =
  365. __ATTR(xprt_switch_info, 0444, rpc_sysfs_xprt_switch_info_show, NULL);
  366. static struct attribute *rpc_sysfs_xprt_switch_attrs[] = {
  367. &rpc_sysfs_xprt_switch_info.attr,
  368. NULL,
  369. };
  370. ATTRIBUTE_GROUPS(rpc_sysfs_xprt_switch);
  371. static struct kobj_type rpc_sysfs_client_type = {
  372. .release = rpc_sysfs_client_release,
  373. .sysfs_ops = &kobj_sysfs_ops,
  374. .namespace = rpc_sysfs_client_namespace,
  375. };
  376. static struct kobj_type rpc_sysfs_xprt_switch_type = {
  377. .release = rpc_sysfs_xprt_switch_release,
  378. .default_groups = rpc_sysfs_xprt_switch_groups,
  379. .sysfs_ops = &kobj_sysfs_ops,
  380. .namespace = rpc_sysfs_xprt_switch_namespace,
  381. };
  382. static struct kobj_type rpc_sysfs_xprt_type = {
  383. .release = rpc_sysfs_xprt_release,
  384. .default_groups = rpc_sysfs_xprt_groups,
  385. .sysfs_ops = &kobj_sysfs_ops,
  386. .namespace = rpc_sysfs_xprt_namespace,
  387. };
  388. void rpc_sysfs_exit(void)
  389. {
  390. kobject_put(rpc_sunrpc_client_kobj);
  391. kobject_put(rpc_sunrpc_xprt_switch_kobj);
  392. kset_unregister(rpc_sunrpc_kset);
  393. }
  394. static struct rpc_sysfs_client *rpc_sysfs_client_alloc(struct kobject *parent,
  395. struct net *net,
  396. int clid)
  397. {
  398. struct rpc_sysfs_client *p;
  399. p = kzalloc(sizeof(*p), GFP_KERNEL);
  400. if (p) {
  401. p->net = net;
  402. p->kobject.kset = rpc_sunrpc_kset;
  403. if (kobject_init_and_add(&p->kobject, &rpc_sysfs_client_type,
  404. parent, "clnt-%d", clid) == 0)
  405. return p;
  406. kobject_put(&p->kobject);
  407. }
  408. return NULL;
  409. }
  410. static struct rpc_sysfs_xprt_switch *
  411. rpc_sysfs_xprt_switch_alloc(struct kobject *parent,
  412. struct rpc_xprt_switch *xprt_switch,
  413. struct net *net,
  414. gfp_t gfp_flags)
  415. {
  416. struct rpc_sysfs_xprt_switch *p;
  417. p = kzalloc(sizeof(*p), gfp_flags);
  418. if (p) {
  419. p->net = net;
  420. p->kobject.kset = rpc_sunrpc_kset;
  421. if (kobject_init_and_add(&p->kobject,
  422. &rpc_sysfs_xprt_switch_type,
  423. parent, "switch-%d",
  424. xprt_switch->xps_id) == 0)
  425. return p;
  426. kobject_put(&p->kobject);
  427. }
  428. return NULL;
  429. }
  430. static struct rpc_sysfs_xprt *rpc_sysfs_xprt_alloc(struct kobject *parent,
  431. struct rpc_xprt *xprt,
  432. gfp_t gfp_flags)
  433. {
  434. struct rpc_sysfs_xprt *p;
  435. p = kzalloc(sizeof(*p), gfp_flags);
  436. if (!p)
  437. goto out;
  438. p->kobject.kset = rpc_sunrpc_kset;
  439. if (kobject_init_and_add(&p->kobject, &rpc_sysfs_xprt_type,
  440. parent, "xprt-%d-%s", xprt->id,
  441. xprt->address_strings[RPC_DISPLAY_PROTO]) == 0)
  442. return p;
  443. kobject_put(&p->kobject);
  444. out:
  445. return NULL;
  446. }
  447. void rpc_sysfs_client_setup(struct rpc_clnt *clnt,
  448. struct rpc_xprt_switch *xprt_switch,
  449. struct net *net)
  450. {
  451. struct rpc_sysfs_client *rpc_client;
  452. struct rpc_sysfs_xprt_switch *xswitch =
  453. (struct rpc_sysfs_xprt_switch *)xprt_switch->xps_sysfs;
  454. if (!xswitch)
  455. return;
  456. rpc_client = rpc_sysfs_client_alloc(rpc_sunrpc_client_kobj,
  457. net, clnt->cl_clid);
  458. if (rpc_client) {
  459. char name[] = "switch";
  460. int ret;
  461. clnt->cl_sysfs = rpc_client;
  462. rpc_client->clnt = clnt;
  463. rpc_client->xprt_switch = xprt_switch;
  464. kobject_uevent(&rpc_client->kobject, KOBJ_ADD);
  465. ret = sysfs_create_link_nowarn(&rpc_client->kobject,
  466. &xswitch->kobject, name);
  467. if (ret)
  468. pr_warn("can't create link to %s in sysfs (%d)\n",
  469. name, ret);
  470. }
  471. }
  472. void rpc_sysfs_xprt_switch_setup(struct rpc_xprt_switch *xprt_switch,
  473. struct rpc_xprt *xprt,
  474. gfp_t gfp_flags)
  475. {
  476. struct rpc_sysfs_xprt_switch *rpc_xprt_switch;
  477. struct net *net;
  478. if (xprt_switch->xps_net)
  479. net = xprt_switch->xps_net;
  480. else
  481. net = xprt->xprt_net;
  482. rpc_xprt_switch =
  483. rpc_sysfs_xprt_switch_alloc(rpc_sunrpc_xprt_switch_kobj,
  484. xprt_switch, net, gfp_flags);
  485. if (rpc_xprt_switch) {
  486. xprt_switch->xps_sysfs = rpc_xprt_switch;
  487. rpc_xprt_switch->xprt_switch = xprt_switch;
  488. rpc_xprt_switch->xprt = xprt;
  489. kobject_uevent(&rpc_xprt_switch->kobject, KOBJ_ADD);
  490. } else {
  491. xprt_switch->xps_sysfs = NULL;
  492. }
  493. }
  494. void rpc_sysfs_xprt_setup(struct rpc_xprt_switch *xprt_switch,
  495. struct rpc_xprt *xprt,
  496. gfp_t gfp_flags)
  497. {
  498. struct rpc_sysfs_xprt *rpc_xprt;
  499. struct rpc_sysfs_xprt_switch *switch_obj =
  500. (struct rpc_sysfs_xprt_switch *)xprt_switch->xps_sysfs;
  501. if (!switch_obj)
  502. return;
  503. rpc_xprt = rpc_sysfs_xprt_alloc(&switch_obj->kobject, xprt, gfp_flags);
  504. if (rpc_xprt) {
  505. xprt->xprt_sysfs = rpc_xprt;
  506. rpc_xprt->xprt = xprt;
  507. rpc_xprt->xprt_switch = xprt_switch;
  508. kobject_uevent(&rpc_xprt->kobject, KOBJ_ADD);
  509. }
  510. }
  511. void rpc_sysfs_client_destroy(struct rpc_clnt *clnt)
  512. {
  513. struct rpc_sysfs_client *rpc_client = clnt->cl_sysfs;
  514. if (rpc_client) {
  515. char name[] = "switch";
  516. sysfs_remove_link(&rpc_client->kobject, name);
  517. kobject_uevent(&rpc_client->kobject, KOBJ_REMOVE);
  518. kobject_del(&rpc_client->kobject);
  519. kobject_put(&rpc_client->kobject);
  520. clnt->cl_sysfs = NULL;
  521. }
  522. }
  523. void rpc_sysfs_xprt_switch_destroy(struct rpc_xprt_switch *xprt_switch)
  524. {
  525. struct rpc_sysfs_xprt_switch *rpc_xprt_switch = xprt_switch->xps_sysfs;
  526. if (rpc_xprt_switch) {
  527. kobject_uevent(&rpc_xprt_switch->kobject, KOBJ_REMOVE);
  528. kobject_del(&rpc_xprt_switch->kobject);
  529. kobject_put(&rpc_xprt_switch->kobject);
  530. xprt_switch->xps_sysfs = NULL;
  531. }
  532. }
  533. void rpc_sysfs_xprt_destroy(struct rpc_xprt *xprt)
  534. {
  535. struct rpc_sysfs_xprt *rpc_xprt = xprt->xprt_sysfs;
  536. if (rpc_xprt) {
  537. kobject_uevent(&rpc_xprt->kobject, KOBJ_REMOVE);
  538. kobject_del(&rpc_xprt->kobject);
  539. kobject_put(&rpc_xprt->kobject);
  540. xprt->xprt_sysfs = NULL;
  541. }
  542. }