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

SUNRPC: take a xprt offline using sysfs

Using sysfs's xprt_state attribute, mark a particular transport offline.
It will not be picked during the round-robin selection. It's not allowed
to take the main (1st created transport associated with the rpc_client)
offline. Also bring a transport back online via sysfs by writing "online"
and that would allow for this transport to be picked during the round-
robin selection.

Signed-off-by: Olga Kornievskaia <kolga@netapp.com>
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>

authored by

Olga Kornievskaia and committed by
Trond Myklebust
5b7eb784 c1830a63

+68 -6
+1
include/linux/sunrpc/xprt.h
··· 427 427 #define XPRT_BOUND (4) 428 428 #define XPRT_BINDING (5) 429 429 #define XPRT_CLOSING (6) 430 + #define XPRT_OFFLINE (7) 430 431 #define XPRT_CONGESTED (9) 431 432 #define XPRT_CWND_WAIT (10) 432 433 #define XPRT_WRITE_SPACE (11)
+62 -4
net/sunrpc/sysfs.c
··· 69 69 } 70 70 71 71 static inline struct rpc_xprt_switch * 72 + rpc_sysfs_xprt_kobj_get_xprt_switch(struct kobject *kobj) 73 + { 74 + struct rpc_sysfs_xprt *x = container_of(kobj, 75 + struct rpc_sysfs_xprt, kobject); 76 + 77 + return xprt_switch_get(x->xprt_switch); 78 + } 79 + 80 + static inline struct rpc_xprt_switch * 72 81 rpc_sysfs_xprt_switch_kobj_get_xprt(struct kobject *kobj) 73 82 { 74 83 struct rpc_sysfs_xprt_switch *x = container_of(kobj, ··· 131 122 struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj); 132 123 ssize_t ret; 133 124 int locked, connected, connecting, close_wait, bound, binding, 134 - closing, congested, cwnd_wait, write_space; 125 + closing, congested, cwnd_wait, write_space, offline; 135 126 136 127 if (!xprt) 137 128 return 0; ··· 149 140 congested = test_bit(XPRT_CONGESTED, &xprt->state); 150 141 cwnd_wait = test_bit(XPRT_CWND_WAIT, &xprt->state); 151 142 write_space = test_bit(XPRT_WRITE_SPACE, &xprt->state); 143 + offline = test_bit(XPRT_OFFLINE, &xprt->state); 152 144 153 - ret = sprintf(buf, "state=%s %s %s %s %s %s %s %s %s %s\n", 145 + ret = sprintf(buf, "state=%s %s %s %s %s %s %s %s %s %s %s\n", 154 146 locked ? "LOCKED" : "", 155 147 connected ? "CONNECTED" : "", 156 148 connecting ? "CONNECTING" : "", ··· 161 151 closing ? "CLOSING" : "", 162 152 congested ? "CONGESTED" : "", 163 153 cwnd_wait ? "CWND_WAIT" : "", 164 - write_space ? "WRITE_SPACE" : ""); 154 + write_space ? "WRITE_SPACE" : "", 155 + offline ? "OFFLINE" : ""); 165 156 } 166 157 167 158 xprt_put(xprt); ··· 244 233 goto out; 245 234 } 246 235 236 + static ssize_t rpc_sysfs_xprt_state_change(struct kobject *kobj, 237 + struct kobj_attribute *attr, 238 + const char *buf, size_t count) 239 + { 240 + struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj); 241 + int offline = 0, online = 0; 242 + struct rpc_xprt_switch *xps = rpc_sysfs_xprt_kobj_get_xprt_switch(kobj); 243 + 244 + if (!xprt) 245 + return 0; 246 + 247 + if (!strncmp(buf, "offline", 7)) 248 + offline = 1; 249 + else if (!strncmp(buf, "online", 6)) 250 + online = 1; 251 + else 252 + return -EINVAL; 253 + 254 + if (wait_on_bit_lock(&xprt->state, XPRT_LOCKED, TASK_KILLABLE)) { 255 + count = -EINTR; 256 + goto out_put; 257 + } 258 + if (xprt->main) { 259 + count = -EINVAL; 260 + goto release_tasks; 261 + } 262 + if (offline) { 263 + set_bit(XPRT_OFFLINE, &xprt->state); 264 + spin_lock(&xps->xps_lock); 265 + xps->xps_nactive--; 266 + spin_unlock(&xps->xps_lock); 267 + } else if (online) { 268 + clear_bit(XPRT_OFFLINE, &xprt->state); 269 + spin_lock(&xps->xps_lock); 270 + xps->xps_nactive++; 271 + spin_unlock(&xps->xps_lock); 272 + } 273 + 274 + release_tasks: 275 + xprt_release_write(xprt, NULL); 276 + out_put: 277 + xprt_put(xprt); 278 + xprt_switch_put(xps); 279 + return count; 280 + } 281 + 247 282 int rpc_sysfs_init(void) 248 283 { 249 284 rpc_sunrpc_kset = kset_create_and_add("sunrpc", NULL, kernel_kobj); ··· 360 303 0444, rpc_sysfs_xprt_info_show, NULL); 361 304 362 305 static struct kobj_attribute rpc_sysfs_xprt_change_state = __ATTR(xprt_state, 363 - 0644, rpc_sysfs_xprt_state_show, NULL); 306 + 0644, rpc_sysfs_xprt_state_show, rpc_sysfs_xprt_state_change); 364 307 365 308 static struct attribute *rpc_sysfs_xprt_attrs[] = { 366 309 &rpc_sysfs_xprt_dstaddr.attr, ··· 523 466 if (rpc_xprt) { 524 467 xprt->xprt_sysfs = rpc_xprt; 525 468 rpc_xprt->xprt = xprt; 469 + rpc_xprt->xprt_switch = xprt_switch; 526 470 kobject_uevent(&rpc_xprt->kobject, KOBJ_ADD); 527 471 } 528 472 }
+1
net/sunrpc/sysfs.h
··· 22 22 struct rpc_sysfs_xprt { 23 23 struct kobject kobject; 24 24 struct rpc_xprt *xprt; 25 + struct rpc_xprt_switch *xprt_switch; 25 26 }; 26 27 27 28 int rpc_sysfs_init(void);
+4 -2
net/sunrpc/xprtmultipath.c
··· 65 65 { 66 66 if (unlikely(xprt == NULL)) 67 67 return; 68 - xps->xps_nactive--; 68 + if (!test_bit(XPRT_OFFLINE, &xprt->state)) 69 + xps->xps_nactive--; 69 70 xps->xps_nxprts--; 70 71 if (xps->xps_nxprts == 0) 71 72 xps->xps_net = NULL; ··· 231 230 static 232 231 bool xprt_is_active(const struct rpc_xprt *xprt) 233 232 { 234 - return kref_read(&xprt->kref) != 0; 233 + return (kref_read(&xprt->kref) != 0 && 234 + !test_bit(XPRT_OFFLINE, &xprt->state)); 235 235 } 236 236 237 237 static