sysfs.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627
  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(const struct kobject *kobj)
  28. {
  29. return &net_ns_type_operations;
  30. }
  31. static const 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_TCP_TLS ||
  211. xprt->xprt_class->ident == XPRT_TRANSPORT_RDMA)) {
  212. xprt_put(xprt);
  213. return -EOPNOTSUPP;
  214. }
  215. if (wait_on_bit_lock(&xprt->state, XPRT_LOCKED, TASK_KILLABLE)) {
  216. count = -EINTR;
  217. goto out_put;
  218. }
  219. saddr = (struct sockaddr *)&xprt->addr;
  220. port = rpc_get_port(saddr);
  221. /* buf_len is the len until the first occurence of either
  222. * '\n' or '\0'
  223. */
  224. buf_len = strcspn(buf, "\n");
  225. dst_addr = kstrndup(buf, buf_len, GFP_KERNEL);
  226. if (!dst_addr)
  227. goto out_err;
  228. saved_addr = kzalloc(sizeof(*saved_addr), GFP_KERNEL);
  229. if (!saved_addr)
  230. goto out_err_free;
  231. saved_addr->addr =
  232. rcu_dereference_raw(xprt->address_strings[RPC_DISPLAY_ADDR]);
  233. rcu_assign_pointer(xprt->address_strings[RPC_DISPLAY_ADDR], dst_addr);
  234. call_rcu(&saved_addr->rcu, free_xprt_addr);
  235. xprt->addrlen = rpc_pton(xprt->xprt_net, buf, buf_len, saddr,
  236. sizeof(*saddr));
  237. rpc_set_port(saddr, port);
  238. xprt_force_disconnect(xprt);
  239. out:
  240. xprt_release_write(xprt, NULL);
  241. out_put:
  242. xprt_put(xprt);
  243. return count;
  244. out_err_free:
  245. kfree(dst_addr);
  246. out_err:
  247. count = -ENOMEM;
  248. goto out;
  249. }
  250. static ssize_t rpc_sysfs_xprt_state_change(struct kobject *kobj,
  251. struct kobj_attribute *attr,
  252. const char *buf, size_t count)
  253. {
  254. struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
  255. int offline = 0, online = 0, remove = 0;
  256. struct rpc_xprt_switch *xps = rpc_sysfs_xprt_kobj_get_xprt_switch(kobj);
  257. if (!xprt || !xps) {
  258. count = 0;
  259. goto out_put;
  260. }
  261. if (!strncmp(buf, "offline", 7))
  262. offline = 1;
  263. else if (!strncmp(buf, "online", 6))
  264. online = 1;
  265. else if (!strncmp(buf, "remove", 6))
  266. remove = 1;
  267. else {
  268. count = -EINVAL;
  269. goto out_put;
  270. }
  271. if (wait_on_bit_lock(&xprt->state, XPRT_LOCKED, TASK_KILLABLE)) {
  272. count = -EINTR;
  273. goto out_put;
  274. }
  275. if (xprt->main) {
  276. count = -EINVAL;
  277. goto release_tasks;
  278. }
  279. if (offline) {
  280. xprt_set_offline_locked(xprt, xps);
  281. } else if (online) {
  282. xprt_set_online_locked(xprt, xps);
  283. } else if (remove) {
  284. if (test_bit(XPRT_OFFLINE, &xprt->state))
  285. xprt_delete_locked(xprt, xps);
  286. else
  287. count = -EINVAL;
  288. }
  289. release_tasks:
  290. xprt_release_write(xprt, NULL);
  291. out_put:
  292. xprt_put(xprt);
  293. xprt_switch_put(xps);
  294. return count;
  295. }
  296. int rpc_sysfs_init(void)
  297. {
  298. rpc_sunrpc_kset = kset_create_and_add("sunrpc", NULL, kernel_kobj);
  299. if (!rpc_sunrpc_kset)
  300. return -ENOMEM;
  301. rpc_sunrpc_client_kobj =
  302. rpc_sysfs_object_alloc("rpc-clients", rpc_sunrpc_kset, NULL);
  303. if (!rpc_sunrpc_client_kobj)
  304. goto err_client;
  305. rpc_sunrpc_xprt_switch_kobj =
  306. rpc_sysfs_object_alloc("xprt-switches", rpc_sunrpc_kset, NULL);
  307. if (!rpc_sunrpc_xprt_switch_kobj)
  308. goto err_switch;
  309. return 0;
  310. err_switch:
  311. kobject_put(rpc_sunrpc_client_kobj);
  312. rpc_sunrpc_client_kobj = NULL;
  313. err_client:
  314. kset_unregister(rpc_sunrpc_kset);
  315. rpc_sunrpc_kset = NULL;
  316. return -ENOMEM;
  317. }
  318. static void rpc_sysfs_client_release(struct kobject *kobj)
  319. {
  320. struct rpc_sysfs_client *c;
  321. c = container_of(kobj, struct rpc_sysfs_client, kobject);
  322. kfree(c);
  323. }
  324. static void rpc_sysfs_xprt_switch_release(struct kobject *kobj)
  325. {
  326. struct rpc_sysfs_xprt_switch *xprt_switch;
  327. xprt_switch = container_of(kobj, struct rpc_sysfs_xprt_switch, kobject);
  328. kfree(xprt_switch);
  329. }
  330. static void rpc_sysfs_xprt_release(struct kobject *kobj)
  331. {
  332. struct rpc_sysfs_xprt *xprt;
  333. xprt = container_of(kobj, struct rpc_sysfs_xprt, kobject);
  334. kfree(xprt);
  335. }
  336. static const void *rpc_sysfs_client_namespace(const struct kobject *kobj)
  337. {
  338. return container_of(kobj, struct rpc_sysfs_client, kobject)->net;
  339. }
  340. static const void *rpc_sysfs_xprt_switch_namespace(const struct kobject *kobj)
  341. {
  342. return container_of(kobj, struct rpc_sysfs_xprt_switch, kobject)->net;
  343. }
  344. static const void *rpc_sysfs_xprt_namespace(const struct kobject *kobj)
  345. {
  346. return container_of(kobj, struct rpc_sysfs_xprt,
  347. kobject)->xprt->xprt_net;
  348. }
  349. static struct kobj_attribute rpc_sysfs_xprt_dstaddr = __ATTR(dstaddr,
  350. 0644, rpc_sysfs_xprt_dstaddr_show, rpc_sysfs_xprt_dstaddr_store);
  351. static struct kobj_attribute rpc_sysfs_xprt_srcaddr = __ATTR(srcaddr,
  352. 0644, rpc_sysfs_xprt_srcaddr_show, NULL);
  353. static struct kobj_attribute rpc_sysfs_xprt_info = __ATTR(xprt_info,
  354. 0444, rpc_sysfs_xprt_info_show, NULL);
  355. static struct kobj_attribute rpc_sysfs_xprt_change_state = __ATTR(xprt_state,
  356. 0644, rpc_sysfs_xprt_state_show, rpc_sysfs_xprt_state_change);
  357. static struct attribute *rpc_sysfs_xprt_attrs[] = {
  358. &rpc_sysfs_xprt_dstaddr.attr,
  359. &rpc_sysfs_xprt_srcaddr.attr,
  360. &rpc_sysfs_xprt_info.attr,
  361. &rpc_sysfs_xprt_change_state.attr,
  362. NULL,
  363. };
  364. ATTRIBUTE_GROUPS(rpc_sysfs_xprt);
  365. static struct kobj_attribute rpc_sysfs_xprt_switch_info =
  366. __ATTR(xprt_switch_info, 0444, rpc_sysfs_xprt_switch_info_show, NULL);
  367. static struct attribute *rpc_sysfs_xprt_switch_attrs[] = {
  368. &rpc_sysfs_xprt_switch_info.attr,
  369. NULL,
  370. };
  371. ATTRIBUTE_GROUPS(rpc_sysfs_xprt_switch);
  372. static const struct kobj_type rpc_sysfs_client_type = {
  373. .release = rpc_sysfs_client_release,
  374. .sysfs_ops = &kobj_sysfs_ops,
  375. .namespace = rpc_sysfs_client_namespace,
  376. };
  377. static const struct kobj_type rpc_sysfs_xprt_switch_type = {
  378. .release = rpc_sysfs_xprt_switch_release,
  379. .default_groups = rpc_sysfs_xprt_switch_groups,
  380. .sysfs_ops = &kobj_sysfs_ops,
  381. .namespace = rpc_sysfs_xprt_switch_namespace,
  382. };
  383. static const struct kobj_type rpc_sysfs_xprt_type = {
  384. .release = rpc_sysfs_xprt_release,
  385. .default_groups = rpc_sysfs_xprt_groups,
  386. .sysfs_ops = &kobj_sysfs_ops,
  387. .namespace = rpc_sysfs_xprt_namespace,
  388. };
  389. void rpc_sysfs_exit(void)
  390. {
  391. kobject_put(rpc_sunrpc_client_kobj);
  392. kobject_put(rpc_sunrpc_xprt_switch_kobj);
  393. kset_unregister(rpc_sunrpc_kset);
  394. }
  395. static struct rpc_sysfs_client *rpc_sysfs_client_alloc(struct kobject *parent,
  396. struct net *net,
  397. int clid)
  398. {
  399. struct rpc_sysfs_client *p;
  400. p = kzalloc(sizeof(*p), GFP_KERNEL);
  401. if (p) {
  402. p->net = net;
  403. p->kobject.kset = rpc_sunrpc_kset;
  404. if (kobject_init_and_add(&p->kobject, &rpc_sysfs_client_type,
  405. parent, "clnt-%d", clid) == 0)
  406. return p;
  407. kobject_put(&p->kobject);
  408. }
  409. return NULL;
  410. }
  411. static struct rpc_sysfs_xprt_switch *
  412. rpc_sysfs_xprt_switch_alloc(struct kobject *parent,
  413. struct rpc_xprt_switch *xprt_switch,
  414. struct net *net,
  415. gfp_t gfp_flags)
  416. {
  417. struct rpc_sysfs_xprt_switch *p;
  418. p = kzalloc(sizeof(*p), gfp_flags);
  419. if (p) {
  420. p->net = net;
  421. p->kobject.kset = rpc_sunrpc_kset;
  422. if (kobject_init_and_add(&p->kobject,
  423. &rpc_sysfs_xprt_switch_type,
  424. parent, "switch-%d",
  425. xprt_switch->xps_id) == 0)
  426. return p;
  427. kobject_put(&p->kobject);
  428. }
  429. return NULL;
  430. }
  431. static struct rpc_sysfs_xprt *rpc_sysfs_xprt_alloc(struct kobject *parent,
  432. struct rpc_xprt *xprt,
  433. gfp_t gfp_flags)
  434. {
  435. struct rpc_sysfs_xprt *p;
  436. p = kzalloc(sizeof(*p), gfp_flags);
  437. if (!p)
  438. goto out;
  439. p->kobject.kset = rpc_sunrpc_kset;
  440. if (kobject_init_and_add(&p->kobject, &rpc_sysfs_xprt_type,
  441. parent, "xprt-%d-%s", xprt->id,
  442. xprt->address_strings[RPC_DISPLAY_PROTO]) == 0)
  443. return p;
  444. kobject_put(&p->kobject);
  445. out:
  446. return NULL;
  447. }
  448. void rpc_sysfs_client_setup(struct rpc_clnt *clnt,
  449. struct rpc_xprt_switch *xprt_switch,
  450. struct net *net)
  451. {
  452. struct rpc_sysfs_client *rpc_client;
  453. struct rpc_sysfs_xprt_switch *xswitch =
  454. (struct rpc_sysfs_xprt_switch *)xprt_switch->xps_sysfs;
  455. if (!xswitch)
  456. return;
  457. rpc_client = rpc_sysfs_client_alloc(rpc_sunrpc_client_kobj,
  458. net, clnt->cl_clid);
  459. if (rpc_client) {
  460. char name[] = "switch";
  461. int ret;
  462. clnt->cl_sysfs = rpc_client;
  463. rpc_client->clnt = clnt;
  464. rpc_client->xprt_switch = xprt_switch;
  465. kobject_uevent(&rpc_client->kobject, KOBJ_ADD);
  466. ret = sysfs_create_link_nowarn(&rpc_client->kobject,
  467. &xswitch->kobject, name);
  468. if (ret)
  469. pr_warn("can't create link to %s in sysfs (%d)\n",
  470. name, ret);
  471. }
  472. }
  473. void rpc_sysfs_xprt_switch_setup(struct rpc_xprt_switch *xprt_switch,
  474. struct rpc_xprt *xprt,
  475. gfp_t gfp_flags)
  476. {
  477. struct rpc_sysfs_xprt_switch *rpc_xprt_switch;
  478. struct net *net;
  479. if (xprt_switch->xps_net)
  480. net = xprt_switch->xps_net;
  481. else
  482. net = xprt->xprt_net;
  483. rpc_xprt_switch =
  484. rpc_sysfs_xprt_switch_alloc(rpc_sunrpc_xprt_switch_kobj,
  485. xprt_switch, net, gfp_flags);
  486. if (rpc_xprt_switch) {
  487. xprt_switch->xps_sysfs = rpc_xprt_switch;
  488. rpc_xprt_switch->xprt_switch = xprt_switch;
  489. rpc_xprt_switch->xprt = xprt;
  490. kobject_uevent(&rpc_xprt_switch->kobject, KOBJ_ADD);
  491. } else {
  492. xprt_switch->xps_sysfs = NULL;
  493. }
  494. }
  495. void rpc_sysfs_xprt_setup(struct rpc_xprt_switch *xprt_switch,
  496. struct rpc_xprt *xprt,
  497. gfp_t gfp_flags)
  498. {
  499. struct rpc_sysfs_xprt *rpc_xprt;
  500. struct rpc_sysfs_xprt_switch *switch_obj =
  501. (struct rpc_sysfs_xprt_switch *)xprt_switch->xps_sysfs;
  502. if (!switch_obj)
  503. return;
  504. rpc_xprt = rpc_sysfs_xprt_alloc(&switch_obj->kobject, xprt, gfp_flags);
  505. if (rpc_xprt) {
  506. xprt->xprt_sysfs = rpc_xprt;
  507. rpc_xprt->xprt = xprt;
  508. rpc_xprt->xprt_switch = xprt_switch;
  509. kobject_uevent(&rpc_xprt->kobject, KOBJ_ADD);
  510. }
  511. }
  512. void rpc_sysfs_client_destroy(struct rpc_clnt *clnt)
  513. {
  514. struct rpc_sysfs_client *rpc_client = clnt->cl_sysfs;
  515. if (rpc_client) {
  516. char name[] = "switch";
  517. sysfs_remove_link(&rpc_client->kobject, name);
  518. kobject_uevent(&rpc_client->kobject, KOBJ_REMOVE);
  519. kobject_del(&rpc_client->kobject);
  520. kobject_put(&rpc_client->kobject);
  521. clnt->cl_sysfs = NULL;
  522. }
  523. }
  524. void rpc_sysfs_xprt_switch_destroy(struct rpc_xprt_switch *xprt_switch)
  525. {
  526. struct rpc_sysfs_xprt_switch *rpc_xprt_switch = xprt_switch->xps_sysfs;
  527. if (rpc_xprt_switch) {
  528. kobject_uevent(&rpc_xprt_switch->kobject, KOBJ_REMOVE);
  529. kobject_del(&rpc_xprt_switch->kobject);
  530. kobject_put(&rpc_xprt_switch->kobject);
  531. xprt_switch->xps_sysfs = NULL;
  532. }
  533. }
  534. void rpc_sysfs_xprt_destroy(struct rpc_xprt *xprt)
  535. {
  536. struct rpc_sysfs_xprt *rpc_xprt = xprt->xprt_sysfs;
  537. if (rpc_xprt) {
  538. kobject_uevent(&rpc_xprt->kobject, KOBJ_REMOVE);
  539. kobject_del(&rpc_xprt->kobject);
  540. kobject_put(&rpc_xprt->kobject);
  541. xprt->xprt_sysfs = NULL;
  542. }
  543. }