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