| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* proc.c: /proc interface for RxRPC | 
|  | 2 | * | 
|  | 3 | * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. | 
|  | 4 | * Written by David Howells (dhowells@redhat.com) | 
|  | 5 | * | 
|  | 6 | * This program is free software; you can redistribute it and/or | 
|  | 7 | * modify it under the terms of the GNU General Public License | 
|  | 8 | * as published by the Free Software Foundation; either version | 
|  | 9 | * 2 of the License, or (at your option) any later version. | 
|  | 10 | */ | 
|  | 11 |  | 
|  | 12 | #include <linux/sched.h> | 
|  | 13 | #include <linux/slab.h> | 
|  | 14 | #include <linux/module.h> | 
|  | 15 | #include <linux/proc_fs.h> | 
|  | 16 | #include <linux/seq_file.h> | 
|  | 17 | #include <rxrpc/rxrpc.h> | 
|  | 18 | #include <rxrpc/transport.h> | 
|  | 19 | #include <rxrpc/peer.h> | 
|  | 20 | #include <rxrpc/connection.h> | 
|  | 21 | #include <rxrpc/call.h> | 
|  | 22 | #include <rxrpc/message.h> | 
|  | 23 | #include "internal.h" | 
|  | 24 |  | 
|  | 25 | static struct proc_dir_entry *proc_rxrpc; | 
|  | 26 |  | 
|  | 27 | static int rxrpc_proc_transports_open(struct inode *inode, struct file *file); | 
|  | 28 | static void *rxrpc_proc_transports_start(struct seq_file *p, loff_t *pos); | 
|  | 29 | static void *rxrpc_proc_transports_next(struct seq_file *p, void *v, loff_t *pos); | 
|  | 30 | static void rxrpc_proc_transports_stop(struct seq_file *p, void *v); | 
|  | 31 | static int rxrpc_proc_transports_show(struct seq_file *m, void *v); | 
|  | 32 |  | 
|  | 33 | static struct seq_operations rxrpc_proc_transports_ops = { | 
|  | 34 | .start	= rxrpc_proc_transports_start, | 
|  | 35 | .next	= rxrpc_proc_transports_next, | 
|  | 36 | .stop	= rxrpc_proc_transports_stop, | 
|  | 37 | .show	= rxrpc_proc_transports_show, | 
|  | 38 | }; | 
|  | 39 |  | 
|  | 40 | static struct file_operations rxrpc_proc_transports_fops = { | 
|  | 41 | .open		= rxrpc_proc_transports_open, | 
|  | 42 | .read		= seq_read, | 
|  | 43 | .llseek		= seq_lseek, | 
|  | 44 | .release	= seq_release, | 
|  | 45 | }; | 
|  | 46 |  | 
|  | 47 | static int rxrpc_proc_peers_open(struct inode *inode, struct file *file); | 
|  | 48 | static void *rxrpc_proc_peers_start(struct seq_file *p, loff_t *pos); | 
|  | 49 | static void *rxrpc_proc_peers_next(struct seq_file *p, void *v, loff_t *pos); | 
|  | 50 | static void rxrpc_proc_peers_stop(struct seq_file *p, void *v); | 
|  | 51 | static int rxrpc_proc_peers_show(struct seq_file *m, void *v); | 
|  | 52 |  | 
|  | 53 | static struct seq_operations rxrpc_proc_peers_ops = { | 
|  | 54 | .start	= rxrpc_proc_peers_start, | 
|  | 55 | .next	= rxrpc_proc_peers_next, | 
|  | 56 | .stop	= rxrpc_proc_peers_stop, | 
|  | 57 | .show	= rxrpc_proc_peers_show, | 
|  | 58 | }; | 
|  | 59 |  | 
|  | 60 | static struct file_operations rxrpc_proc_peers_fops = { | 
|  | 61 | .open		= rxrpc_proc_peers_open, | 
|  | 62 | .read		= seq_read, | 
|  | 63 | .llseek		= seq_lseek, | 
|  | 64 | .release	= seq_release, | 
|  | 65 | }; | 
|  | 66 |  | 
|  | 67 | static int rxrpc_proc_conns_open(struct inode *inode, struct file *file); | 
|  | 68 | static void *rxrpc_proc_conns_start(struct seq_file *p, loff_t *pos); | 
|  | 69 | static void *rxrpc_proc_conns_next(struct seq_file *p, void *v, loff_t *pos); | 
|  | 70 | static void rxrpc_proc_conns_stop(struct seq_file *p, void *v); | 
|  | 71 | static int rxrpc_proc_conns_show(struct seq_file *m, void *v); | 
|  | 72 |  | 
|  | 73 | static struct seq_operations rxrpc_proc_conns_ops = { | 
|  | 74 | .start	= rxrpc_proc_conns_start, | 
|  | 75 | .next	= rxrpc_proc_conns_next, | 
|  | 76 | .stop	= rxrpc_proc_conns_stop, | 
|  | 77 | .show	= rxrpc_proc_conns_show, | 
|  | 78 | }; | 
|  | 79 |  | 
|  | 80 | static struct file_operations rxrpc_proc_conns_fops = { | 
|  | 81 | .open		= rxrpc_proc_conns_open, | 
|  | 82 | .read		= seq_read, | 
|  | 83 | .llseek		= seq_lseek, | 
|  | 84 | .release	= seq_release, | 
|  | 85 | }; | 
|  | 86 |  | 
|  | 87 | static int rxrpc_proc_calls_open(struct inode *inode, struct file *file); | 
|  | 88 | static void *rxrpc_proc_calls_start(struct seq_file *p, loff_t *pos); | 
|  | 89 | static void *rxrpc_proc_calls_next(struct seq_file *p, void *v, loff_t *pos); | 
|  | 90 | static void rxrpc_proc_calls_stop(struct seq_file *p, void *v); | 
|  | 91 | static int rxrpc_proc_calls_show(struct seq_file *m, void *v); | 
|  | 92 |  | 
|  | 93 | static struct seq_operations rxrpc_proc_calls_ops = { | 
|  | 94 | .start	= rxrpc_proc_calls_start, | 
|  | 95 | .next	= rxrpc_proc_calls_next, | 
|  | 96 | .stop	= rxrpc_proc_calls_stop, | 
|  | 97 | .show	= rxrpc_proc_calls_show, | 
|  | 98 | }; | 
|  | 99 |  | 
|  | 100 | static struct file_operations rxrpc_proc_calls_fops = { | 
|  | 101 | .open		= rxrpc_proc_calls_open, | 
|  | 102 | .read		= seq_read, | 
|  | 103 | .llseek		= seq_lseek, | 
|  | 104 | .release	= seq_release, | 
|  | 105 | }; | 
|  | 106 |  | 
|  | 107 | static const char *rxrpc_call_states7[] = { | 
|  | 108 | "complet", | 
|  | 109 | "error  ", | 
|  | 110 | "rcv_op ", | 
|  | 111 | "rcv_arg", | 
|  | 112 | "got_arg", | 
|  | 113 | "snd_rpl", | 
|  | 114 | "fin_ack", | 
|  | 115 | "snd_arg", | 
|  | 116 | "rcv_rpl", | 
|  | 117 | "got_rpl" | 
|  | 118 | }; | 
|  | 119 |  | 
|  | 120 | static const char *rxrpc_call_error_states7[] = { | 
|  | 121 | "no_err ", | 
|  | 122 | "loc_abt", | 
|  | 123 | "rmt_abt", | 
|  | 124 | "loc_err", | 
|  | 125 | "rmt_err" | 
|  | 126 | }; | 
|  | 127 |  | 
|  | 128 | /*****************************************************************************/ | 
|  | 129 | /* | 
|  | 130 | * initialise the /proc/net/rxrpc/ directory | 
|  | 131 | */ | 
|  | 132 | int rxrpc_proc_init(void) | 
|  | 133 | { | 
|  | 134 | struct proc_dir_entry *p; | 
|  | 135 |  | 
|  | 136 | proc_rxrpc = proc_mkdir("rxrpc", proc_net); | 
|  | 137 | if (!proc_rxrpc) | 
|  | 138 | goto error; | 
|  | 139 | proc_rxrpc->owner = THIS_MODULE; | 
|  | 140 |  | 
|  | 141 | p = create_proc_entry("calls", 0, proc_rxrpc); | 
|  | 142 | if (!p) | 
|  | 143 | goto error_proc; | 
|  | 144 | p->proc_fops = &rxrpc_proc_calls_fops; | 
|  | 145 | p->owner = THIS_MODULE; | 
|  | 146 |  | 
|  | 147 | p = create_proc_entry("connections", 0, proc_rxrpc); | 
|  | 148 | if (!p) | 
|  | 149 | goto error_calls; | 
|  | 150 | p->proc_fops = &rxrpc_proc_conns_fops; | 
|  | 151 | p->owner = THIS_MODULE; | 
|  | 152 |  | 
|  | 153 | p = create_proc_entry("peers", 0, proc_rxrpc); | 
|  | 154 | if (!p) | 
|  | 155 | goto error_calls; | 
|  | 156 | p->proc_fops = &rxrpc_proc_peers_fops; | 
|  | 157 | p->owner = THIS_MODULE; | 
|  | 158 |  | 
|  | 159 | p = create_proc_entry("transports", 0, proc_rxrpc); | 
|  | 160 | if (!p) | 
|  | 161 | goto error_conns; | 
|  | 162 | p->proc_fops = &rxrpc_proc_transports_fops; | 
|  | 163 | p->owner = THIS_MODULE; | 
|  | 164 |  | 
|  | 165 | return 0; | 
|  | 166 |  | 
|  | 167 | error_conns: | 
|  | 168 | remove_proc_entry("connections", proc_rxrpc); | 
|  | 169 | error_calls: | 
|  | 170 | remove_proc_entry("calls", proc_rxrpc); | 
|  | 171 | error_proc: | 
|  | 172 | remove_proc_entry("rxrpc", proc_net); | 
|  | 173 | error: | 
|  | 174 | return -ENOMEM; | 
|  | 175 | } /* end rxrpc_proc_init() */ | 
|  | 176 |  | 
|  | 177 | /*****************************************************************************/ | 
|  | 178 | /* | 
|  | 179 | * clean up the /proc/net/rxrpc/ directory | 
|  | 180 | */ | 
|  | 181 | void rxrpc_proc_cleanup(void) | 
|  | 182 | { | 
|  | 183 | remove_proc_entry("transports", proc_rxrpc); | 
|  | 184 | remove_proc_entry("peers", proc_rxrpc); | 
|  | 185 | remove_proc_entry("connections", proc_rxrpc); | 
|  | 186 | remove_proc_entry("calls", proc_rxrpc); | 
|  | 187 |  | 
|  | 188 | remove_proc_entry("rxrpc", proc_net); | 
|  | 189 |  | 
|  | 190 | } /* end rxrpc_proc_cleanup() */ | 
|  | 191 |  | 
|  | 192 | /*****************************************************************************/ | 
|  | 193 | /* | 
|  | 194 | * open "/proc/net/rxrpc/transports" which provides a summary of extant transports | 
|  | 195 | */ | 
|  | 196 | static int rxrpc_proc_transports_open(struct inode *inode, struct file *file) | 
|  | 197 | { | 
|  | 198 | struct seq_file *m; | 
|  | 199 | int ret; | 
|  | 200 |  | 
|  | 201 | ret = seq_open(file, &rxrpc_proc_transports_ops); | 
|  | 202 | if (ret < 0) | 
|  | 203 | return ret; | 
|  | 204 |  | 
|  | 205 | m = file->private_data; | 
|  | 206 | m->private = PDE(inode)->data; | 
|  | 207 |  | 
|  | 208 | return 0; | 
|  | 209 | } /* end rxrpc_proc_transports_open() */ | 
|  | 210 |  | 
|  | 211 | /*****************************************************************************/ | 
|  | 212 | /* | 
|  | 213 | * set up the iterator to start reading from the transports list and return the first item | 
|  | 214 | */ | 
|  | 215 | static void *rxrpc_proc_transports_start(struct seq_file *m, loff_t *_pos) | 
|  | 216 | { | 
|  | 217 | struct list_head *_p; | 
|  | 218 | loff_t pos = *_pos; | 
|  | 219 |  | 
|  | 220 | /* lock the list against modification */ | 
|  | 221 | down_read(&rxrpc_proc_transports_sem); | 
|  | 222 |  | 
|  | 223 | /* allow for the header line */ | 
|  | 224 | if (!pos) | 
|  | 225 | return SEQ_START_TOKEN; | 
|  | 226 | pos--; | 
|  | 227 |  | 
|  | 228 | /* find the n'th element in the list */ | 
|  | 229 | list_for_each(_p, &rxrpc_proc_transports) | 
|  | 230 | if (!pos--) | 
|  | 231 | break; | 
|  | 232 |  | 
|  | 233 | return _p != &rxrpc_proc_transports ? _p : NULL; | 
|  | 234 | } /* end rxrpc_proc_transports_start() */ | 
|  | 235 |  | 
|  | 236 | /*****************************************************************************/ | 
|  | 237 | /* | 
|  | 238 | * move to next call in transports list | 
|  | 239 | */ | 
|  | 240 | static void *rxrpc_proc_transports_next(struct seq_file *p, void *v, loff_t *pos) | 
|  | 241 | { | 
|  | 242 | struct list_head *_p; | 
|  | 243 |  | 
|  | 244 | (*pos)++; | 
|  | 245 |  | 
|  | 246 | _p = v; | 
|  | 247 | _p = (v == SEQ_START_TOKEN) ? rxrpc_proc_transports.next : _p->next; | 
|  | 248 |  | 
|  | 249 | return _p != &rxrpc_proc_transports ? _p : NULL; | 
|  | 250 | } /* end rxrpc_proc_transports_next() */ | 
|  | 251 |  | 
|  | 252 | /*****************************************************************************/ | 
|  | 253 | /* | 
|  | 254 | * clean up after reading from the transports list | 
|  | 255 | */ | 
|  | 256 | static void rxrpc_proc_transports_stop(struct seq_file *p, void *v) | 
|  | 257 | { | 
|  | 258 | up_read(&rxrpc_proc_transports_sem); | 
|  | 259 |  | 
|  | 260 | } /* end rxrpc_proc_transports_stop() */ | 
|  | 261 |  | 
|  | 262 | /*****************************************************************************/ | 
|  | 263 | /* | 
|  | 264 | * display a header line followed by a load of call lines | 
|  | 265 | */ | 
|  | 266 | static int rxrpc_proc_transports_show(struct seq_file *m, void *v) | 
|  | 267 | { | 
|  | 268 | struct rxrpc_transport *trans = | 
|  | 269 | list_entry(v, struct rxrpc_transport, proc_link); | 
|  | 270 |  | 
|  | 271 | /* display header on line 1 */ | 
|  | 272 | if (v == SEQ_START_TOKEN) { | 
|  | 273 | seq_puts(m, "LOCAL USE\n"); | 
|  | 274 | return 0; | 
|  | 275 | } | 
|  | 276 |  | 
|  | 277 | /* display one transport per line on subsequent lines */ | 
|  | 278 | seq_printf(m, "%5hu %3d\n", | 
|  | 279 | trans->port, | 
|  | 280 | atomic_read(&trans->usage) | 
|  | 281 | ); | 
|  | 282 |  | 
|  | 283 | return 0; | 
|  | 284 | } /* end rxrpc_proc_transports_show() */ | 
|  | 285 |  | 
|  | 286 | /*****************************************************************************/ | 
|  | 287 | /* | 
|  | 288 | * open "/proc/net/rxrpc/peers" which provides a summary of extant peers | 
|  | 289 | */ | 
|  | 290 | static int rxrpc_proc_peers_open(struct inode *inode, struct file *file) | 
|  | 291 | { | 
|  | 292 | struct seq_file *m; | 
|  | 293 | int ret; | 
|  | 294 |  | 
|  | 295 | ret = seq_open(file, &rxrpc_proc_peers_ops); | 
|  | 296 | if (ret < 0) | 
|  | 297 | return ret; | 
|  | 298 |  | 
|  | 299 | m = file->private_data; | 
|  | 300 | m->private = PDE(inode)->data; | 
|  | 301 |  | 
|  | 302 | return 0; | 
|  | 303 | } /* end rxrpc_proc_peers_open() */ | 
|  | 304 |  | 
|  | 305 | /*****************************************************************************/ | 
|  | 306 | /* | 
|  | 307 | * set up the iterator to start reading from the peers list and return the | 
|  | 308 | * first item | 
|  | 309 | */ | 
|  | 310 | static void *rxrpc_proc_peers_start(struct seq_file *m, loff_t *_pos) | 
|  | 311 | { | 
|  | 312 | struct list_head *_p; | 
|  | 313 | loff_t pos = *_pos; | 
|  | 314 |  | 
|  | 315 | /* lock the list against modification */ | 
|  | 316 | down_read(&rxrpc_peers_sem); | 
|  | 317 |  | 
|  | 318 | /* allow for the header line */ | 
|  | 319 | if (!pos) | 
|  | 320 | return SEQ_START_TOKEN; | 
|  | 321 | pos--; | 
|  | 322 |  | 
|  | 323 | /* find the n'th element in the list */ | 
|  | 324 | list_for_each(_p, &rxrpc_peers) | 
|  | 325 | if (!pos--) | 
|  | 326 | break; | 
|  | 327 |  | 
|  | 328 | return _p != &rxrpc_peers ? _p : NULL; | 
|  | 329 | } /* end rxrpc_proc_peers_start() */ | 
|  | 330 |  | 
|  | 331 | /*****************************************************************************/ | 
|  | 332 | /* | 
|  | 333 | * move to next conn in peers list | 
|  | 334 | */ | 
|  | 335 | static void *rxrpc_proc_peers_next(struct seq_file *p, void *v, loff_t *pos) | 
|  | 336 | { | 
|  | 337 | struct list_head *_p; | 
|  | 338 |  | 
|  | 339 | (*pos)++; | 
|  | 340 |  | 
|  | 341 | _p = v; | 
|  | 342 | _p = (v == SEQ_START_TOKEN) ? rxrpc_peers.next : _p->next; | 
|  | 343 |  | 
|  | 344 | return _p != &rxrpc_peers ? _p : NULL; | 
|  | 345 | } /* end rxrpc_proc_peers_next() */ | 
|  | 346 |  | 
|  | 347 | /*****************************************************************************/ | 
|  | 348 | /* | 
|  | 349 | * clean up after reading from the peers list | 
|  | 350 | */ | 
|  | 351 | static void rxrpc_proc_peers_stop(struct seq_file *p, void *v) | 
|  | 352 | { | 
|  | 353 | up_read(&rxrpc_peers_sem); | 
|  | 354 |  | 
|  | 355 | } /* end rxrpc_proc_peers_stop() */ | 
|  | 356 |  | 
|  | 357 | /*****************************************************************************/ | 
|  | 358 | /* | 
|  | 359 | * display a header line followed by a load of conn lines | 
|  | 360 | */ | 
|  | 361 | static int rxrpc_proc_peers_show(struct seq_file *m, void *v) | 
|  | 362 | { | 
|  | 363 | struct rxrpc_peer *peer = list_entry(v, struct rxrpc_peer, proc_link); | 
| Kris Katterjohn | a8fc3d8 | 2006-01-17 13:03:54 -0800 | [diff] [blame] | 364 | long timeout; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 365 |  | 
|  | 366 | /* display header on line 1 */ | 
|  | 367 | if (v == SEQ_START_TOKEN) { | 
|  | 368 | seq_puts(m, "LOCAL REMOTE   USAGE CONNS  TIMEOUT" | 
|  | 369 | "   MTU RTT(uS)\n"); | 
|  | 370 | return 0; | 
|  | 371 | } | 
|  | 372 |  | 
|  | 373 | /* display one peer per line on subsequent lines */ | 
|  | 374 | timeout = 0; | 
|  | 375 | if (!list_empty(&peer->timeout.link)) | 
| Kris Katterjohn | a8fc3d8 | 2006-01-17 13:03:54 -0800 | [diff] [blame] | 376 | timeout = (long) peer->timeout.timo_jif - | 
|  | 377 | (long) jiffies; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 378 |  | 
|  | 379 | seq_printf(m, "%5hu %08x %5d %5d %8ld %5Zu %7lu\n", | 
|  | 380 | peer->trans->port, | 
|  | 381 | ntohl(peer->addr.s_addr), | 
|  | 382 | atomic_read(&peer->usage), | 
|  | 383 | atomic_read(&peer->conn_count), | 
|  | 384 | timeout, | 
|  | 385 | peer->if_mtu, | 
|  | 386 | (long) peer->rtt | 
|  | 387 | ); | 
|  | 388 |  | 
|  | 389 | return 0; | 
|  | 390 | } /* end rxrpc_proc_peers_show() */ | 
|  | 391 |  | 
|  | 392 | /*****************************************************************************/ | 
|  | 393 | /* | 
|  | 394 | * open "/proc/net/rxrpc/connections" which provides a summary of extant | 
|  | 395 | * connections | 
|  | 396 | */ | 
|  | 397 | static int rxrpc_proc_conns_open(struct inode *inode, struct file *file) | 
|  | 398 | { | 
|  | 399 | struct seq_file *m; | 
|  | 400 | int ret; | 
|  | 401 |  | 
|  | 402 | ret = seq_open(file, &rxrpc_proc_conns_ops); | 
|  | 403 | if (ret < 0) | 
|  | 404 | return ret; | 
|  | 405 |  | 
|  | 406 | m = file->private_data; | 
|  | 407 | m->private = PDE(inode)->data; | 
|  | 408 |  | 
|  | 409 | return 0; | 
|  | 410 | } /* end rxrpc_proc_conns_open() */ | 
|  | 411 |  | 
|  | 412 | /*****************************************************************************/ | 
|  | 413 | /* | 
|  | 414 | * set up the iterator to start reading from the conns list and return the | 
|  | 415 | * first item | 
|  | 416 | */ | 
|  | 417 | static void *rxrpc_proc_conns_start(struct seq_file *m, loff_t *_pos) | 
|  | 418 | { | 
|  | 419 | struct list_head *_p; | 
|  | 420 | loff_t pos = *_pos; | 
|  | 421 |  | 
|  | 422 | /* lock the list against modification */ | 
|  | 423 | down_read(&rxrpc_conns_sem); | 
|  | 424 |  | 
|  | 425 | /* allow for the header line */ | 
|  | 426 | if (!pos) | 
|  | 427 | return SEQ_START_TOKEN; | 
|  | 428 | pos--; | 
|  | 429 |  | 
|  | 430 | /* find the n'th element in the list */ | 
|  | 431 | list_for_each(_p, &rxrpc_conns) | 
|  | 432 | if (!pos--) | 
|  | 433 | break; | 
|  | 434 |  | 
|  | 435 | return _p != &rxrpc_conns ? _p : NULL; | 
|  | 436 | } /* end rxrpc_proc_conns_start() */ | 
|  | 437 |  | 
|  | 438 | /*****************************************************************************/ | 
|  | 439 | /* | 
|  | 440 | * move to next conn in conns list | 
|  | 441 | */ | 
|  | 442 | static void *rxrpc_proc_conns_next(struct seq_file *p, void *v, loff_t *pos) | 
|  | 443 | { | 
|  | 444 | struct list_head *_p; | 
|  | 445 |  | 
|  | 446 | (*pos)++; | 
|  | 447 |  | 
|  | 448 | _p = v; | 
|  | 449 | _p = (v == SEQ_START_TOKEN) ? rxrpc_conns.next : _p->next; | 
|  | 450 |  | 
|  | 451 | return _p != &rxrpc_conns ? _p : NULL; | 
|  | 452 | } /* end rxrpc_proc_conns_next() */ | 
|  | 453 |  | 
|  | 454 | /*****************************************************************************/ | 
|  | 455 | /* | 
|  | 456 | * clean up after reading from the conns list | 
|  | 457 | */ | 
|  | 458 | static void rxrpc_proc_conns_stop(struct seq_file *p, void *v) | 
|  | 459 | { | 
|  | 460 | up_read(&rxrpc_conns_sem); | 
|  | 461 |  | 
|  | 462 | } /* end rxrpc_proc_conns_stop() */ | 
|  | 463 |  | 
|  | 464 | /*****************************************************************************/ | 
|  | 465 | /* | 
|  | 466 | * display a header line followed by a load of conn lines | 
|  | 467 | */ | 
|  | 468 | static int rxrpc_proc_conns_show(struct seq_file *m, void *v) | 
|  | 469 | { | 
|  | 470 | struct rxrpc_connection *conn; | 
| Kris Katterjohn | a8fc3d8 | 2006-01-17 13:03:54 -0800 | [diff] [blame] | 471 | long timeout; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 472 |  | 
|  | 473 | conn = list_entry(v, struct rxrpc_connection, proc_link); | 
|  | 474 |  | 
|  | 475 | /* display header on line 1 */ | 
|  | 476 | if (v == SEQ_START_TOKEN) { | 
|  | 477 | seq_puts(m, | 
|  | 478 | "LOCAL REMOTE   RPORT SRVC CONN     END SERIALNO " | 
|  | 479 | "CALLNO     MTU  TIMEOUT" | 
|  | 480 | "\n"); | 
|  | 481 | return 0; | 
|  | 482 | } | 
|  | 483 |  | 
|  | 484 | /* display one conn per line on subsequent lines */ | 
|  | 485 | timeout = 0; | 
|  | 486 | if (!list_empty(&conn->timeout.link)) | 
| Kris Katterjohn | a8fc3d8 | 2006-01-17 13:03:54 -0800 | [diff] [blame] | 487 | timeout = (long) conn->timeout.timo_jif - | 
|  | 488 | (long) jiffies; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 489 |  | 
|  | 490 | seq_printf(m, | 
|  | 491 | "%5hu %08x %5hu %04hx %08x %-3.3s %08x %08x %5Zu %8ld\n", | 
|  | 492 | conn->trans->port, | 
|  | 493 | ntohl(conn->addr.sin_addr.s_addr), | 
|  | 494 | ntohs(conn->addr.sin_port), | 
|  | 495 | ntohs(conn->service_id), | 
|  | 496 | ntohl(conn->conn_id), | 
|  | 497 | conn->out_clientflag ? "CLT" : "SRV", | 
|  | 498 | conn->serial_counter, | 
|  | 499 | conn->call_counter, | 
|  | 500 | conn->mtu_size, | 
|  | 501 | timeout | 
|  | 502 | ); | 
|  | 503 |  | 
|  | 504 | return 0; | 
|  | 505 | } /* end rxrpc_proc_conns_show() */ | 
|  | 506 |  | 
|  | 507 | /*****************************************************************************/ | 
|  | 508 | /* | 
|  | 509 | * open "/proc/net/rxrpc/calls" which provides a summary of extant calls | 
|  | 510 | */ | 
|  | 511 | static int rxrpc_proc_calls_open(struct inode *inode, struct file *file) | 
|  | 512 | { | 
|  | 513 | struct seq_file *m; | 
|  | 514 | int ret; | 
|  | 515 |  | 
|  | 516 | ret = seq_open(file, &rxrpc_proc_calls_ops); | 
|  | 517 | if (ret < 0) | 
|  | 518 | return ret; | 
|  | 519 |  | 
|  | 520 | m = file->private_data; | 
|  | 521 | m->private = PDE(inode)->data; | 
|  | 522 |  | 
|  | 523 | return 0; | 
|  | 524 | } /* end rxrpc_proc_calls_open() */ | 
|  | 525 |  | 
|  | 526 | /*****************************************************************************/ | 
|  | 527 | /* | 
|  | 528 | * set up the iterator to start reading from the calls list and return the | 
|  | 529 | * first item | 
|  | 530 | */ | 
|  | 531 | static void *rxrpc_proc_calls_start(struct seq_file *m, loff_t *_pos) | 
|  | 532 | { | 
|  | 533 | struct list_head *_p; | 
|  | 534 | loff_t pos = *_pos; | 
|  | 535 |  | 
|  | 536 | /* lock the list against modification */ | 
|  | 537 | down_read(&rxrpc_calls_sem); | 
|  | 538 |  | 
|  | 539 | /* allow for the header line */ | 
|  | 540 | if (!pos) | 
|  | 541 | return SEQ_START_TOKEN; | 
|  | 542 | pos--; | 
|  | 543 |  | 
|  | 544 | /* find the n'th element in the list */ | 
|  | 545 | list_for_each(_p, &rxrpc_calls) | 
|  | 546 | if (!pos--) | 
|  | 547 | break; | 
|  | 548 |  | 
|  | 549 | return _p != &rxrpc_calls ? _p : NULL; | 
|  | 550 | } /* end rxrpc_proc_calls_start() */ | 
|  | 551 |  | 
|  | 552 | /*****************************************************************************/ | 
|  | 553 | /* | 
|  | 554 | * move to next call in calls list | 
|  | 555 | */ | 
|  | 556 | static void *rxrpc_proc_calls_next(struct seq_file *p, void *v, loff_t *pos) | 
|  | 557 | { | 
|  | 558 | struct list_head *_p; | 
|  | 559 |  | 
|  | 560 | (*pos)++; | 
|  | 561 |  | 
|  | 562 | _p = v; | 
|  | 563 | _p = (v == SEQ_START_TOKEN) ? rxrpc_calls.next : _p->next; | 
|  | 564 |  | 
|  | 565 | return _p != &rxrpc_calls ? _p : NULL; | 
|  | 566 | } /* end rxrpc_proc_calls_next() */ | 
|  | 567 |  | 
|  | 568 | /*****************************************************************************/ | 
|  | 569 | /* | 
|  | 570 | * clean up after reading from the calls list | 
|  | 571 | */ | 
|  | 572 | static void rxrpc_proc_calls_stop(struct seq_file *p, void *v) | 
|  | 573 | { | 
|  | 574 | up_read(&rxrpc_calls_sem); | 
|  | 575 |  | 
|  | 576 | } /* end rxrpc_proc_calls_stop() */ | 
|  | 577 |  | 
|  | 578 | /*****************************************************************************/ | 
|  | 579 | /* | 
|  | 580 | * display a header line followed by a load of call lines | 
|  | 581 | */ | 
|  | 582 | static int rxrpc_proc_calls_show(struct seq_file *m, void *v) | 
|  | 583 | { | 
|  | 584 | struct rxrpc_call *call = list_entry(v, struct rxrpc_call, call_link); | 
|  | 585 |  | 
|  | 586 | /* display header on line 1 */ | 
|  | 587 | if (v == SEQ_START_TOKEN) { | 
|  | 588 | seq_puts(m, | 
|  | 589 | "LOCAL REMOT SRVC CONN     CALL     DIR USE " | 
|  | 590 | " L STATE   OPCODE ABORT    ERRNO\n" | 
|  | 591 | ); | 
|  | 592 | return 0; | 
|  | 593 | } | 
|  | 594 |  | 
|  | 595 | /* display one call per line on subsequent lines */ | 
|  | 596 | seq_printf(m, | 
|  | 597 | "%5hu %5hu %04hx %08x %08x %s %3u%c" | 
|  | 598 | " %c %-7.7s %6d %08x %5d\n", | 
|  | 599 | call->conn->trans->port, | 
|  | 600 | ntohs(call->conn->addr.sin_port), | 
|  | 601 | ntohs(call->conn->service_id), | 
|  | 602 | ntohl(call->conn->conn_id), | 
|  | 603 | ntohl(call->call_id), | 
|  | 604 | call->conn->service ? "SVC" : "CLT", | 
|  | 605 | atomic_read(&call->usage), | 
|  | 606 | waitqueue_active(&call->waitq) ? 'w' : ' ', | 
|  | 607 | call->app_last_rcv ? 'Y' : '-', | 
|  | 608 | (call->app_call_state!=RXRPC_CSTATE_ERROR ? | 
|  | 609 | rxrpc_call_states7[call->app_call_state] : | 
|  | 610 | rxrpc_call_error_states7[call->app_err_state]), | 
|  | 611 | call->app_opcode, | 
|  | 612 | call->app_abort_code, | 
|  | 613 | call->app_errno | 
|  | 614 | ); | 
|  | 615 |  | 
|  | 616 | return 0; | 
|  | 617 | } /* end rxrpc_proc_calls_show() */ |