1219820Sjeff/* 2219820Sjeff * Copyright (c) 2008 Mellanox Technologies Ltd. All rights reserved. 3219820Sjeff * 4219820Sjeff * This software is available to you under a choice of one of two 5219820Sjeff * licenses. You may choose to be licensed under the terms of the GNU 6219820Sjeff * General Public License (GPL) Version 2, available from the file 7219820Sjeff * COPYING in the main directory of this source tree, or the 8219820Sjeff * OpenIB.org BSD license below: 9219820Sjeff * 10219820Sjeff * Redistribution and use in source and binary forms, with or 11219820Sjeff * without modification, are permitted provided that the following 12219820Sjeff * conditions are met: 13219820Sjeff * 14219820Sjeff * - Redistributions of source code must retain the above 15219820Sjeff * copyright notice, this list of conditions and the following 16219820Sjeff * disclaimer. 17219820Sjeff * 18219820Sjeff * - Redistributions in binary form must reproduce the above 19219820Sjeff * copyright notice, this list of conditions and the following 20219820Sjeff * disclaimer in the documentation and/or other materials 21219820Sjeff * provided with the distribution. 22219820Sjeff * 23219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30219820Sjeff * SOFTWARE. 31219820Sjeff */ 32219820Sjeff 33219820Sjeff#include <linux/proc_fs.h> 34219820Sjeff#include <rdma/sdp_socket.h> 35219820Sjeff#include "sdp.h" 36219820Sjeff 37219820Sjeff#ifdef CONFIG_PROC_FS 38219820Sjeff 39219820Sjeff#define PROC_SDP_STATS "sdpstats" 40219820Sjeff#define PROC_SDP_PERF "sdpprf" 41219820Sjeff 42219820Sjeff/* just like TCP fs */ 43219820Sjeffstruct sdp_seq_afinfo { 44219820Sjeff struct module *owner; 45219820Sjeff char *name; 46219820Sjeff sa_family_t family; 47219820Sjeff int (*seq_show) (struct seq_file *m, void *v); 48219820Sjeff struct file_operations *seq_fops; 49219820Sjeff}; 50219820Sjeff 51219820Sjeffstruct sdp_iter_state { 52219820Sjeff sa_family_t family; 53219820Sjeff int num; 54219820Sjeff struct seq_operations seq_ops; 55219820Sjeff}; 56219820Sjeff 57219820Sjeffstatic void *sdp_get_idx(struct seq_file *seq, loff_t pos) 58219820Sjeff{ 59219820Sjeff int i = 0; 60219820Sjeff struct sdp_sock *ssk; 61219820Sjeff 62219820Sjeff if (!list_empty(&sock_list)) 63219820Sjeff list_for_each_entry(ssk, &sock_list, sock_list) { 64219820Sjeff if (i == pos) 65219820Sjeff return ssk; 66219820Sjeff i++; 67219820Sjeff } 68219820Sjeff 69219820Sjeff return NULL; 70219820Sjeff} 71219820Sjeff 72219820Sjeffstatic void *sdp_seq_start(struct seq_file *seq, loff_t *pos) 73219820Sjeff{ 74219820Sjeff void *start = NULL; 75219820Sjeff struct sdp_iter_state *st = seq->private; 76219820Sjeff 77219820Sjeff st->num = 0; 78219820Sjeff 79219820Sjeff if (!*pos) 80219820Sjeff return SEQ_START_TOKEN; 81219820Sjeff 82219820Sjeff spin_lock_irq(&sock_list_lock); 83219820Sjeff start = sdp_get_idx(seq, *pos - 1); 84219820Sjeff if (start) 85219820Sjeff sock_hold((struct socket *)start, SOCK_REF_SEQ); 86219820Sjeff spin_unlock_irq(&sock_list_lock); 87219820Sjeff 88219820Sjeff return start; 89219820Sjeff} 90219820Sjeff 91219820Sjeffstatic void *sdp_seq_next(struct seq_file *seq, void *v, loff_t *pos) 92219820Sjeff{ 93219820Sjeff struct sdp_iter_state *st = seq->private; 94219820Sjeff void *next = NULL; 95219820Sjeff 96219820Sjeff spin_lock_irq(&sock_list_lock); 97219820Sjeff if (v == SEQ_START_TOKEN) 98219820Sjeff next = sdp_get_idx(seq, 0); 99219820Sjeff else 100219820Sjeff next = sdp_get_idx(seq, *pos); 101219820Sjeff if (next) 102219820Sjeff sock_hold((struct socket *)next, SOCK_REF_SEQ); 103219820Sjeff spin_unlock_irq(&sock_list_lock); 104219820Sjeff 105219820Sjeff *pos += 1; 106219820Sjeff st->num++; 107219820Sjeff 108219820Sjeff return next; 109219820Sjeff} 110219820Sjeff 111219820Sjeffstatic void sdp_seq_stop(struct seq_file *seq, void *v) 112219820Sjeff{ 113219820Sjeff} 114219820Sjeff 115219820Sjeff#define TMPSZ 150 116219820Sjeff 117219820Sjeffstatic int sdp_seq_show(struct seq_file *seq, void *v) 118219820Sjeff{ 119219820Sjeff struct sdp_iter_state *st; 120219820Sjeff struct socket *sk = v; 121219820Sjeff char tmpbuf[TMPSZ + 1]; 122219820Sjeff unsigned int dest; 123219820Sjeff unsigned int src; 124219820Sjeff int uid; 125219820Sjeff unsigned long inode; 126219820Sjeff __u16 destp; 127219820Sjeff __u16 srcp; 128219820Sjeff __u32 rx_queue, tx_queue; 129219820Sjeff 130219820Sjeff if (v == SEQ_START_TOKEN) { 131219820Sjeff seq_printf(seq, "%-*s\n", TMPSZ - 1, 132219820Sjeff " sl local_address rem_address " 133219820Sjeff "uid inode rx_queue tx_queue state"); 134219820Sjeff goto out; 135219820Sjeff } 136219820Sjeff 137219820Sjeff st = seq->private; 138219820Sjeff 139219820Sjeff dest = inet_sk(sk)->daddr; 140219820Sjeff src = inet_sk(sk)->rcv_saddr; 141219820Sjeff destp = ntohs(inet_sk(sk)->dport); 142219820Sjeff srcp = ntohs(inet_sk(sk)->sport); 143219820Sjeff uid = sock_i_uid(sk); 144219820Sjeff inode = sock_i_ino(sk); 145219820Sjeff rx_queue = rcv_nxt(sdp_sk(sk)) - sdp_sk(sk)->copied_seq; 146219820Sjeff tx_queue = sdp_sk(sk)->write_seq - sdp_sk(sk)->tx_ring.una_seq; 147219820Sjeff 148219820Sjeff sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X %5d %lu %08X:%08X %X", 149219820Sjeff st->num, src, srcp, dest, destp, uid, inode, 150219820Sjeff rx_queue, tx_queue, sk->sk_state); 151219820Sjeff 152219820Sjeff seq_printf(seq, "%-*s\n", TMPSZ - 1, tmpbuf); 153219820Sjeff 154219820Sjeff sock_put(sk, SOCK_REF_SEQ); 155219820Sjeffout: 156219820Sjeff return 0; 157219820Sjeff} 158219820Sjeff 159219820Sjeffstatic int sdp_seq_open(struct inode *inode, struct file *file) 160219820Sjeff{ 161219820Sjeff struct sdp_seq_afinfo *afinfo = PDE(inode)->data; 162219820Sjeff struct seq_file *seq; 163219820Sjeff struct sdp_iter_state *s; 164219820Sjeff int rc; 165219820Sjeff 166219820Sjeff if (unlikely(afinfo == NULL)) 167219820Sjeff return -EINVAL; 168219820Sjeff 169219820Sjeff/* Workaround bogus warning by memtrack */ 170219820Sjeff#define _kzalloc(size,flags) kzalloc(size,flags) 171219820Sjeff#undef kzalloc 172219820Sjeff s = kzalloc(sizeof(*s), GFP_KERNEL); 173219820Sjeff#define kzalloc(s,f) _kzalloc(s,f) 174219820Sjeff if (!s) 175219820Sjeff return -ENOMEM; 176219820Sjeff s->family = afinfo->family; 177219820Sjeff s->seq_ops.start = sdp_seq_start; 178219820Sjeff s->seq_ops.next = sdp_seq_next; 179219820Sjeff s->seq_ops.show = afinfo->seq_show; 180219820Sjeff s->seq_ops.stop = sdp_seq_stop; 181219820Sjeff 182219820Sjeff rc = seq_open(file, &s->seq_ops); 183219820Sjeff if (rc) 184219820Sjeff goto out_kfree; 185219820Sjeff seq = file->private_data; 186219820Sjeff seq->private = s; 187219820Sjeffout: 188219820Sjeff return rc; 189219820Sjeffout_kfree: 190219820Sjeff kfree(s); 191219820Sjeff goto out; 192219820Sjeff} 193219820Sjeff 194219820Sjeff 195219820Sjeffstatic struct file_operations sdp_seq_fops; 196219820Sjeffstatic struct sdp_seq_afinfo sdp_seq_afinfo = { 197219820Sjeff .owner = THIS_MODULE, 198219820Sjeff .name = "sdp", 199219820Sjeff .family = AF_INET_SDP, 200219820Sjeff .seq_show = sdp_seq_show, 201219820Sjeff .seq_fops = &sdp_seq_fops, 202219820Sjeff}; 203219820Sjeff 204219820Sjeff#ifdef SDPSTATS_ON 205219820SjeffDEFINE_PER_CPU(struct sdpstats, sdpstats); 206219820Sjeff 207219820Sjeffstatic void sdpstats_seq_hist(struct seq_file *seq, char *str, u32 *h, int n, 208219820Sjeff int is_log) 209219820Sjeff{ 210219820Sjeff int i; 211219820Sjeff u32 max = 0; 212219820Sjeff 213219820Sjeff seq_printf(seq, "%s:\n", str); 214219820Sjeff 215219820Sjeff for (i = 0; i < n; i++) { 216219820Sjeff if (h[i] > max) 217219820Sjeff max = h[i]; 218219820Sjeff } 219219820Sjeff 220219820Sjeff if (max == 0) { 221219820Sjeff seq_printf(seq, " - all values are 0\n"); 222219820Sjeff return; 223219820Sjeff } 224219820Sjeff 225219820Sjeff for (i = 0; i < n; i++) { 226219820Sjeff char s[51]; 227219820Sjeff int j = 50 * h[i] / max; 228219820Sjeff int val = is_log ? (i == n-1 ? 0 : 1<<i) : i; 229219820Sjeff memset(s, '*', j); 230219820Sjeff s[j] = '\0'; 231219820Sjeff 232219820Sjeff seq_printf(seq, "%10d | %-50s - %d\n", val, s, h[i]); 233219820Sjeff } 234219820Sjeff} 235219820Sjeff 236219820Sjeff#define SDPSTATS_COUNTER_GET(var) ({ \ 237219820Sjeff u32 __val = 0; \ 238219820Sjeff unsigned int __i; \ 239219820Sjeff for_each_possible_cpu(__i) \ 240219820Sjeff __val += per_cpu(sdpstats, __i).var; \ 241219820Sjeff __val; \ 242219820Sjeff}) 243219820Sjeff 244219820Sjeff#define SDPSTATS_HIST_GET(hist, hist_len, sum) ({ \ 245219820Sjeff unsigned int __i; \ 246219820Sjeff for_each_possible_cpu(__i) { \ 247219820Sjeff unsigned int __j; \ 248219820Sjeff u32 *h = per_cpu(sdpstats, __i).hist; \ 249219820Sjeff for (__j = 0; __j < hist_len; __j++) { \ 250219820Sjeff sum[__j] += h[__j]; \ 251219820Sjeff } \ 252219820Sjeff } \ 253219820Sjeff}) 254219820Sjeff 255219820Sjeff#define __sdpstats_seq_hist(seq, msg, hist, is_log) ({ \ 256219820Sjeff u32 tmp_hist[SDPSTATS_MAX_HIST_SIZE]; \ 257219820Sjeff int hist_len = ARRAY_SIZE(__get_cpu_var(sdpstats).hist);\ 258219820Sjeff memset(tmp_hist, 0, sizeof(tmp_hist)); \ 259219820Sjeff SDPSTATS_HIST_GET(hist, hist_len, tmp_hist); \ 260219820Sjeff sdpstats_seq_hist(seq, msg, tmp_hist, hist_len, is_log);\ 261219820Sjeff}) 262219820Sjeff 263219820Sjeffstatic int sdpstats_seq_show(struct seq_file *seq, void *v) 264219820Sjeff{ 265219820Sjeff int i; 266219820Sjeff 267219820Sjeff seq_printf(seq, "SDP statistics:\n"); 268219820Sjeff 269219820Sjeff __sdpstats_seq_hist(seq, "sendmsg_seglen", sendmsg_seglen, 1); 270219820Sjeff __sdpstats_seq_hist(seq, "send_size", send_size, 1); 271219820Sjeff __sdpstats_seq_hist(seq, "credits_before_update", 272219820Sjeff credits_before_update, 0); 273219820Sjeff 274219820Sjeff seq_printf(seq, "sdp_sendmsg() calls\t\t: %d\n", 275219820Sjeff SDPSTATS_COUNTER_GET(sendmsg)); 276219820Sjeff seq_printf(seq, "bcopy segments \t\t: %d\n", 277219820Sjeff SDPSTATS_COUNTER_GET(sendmsg_bcopy_segment)); 278219820Sjeff seq_printf(seq, "bzcopy segments \t\t: %d\n", 279219820Sjeff SDPSTATS_COUNTER_GET(sendmsg_bzcopy_segment)); 280219820Sjeff seq_printf(seq, "zcopy segments \t\t: %d\n", 281219820Sjeff SDPSTATS_COUNTER_GET(sendmsg_zcopy_segment)); 282219820Sjeff seq_printf(seq, "post_send_credits \t\t: %d\n", 283219820Sjeff SDPSTATS_COUNTER_GET(post_send_credits)); 284219820Sjeff seq_printf(seq, "memcpy_count \t\t: %u\n", 285219820Sjeff SDPSTATS_COUNTER_GET(memcpy_count)); 286219820Sjeff 287219820Sjeff for (i = 0; i < ARRAY_SIZE(__get_cpu_var(sdpstats).post_send); i++) { 288219820Sjeff if (mid2str(i)) { 289219820Sjeff seq_printf(seq, "post_send %-20s\t: %d\n", 290219820Sjeff mid2str(i), 291219820Sjeff SDPSTATS_COUNTER_GET(post_send[i])); 292219820Sjeff } 293219820Sjeff } 294219820Sjeff 295219820Sjeff seq_printf(seq, "\n"); 296219820Sjeff seq_printf(seq, "post_recv \t\t: %d\n", 297219820Sjeff SDPSTATS_COUNTER_GET(post_recv)); 298219820Sjeff seq_printf(seq, "BZCopy poll miss \t\t: %d\n", 299219820Sjeff SDPSTATS_COUNTER_GET(bzcopy_poll_miss)); 300219820Sjeff seq_printf(seq, "send_wait_for_mem \t\t: %d\n", 301219820Sjeff SDPSTATS_COUNTER_GET(send_wait_for_mem)); 302219820Sjeff seq_printf(seq, "send_miss_no_credits\t\t: %d\n", 303219820Sjeff SDPSTATS_COUNTER_GET(send_miss_no_credits)); 304219820Sjeff 305219820Sjeff seq_printf(seq, "rx_poll_miss \t\t: %d\n", SDPSTATS_COUNTER_GET(rx_poll_miss)); 306219820Sjeff seq_printf(seq, "tx_poll_miss \t\t: %d\n", SDPSTATS_COUNTER_GET(tx_poll_miss)); 307219820Sjeff seq_printf(seq, "tx_poll_busy \t\t: %d\n", SDPSTATS_COUNTER_GET(tx_poll_busy)); 308219820Sjeff seq_printf(seq, "tx_poll_hit \t\t: %d\n", SDPSTATS_COUNTER_GET(tx_poll_hit)); 309219820Sjeff 310219820Sjeff seq_printf(seq, "CQ stats:\n"); 311219820Sjeff seq_printf(seq, "- RX interrupts\t\t: %d\n", SDPSTATS_COUNTER_GET(rx_int_count)); 312219820Sjeff seq_printf(seq, "- TX interrupts\t\t: %d\n", SDPSTATS_COUNTER_GET(tx_int_count)); 313219820Sjeff 314219820Sjeff seq_printf(seq, "ZCopy stats:\n"); 315219820Sjeff seq_printf(seq, "- TX timeout\t\t: %d\n", SDPSTATS_COUNTER_GET(zcopy_tx_timeout)); 316219820Sjeff seq_printf(seq, "- TX cross send\t\t: %d\n", SDPSTATS_COUNTER_GET(zcopy_cross_send)); 317219820Sjeff seq_printf(seq, "- TX aborted by peer\t: %d\n", SDPSTATS_COUNTER_GET(zcopy_tx_aborted)); 318219820Sjeff seq_printf(seq, "- TX error\t\t: %d\n", SDPSTATS_COUNTER_GET(zcopy_tx_error)); 319219820Sjeff return 0; 320219820Sjeff} 321219820Sjeff 322219820Sjeffstatic ssize_t sdpstats_write(struct file *file, const char __user *buf, 323219820Sjeff size_t count, loff_t *offs) 324219820Sjeff{ 325219820Sjeff int i; 326219820Sjeff 327219820Sjeff for_each_possible_cpu(i) 328219820Sjeff memset(&per_cpu(sdpstats, i), 0, sizeof(struct sdpstats)); 329219820Sjeff printk(KERN_WARNING "Cleared sdp statistics\n"); 330219820Sjeff 331219820Sjeff return count; 332219820Sjeff} 333219820Sjeff 334219820Sjeffstatic int sdpstats_seq_open(struct inode *inode, struct file *file) 335219820Sjeff{ 336219820Sjeff return single_open(file, sdpstats_seq_show, NULL); 337219820Sjeff} 338219820Sjeff 339219820Sjeffstatic struct file_operations sdpstats_fops = { 340219820Sjeff .owner = THIS_MODULE, 341219820Sjeff .open = sdpstats_seq_open, 342219820Sjeff .read = seq_read, 343219820Sjeff .write = sdpstats_write, 344219820Sjeff .llseek = seq_lseek, 345219820Sjeff .release = single_release, 346219820Sjeff}; 347219820Sjeff 348219820Sjeff#endif 349219820Sjeff 350219820Sjeff#ifdef SDP_PROFILING 351219820Sjeffstruct sdpprf_log sdpprf_log[SDPPRF_LOG_SIZE]; 352219820Sjeffint sdpprf_log_count; 353219820Sjeff 354219820Sjeffstatic unsigned long long start_t; 355219820Sjeff 356219820Sjeffstatic int sdpprf_show(struct seq_file *m, void *v) 357219820Sjeff{ 358219820Sjeff struct sdpprf_log *l = v; 359219820Sjeff unsigned long nsec_rem, t; 360219820Sjeff 361219820Sjeff if (!sdpprf_log_count) { 362219820Sjeff seq_printf(m, "No performance logs\n"); 363219820Sjeff goto out; 364219820Sjeff } 365219820Sjeff 366219820Sjeff t = l->time - start_t; 367219820Sjeff nsec_rem = do_div(t, 1000000000); 368219820Sjeff 369219820Sjeff seq_printf(m, "%-6d: [%5lu.%06lu] %-50s - [%d{%d} %d:%d] " 370219820Sjeff "mb: %p %s:%d\n", 371219820Sjeff l->idx, (unsigned long)t, nsec_rem/1000, 372219820Sjeff l->msg, l->pid, l->cpu, l->sk_num, l->sk_dport, 373219820Sjeff l->mb, l->func, l->line); 374219820Sjeffout: 375219820Sjeff return 0; 376219820Sjeff} 377219820Sjeff 378219820Sjeffstatic void *sdpprf_start(struct seq_file *p, loff_t *pos) 379219820Sjeff{ 380219820Sjeff int idx = *pos; 381219820Sjeff 382219820Sjeff if (!*pos) { 383219820Sjeff if (!sdpprf_log_count) 384219820Sjeff return SEQ_START_TOKEN; 385219820Sjeff } 386219820Sjeff 387219820Sjeff if (*pos >= MIN(sdpprf_log_count, SDPPRF_LOG_SIZE - 1)) 388219820Sjeff return NULL; 389219820Sjeff 390219820Sjeff if (sdpprf_log_count >= SDPPRF_LOG_SIZE - 1) { 391219820Sjeff int off = sdpprf_log_count & (SDPPRF_LOG_SIZE - 1); 392219820Sjeff idx = (idx + off) & (SDPPRF_LOG_SIZE - 1); 393219820Sjeff 394219820Sjeff } 395219820Sjeff 396219820Sjeff if (!start_t) 397219820Sjeff start_t = sdpprf_log[idx].time; 398219820Sjeff return &sdpprf_log[idx]; 399219820Sjeff} 400219820Sjeff 401219820Sjeffstatic void *sdpprf_next(struct seq_file *p, void *v, loff_t *pos) 402219820Sjeff{ 403219820Sjeff struct sdpprf_log *l = v; 404219820Sjeff 405219820Sjeff if (++*pos >= MIN(sdpprf_log_count, SDPPRF_LOG_SIZE - 1)) 406219820Sjeff return NULL; 407219820Sjeff 408219820Sjeff ++l; 409219820Sjeff if (l - &sdpprf_log[0] >= SDPPRF_LOG_SIZE - 1) 410219820Sjeff return &sdpprf_log[0]; 411219820Sjeff 412219820Sjeff return l; 413219820Sjeff} 414219820Sjeff 415219820Sjeffstatic void sdpprf_stop(struct seq_file *p, void *v) 416219820Sjeff{ 417219820Sjeff} 418219820Sjeff 419219820Sjeffstatic struct seq_operations sdpprf_ops = { 420219820Sjeff .start = sdpprf_start, 421219820Sjeff .stop = sdpprf_stop, 422219820Sjeff .next = sdpprf_next, 423219820Sjeff .show = sdpprf_show, 424219820Sjeff}; 425219820Sjeff 426219820Sjeffstatic int sdpprf_open(struct inode *inode, struct file *file) 427219820Sjeff{ 428219820Sjeff int res; 429219820Sjeff 430219820Sjeff res = seq_open(file, &sdpprf_ops); 431219820Sjeff 432219820Sjeff return res; 433219820Sjeff} 434219820Sjeff 435219820Sjeffstatic ssize_t sdpprf_write(struct file *file, const char __user *buf, 436219820Sjeff size_t count, loff_t *offs) 437219820Sjeff{ 438219820Sjeff sdpprf_log_count = 0; 439219820Sjeff printk(KERN_INFO "Cleared sdpprf statistics\n"); 440219820Sjeff 441219820Sjeff return count; 442219820Sjeff} 443219820Sjeff 444219820Sjeffstatic struct file_operations sdpprf_fops = { 445219820Sjeff .open = sdpprf_open, 446219820Sjeff .read = seq_read, 447219820Sjeff .llseek = seq_lseek, 448219820Sjeff .release = seq_release, 449219820Sjeff .write = sdpprf_write, 450219820Sjeff}; 451219820Sjeff#endif /* SDP_PROFILING */ 452219820Sjeff 453219820Sjeffint __init sdp_proc_init(void) 454219820Sjeff{ 455219820Sjeff struct proc_dir_entry *p = NULL; 456219820Sjeff#ifdef SDPSTATS_ON 457219820Sjeff struct proc_dir_entry *stats = NULL; 458219820Sjeff#endif 459219820Sjeff#ifdef SDP_PROFILING 460219820Sjeff struct proc_dir_entry *prof = NULL; 461219820Sjeff#endif 462219820Sjeff 463219820Sjeff sdp_seq_afinfo.seq_fops->owner = sdp_seq_afinfo.owner; 464219820Sjeff sdp_seq_afinfo.seq_fops->open = sdp_seq_open; 465219820Sjeff sdp_seq_afinfo.seq_fops->read = seq_read; 466219820Sjeff sdp_seq_afinfo.seq_fops->llseek = seq_lseek; 467219820Sjeff sdp_seq_afinfo.seq_fops->release = seq_release_private; 468219820Sjeff 469219820Sjeff p = proc_net_fops_create(&init_net, sdp_seq_afinfo.name, S_IRUGO, 470219820Sjeff sdp_seq_afinfo.seq_fops); 471219820Sjeff if (p) 472219820Sjeff p->data = &sdp_seq_afinfo; 473219820Sjeff else 474219820Sjeff goto no_mem; 475219820Sjeff 476219820Sjeff#ifdef SDPSTATS_ON 477219820Sjeff 478219820Sjeff stats = proc_net_fops_create(&init_net, PROC_SDP_STATS, 479219820Sjeff S_IRUGO | S_IWUGO, &sdpstats_fops); 480219820Sjeff if (!stats) 481219820Sjeff goto no_mem_stats; 482219820Sjeff 483219820Sjeff#endif 484219820Sjeff 485219820Sjeff#ifdef SDP_PROFILING 486219820Sjeff prof = proc_net_fops_create(&init_net, PROC_SDP_PERF, 487219820Sjeff S_IRUGO | S_IWUGO, &sdpprf_fops); 488219820Sjeff if (!prof) 489219820Sjeff goto no_mem_prof; 490219820Sjeff#endif 491219820Sjeff 492219820Sjeff return 0; 493219820Sjeff 494219820Sjeff#ifdef SDP_PROFILING 495219820Sjeffno_mem_prof: 496219820Sjeff#endif 497219820Sjeff 498219820Sjeff#ifdef SDPSTATS_ON 499219820Sjeff proc_net_remove(&init_net, PROC_SDP_STATS); 500219820Sjeff 501219820Sjeffno_mem_stats: 502219820Sjeff#endif 503219820Sjeff proc_net_remove(&init_net, sdp_seq_afinfo.name); 504219820Sjeff 505219820Sjeffno_mem: 506219820Sjeff return -ENOMEM; 507219820Sjeff} 508219820Sjeff 509219820Sjeffvoid sdp_proc_unregister(void) 510219820Sjeff{ 511219820Sjeff proc_net_remove(&init_net, sdp_seq_afinfo.name); 512219820Sjeff memset(sdp_seq_afinfo.seq_fops, 0, sizeof(*sdp_seq_afinfo.seq_fops)); 513219820Sjeff 514219820Sjeff#ifdef SDPSTATS_ON 515219820Sjeff proc_net_remove(&init_net, PROC_SDP_STATS); 516219820Sjeff#endif 517219820Sjeff#ifdef SDP_PROFILING 518219820Sjeff proc_net_remove(&init_net, PROC_SDP_PERF); 519219820Sjeff#endif 520219820Sjeff} 521219820Sjeff 522219820Sjeff#else /* CONFIG_PROC_FS */ 523219820Sjeff 524219820Sjeffint __init sdp_proc_init(void) 525219820Sjeff{ 526219820Sjeff return 0; 527219820Sjeff} 528219820Sjeff 529219820Sjeffvoid sdp_proc_unregister(void) 530219820Sjeff{ 531219820Sjeff 532219820Sjeff} 533219820Sjeff#endif /* CONFIG_PROC_FS */ 534