at v2.6.16 617 lines 16 kB view raw
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 25static struct proc_dir_entry *proc_rxrpc; 26 27static int rxrpc_proc_transports_open(struct inode *inode, struct file *file); 28static void *rxrpc_proc_transports_start(struct seq_file *p, loff_t *pos); 29static void *rxrpc_proc_transports_next(struct seq_file *p, void *v, loff_t *pos); 30static void rxrpc_proc_transports_stop(struct seq_file *p, void *v); 31static int rxrpc_proc_transports_show(struct seq_file *m, void *v); 32 33static 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 40static 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 47static int rxrpc_proc_peers_open(struct inode *inode, struct file *file); 48static void *rxrpc_proc_peers_start(struct seq_file *p, loff_t *pos); 49static void *rxrpc_proc_peers_next(struct seq_file *p, void *v, loff_t *pos); 50static void rxrpc_proc_peers_stop(struct seq_file *p, void *v); 51static int rxrpc_proc_peers_show(struct seq_file *m, void *v); 52 53static 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 60static 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 67static int rxrpc_proc_conns_open(struct inode *inode, struct file *file); 68static void *rxrpc_proc_conns_start(struct seq_file *p, loff_t *pos); 69static void *rxrpc_proc_conns_next(struct seq_file *p, void *v, loff_t *pos); 70static void rxrpc_proc_conns_stop(struct seq_file *p, void *v); 71static int rxrpc_proc_conns_show(struct seq_file *m, void *v); 72 73static 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 80static 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 87static int rxrpc_proc_calls_open(struct inode *inode, struct file *file); 88static void *rxrpc_proc_calls_start(struct seq_file *p, loff_t *pos); 89static void *rxrpc_proc_calls_next(struct seq_file *p, void *v, loff_t *pos); 90static void rxrpc_proc_calls_stop(struct seq_file *p, void *v); 91static int rxrpc_proc_calls_show(struct seq_file *m, void *v); 92 93static 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 100static 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 107static 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 120static 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 */ 132int 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 */ 181void 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 */ 196static 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 */ 215static 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 */ 240static 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 */ 256static 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 */ 266static 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 */ 290static 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 */ 310static 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 */ 335static 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 */ 351static 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 */ 361static 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); 364 long timeout; 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)) 376 timeout = (long) peer->timeout.timo_jif - 377 (long) jiffies; 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 */ 397static 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 */ 417static 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 */ 442static 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 */ 458static 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 */ 468static int rxrpc_proc_conns_show(struct seq_file *m, void *v) 469{ 470 struct rxrpc_connection *conn; 471 long timeout; 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)) 487 timeout = (long) conn->timeout.timo_jif - 488 (long) jiffies; 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 */ 511static 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 */ 531static 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 */ 556static 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 */ 572static 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 */ 582static 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() */