Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id ; Sat, 23 Nov 2002 21:37:38 -0500 Received: (majordomo@vger.kernel.org) by vger.kernel.org id ; Sat, 23 Nov 2002 21:37:38 -0500 Received: from 5-005.ctame701-2.telepar.net.br ([200.181.169.5]:11015 "EHLO brinquendo.conectiva.com.br") by vger.kernel.org with ESMTP id ; Sat, 23 Nov 2002 21:37:30 -0500 Date: Sun, 24 Nov 2002 00:00:46 -0200 From: Arnaldo Carvalho de Melo To: "David S. Miller" Cc: Linux Kernel Mailing List Subject: [PATCH] tcpv4: convert /proc/net/tcp to seq_file Message-ID: <20021124020046.GA29645@conectiva.com.br> Mail-Followup-To: Arnaldo Carvalho de Melo , "David S. Miller" , Linux Kernel Mailing List Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.4i X-Url: http://advogato.org/person/acme Sender: linux-kernel-owner@vger.kernel.org X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 17730 Lines: 651 Hi David, Handle with care and please pull from: master.kernel.org:/home/acme/BK/net-2.5 Now there are two outstanding changesets :-) - Arnaldo You can import this changeset into BK by piping this whole message to: '| bk receive [path to repository]' or apply the patch as usual. =================================================================== ChangeSet@1.859, 2002-11-23 23:49:24-02:00, acme@conectiva.com.br o tcpv4: convert /proc/net/tcp to seq_file af_inet.c | 7 tcp_ipv4.c | 480 +++++++++++++++++++++++++++++++++++++++++++++---------------- 2 files changed, 365 insertions(+), 122 deletions(-) diff -Nru a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c --- a/net/ipv4/af_inet.c Sat Nov 23 23:56:58 2002 +++ b/net/ipv4/af_inet.c Sat Nov 23 23:56:58 2002 @@ -1165,7 +1165,8 @@ extern int ip_misc_proc_init(void); extern int raw_proc_init(void); extern void raw_proc_exit(void); -extern int tcp_get_info(char *buffer, char **start, off_t offset, int length); +extern int tcp_proc_init(void); +extern void tcp_proc_exit(void); extern int udp_proc_init(void); extern void udp_proc_exit(void); @@ -1175,7 +1176,7 @@ if (raw_proc_init()) goto out_raw; - if (!proc_net_create("tcp", 0, tcp_get_info)) + if (tcp_proc_init()) goto out_tcp; if (udp_proc_init()) goto out_udp; @@ -1190,7 +1191,7 @@ out_fib: udp_proc_exit(); out_udp: - proc_net_remove("tcp"); + tcp_proc_exit(); out_tcp: raw_proc_exit(); out_raw: diff -Nru a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c --- a/net/ipv4/tcp_ipv4.c Sat Nov 23 23:56:58 2002 +++ b/net/ipv4/tcp_ipv4.c Sat Nov 23 23:56:58 2002 @@ -69,6 +69,8 @@ #include #include #include +#include +#include extern int sysctl_ip_dynaddr; extern int sysctl_ip_default_ttl; @@ -2131,7 +2133,295 @@ return 0; } +#ifdef CONFIG_PROC_FS /* Proc filesystem TCP sock list dumping. */ + +enum tcp_seq_states { + TCP_SEQ_STATE_LISTENING, + TCP_SEQ_STATE_OPENREQ, + TCP_SEQ_STATE_ESTABLISHED, + TCP_SEQ_STATE_TIME_WAIT, +}; + +struct tcp_iter_state { + enum tcp_seq_states state; + struct sock *syn_wait_sk; + int bucket, sbucket, num, uid; +}; + +static void *listening_get_first(struct seq_file *seq) +{ + struct tcp_iter_state* st = seq->private; + void *rc = NULL; + + for (st->bucket = 0; st->bucket < TCP_LHTABLE_SIZE; ++st->bucket) { + struct open_request *req; + struct tcp_opt *tp; + struct sock *sk = tcp_listening_hash[st->bucket]; + + if (!sk) + continue; + ++st->num; + if (TCP_INET_FAMILY(sk->family)) { + rc = sk; + goto out; + } + tp = tcp_sk(sk); + read_lock_bh(&tp->syn_wait_lock); + if (tp->listen_opt && tp->listen_opt->qlen) { + st->uid = sock_i_uid(sk); + st->syn_wait_sk = sk; + st->state = TCP_SEQ_STATE_OPENREQ; + for (st->sbucket = 0; st->sbucket < TCP_SYNQ_HSIZE; + ++st->sbucket) { + for (req = tp->listen_opt->syn_table[st->sbucket]; + req; req = req->dl_next, ++st->num) { + if (!TCP_INET_FAMILY(req->class->family)) + continue; + rc = req; + goto out; + } + } + st->state = TCP_SEQ_STATE_LISTENING; + } + read_unlock_bh(&tp->syn_wait_lock); + } +out: + return rc; +} + +static void *listening_get_next(struct seq_file *seq, void *cur) +{ + struct tcp_opt *tp; + struct sock *sk = cur; + struct tcp_iter_state* st = seq->private; + + if (st->state == TCP_SEQ_STATE_OPENREQ) { + struct open_request *req = cur; + + tp = tcp_sk(st->syn_wait_sk); + req = req->dl_next; + while (1) { + while (req) { + ++st->num; + if (TCP_INET_FAMILY(req->class->family)) { + cur = req; + goto out; + } + req = req->dl_next; + } + if (++st->sbucket >= TCP_SYNQ_HSIZE) + break; +get_req: + req = tp->listen_opt->syn_table[st->sbucket]; + } + sk = st->syn_wait_sk->next; + st->state = TCP_SEQ_STATE_LISTENING; + read_unlock_bh(&tp->syn_wait_lock); + } else + sk = sk->next; +get_sk: + while (sk) { + if (TCP_INET_FAMILY(sk->family)) { + cur = sk; + goto out; + } + tp = tcp_sk(sk); + read_lock_bh(&tp->syn_wait_lock); + if (tp->listen_opt && tp->listen_opt->qlen) { + st->uid = sock_i_uid(sk); + st->syn_wait_sk = sk; + st->state = TCP_SEQ_STATE_OPENREQ; + st->sbucket = 0; + goto get_req; + } + read_unlock_bh(&tp->syn_wait_lock); + } + if (++st->bucket < TCP_LHTABLE_SIZE) { + sk = tcp_listening_hash[st->bucket]; + goto get_sk; + } + cur = NULL; +out: + return cur; +} + +static void *listening_get_idx(struct seq_file *seq, loff_t *pos) +{ + void *rc = listening_get_first(seq); + + if (rc) + while (*pos && (rc = listening_get_next(seq, rc))) + --*pos; + return *pos ? NULL : rc; +} + +static void *established_get_first(struct seq_file *seq) +{ + struct tcp_iter_state* st = seq->private; + void *rc = NULL; + + for (st->bucket = 0; st->bucket < tcp_ehash_size; ++st->bucket) { + struct sock *sk; + struct tcp_tw_bucket *tw; + + read_lock(&tcp_ehash[st->bucket].lock); + for (sk = tcp_ehash[st->bucket].chain; sk; + sk = sk->next, ++st->num) { + if (!TCP_INET_FAMILY(sk->family)) + continue; + rc = sk; + goto out; + } + st->state = TCP_SEQ_STATE_TIME_WAIT; + for (tw = (struct tcp_tw_bucket *) + tcp_ehash[st->bucket + tcp_ehash_size].chain; + tw; tw = (struct tcp_tw_bucket *)tw->next, ++st->num) { + if (!TCP_INET_FAMILY(tw->family)) + continue; + rc = tw; + goto out; + } + read_unlock(&tcp_ehash[st->bucket].lock); + st->state = TCP_SEQ_STATE_ESTABLISHED; + } +out: + return rc; +} + +static void *established_get_next(struct seq_file *seq, void *cur) +{ + struct sock *sk = cur; + struct tcp_tw_bucket *tw; + struct tcp_iter_state* st = seq->private; + + if (st->state == TCP_SEQ_STATE_TIME_WAIT) { + tw = cur; + tw = (struct tcp_tw_bucket *)tw->next; +get_tw: + while (tw && !TCP_INET_FAMILY(tw->family)) { + ++st->num; + tw = (struct tcp_tw_bucket *)tw->next; + } + if (tw) { + cur = tw; + goto out; + } + read_unlock(&tcp_ehash[st->bucket].lock); + st->state = TCP_SEQ_STATE_ESTABLISHED; + if (++st->bucket < tcp_ehash_size) { + read_lock(&tcp_ehash[st->bucket].lock); + sk = tcp_ehash[st->bucket].chain; + } else { + cur = NULL; + goto out; + } + } else + sk = sk->next; + + while (sk && !TCP_INET_FAMILY(sk->family)) { + ++st->num; + sk = sk->next; + } + if (!sk) { + st->state = TCP_SEQ_STATE_TIME_WAIT; + tw = (struct tcp_tw_bucket *) + tcp_ehash[st->bucket + tcp_ehash_size].chain; + goto get_tw; + } + cur = sk; +out: + return cur; +} + +static void *established_get_idx(struct seq_file *seq, loff_t pos) +{ + void *rc = established_get_first(seq); + + if (rc) + while (pos && (rc = established_get_next(seq, rc))) + --pos; + return pos ? NULL : rc; +} + +static void *tcp_get_idx(struct seq_file *seq, loff_t pos) +{ + void *rc; + struct tcp_iter_state* st = seq->private; + + tcp_listen_lock(); + st->state = TCP_SEQ_STATE_LISTENING; + rc = listening_get_idx(seq, &pos); + + if (!rc) { + tcp_listen_unlock(); + local_bh_disable(); + st->state = TCP_SEQ_STATE_ESTABLISHED; + rc = established_get_idx(seq, pos); + } + + return rc; +} + +static void *tcp_seq_start(struct seq_file *seq, loff_t *pos) +{ + return *pos ? tcp_get_idx(seq, *pos - 1) : (void *)1; +} + +static void *tcp_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + void *rc = NULL; + struct tcp_iter_state* st; + + if (v == (void *)1) { + rc = tcp_get_idx(seq, 0); + goto out; + } + st = seq->private; + + switch (st->state) { + case TCP_SEQ_STATE_OPENREQ: + case TCP_SEQ_STATE_LISTENING: + rc = listening_get_next(seq, v); + if (!rc) { + tcp_listen_unlock(); + local_bh_disable(); + st->state = TCP_SEQ_STATE_ESTABLISHED; + rc = established_get_first(seq); + } + break; + case TCP_SEQ_STATE_ESTABLISHED: + case TCP_SEQ_STATE_TIME_WAIT: + rc = established_get_next(seq, v); + break; + } +out: + ++*pos; + return rc; +} + +static void tcp_seq_stop(struct seq_file *seq, void *v) +{ + struct tcp_iter_state* st = seq->private; + + switch (st->state) { + case TCP_SEQ_STATE_OPENREQ: + if (v) { + struct tcp_opt *tp = tcp_sk(st->syn_wait_sk); + read_unlock_bh(&tp->syn_wait_lock); + } + case TCP_SEQ_STATE_LISTENING: + tcp_listen_unlock(); + break; + case TCP_SEQ_STATE_TIME_WAIT: + case TCP_SEQ_STATE_ESTABLISHED: + if (v) + read_unlock(&tcp_ehash[st->bucket].lock); + local_bh_enable(); + break; + } +} + static void get_openreq(struct sock *sk, struct open_request *req, char *tmpbuf, int i, int uid) { @@ -2219,137 +2509,89 @@ #define TMPSZ 150 -int tcp_get_info(char *buffer, char **start, off_t offset, int length) +static int tcp_seq_show(struct seq_file *seq, void *v) { - int len = 0, num = 0, i; - off_t begin, pos = 0; + struct tcp_iter_state* st; char tmpbuf[TMPSZ + 1]; - if (offset < TMPSZ) - len += sprintf(buffer, "%-*s\n", TMPSZ - 1, - " sl local_address rem_address st tx_queue " - "rx_queue tr tm->when retrnsmt uid timeout " - "inode"); - - pos = TMPSZ; - - /* First, walk listening socket table. */ - tcp_listen_lock(); - for (i = 0; i < TCP_LHTABLE_SIZE; i++) { - struct sock *sk; - struct tcp_listen_opt *lopt; - int k; - - for (sk = tcp_listening_hash[i]; sk; sk = sk->next, num++) { - struct open_request *req; - int uid; - struct tcp_opt *tp = tcp_sk(sk); - - if (!TCP_INET_FAMILY(sk->family)) - goto skip_listen; + if (v == (void *)1) { + seq_printf(seq, "%-*s\n", TMPSZ - 1, + " sl local_address rem_address st tx_queue " + "rx_queue tr tm->when retrnsmt uid timeout " + "inode"); + goto out; + } + st = seq->private; - pos += TMPSZ; - if (pos >= offset) { - get_tcp_sock(sk, tmpbuf, num); - len += sprintf(buffer + len, "%-*s\n", - TMPSZ - 1, tmpbuf); - if (pos >= offset + length) { - tcp_listen_unlock(); - goto out_no_bh; - } - } + switch (st->state) { + case TCP_SEQ_STATE_LISTENING: + case TCP_SEQ_STATE_ESTABLISHED: + get_tcp_sock(v, tmpbuf, st->num); + break; + case TCP_SEQ_STATE_OPENREQ: + get_openreq(st->syn_wait_sk, v, tmpbuf, st->num, st->uid); + break; + case TCP_SEQ_STATE_TIME_WAIT: + get_timewait_sock(v, tmpbuf, st->num); + break; + } + seq_printf(seq, "%-*s\n", TMPSZ - 1, tmpbuf); +out: + return 0; +} -skip_listen: - uid = sock_i_uid(sk); - read_lock_bh(&tp->syn_wait_lock); - lopt = tp->listen_opt; - if (lopt && lopt->qlen) { - for (k = 0; k < TCP_SYNQ_HSIZE; k++) { - for (req = lopt->syn_table[k]; - req; req = req->dl_next, num++) { - if (!TCP_INET_FAMILY(req->class->family)) - continue; - - pos += TMPSZ; - if (pos <= offset) - continue; - get_openreq(sk, req, tmpbuf, - num, uid); - len += sprintf(buffer + len, - "%-*s\n", - TMPSZ - 1, - tmpbuf); - if (pos >= offset + length) { - read_unlock_bh(&tp->syn_wait_lock); - tcp_listen_unlock(); - goto out_no_bh; - } - } - } - } - read_unlock_bh(&tp->syn_wait_lock); +static struct seq_operations tcp_seq_ops = { + .start = tcp_seq_start, + .next = tcp_seq_next, + .stop = tcp_seq_stop, + .show = tcp_seq_show, +}; - /* Completed requests are in normal socket hash table */ - } - } - tcp_listen_unlock(); +static int tcp_seq_open(struct inode *inode, struct file *file) +{ + struct seq_file *seq; + int rc = -ENOMEM; + struct tcp_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL); - local_bh_disable(); + if (!s) + goto out; + rc = seq_open(file, &tcp_seq_ops); + if (rc) + goto out_kfree; + seq = file->private_data; + seq->private = s; + memset(s, 0, sizeof(*s)); +out: + return rc; +out_kfree: + kfree(s); + goto out; +} - /* Next, walk established hash chain. */ - for (i = 0; i < tcp_ehash_size; i++) { - struct tcp_ehash_bucket *head = &tcp_ehash[i]; - struct sock *sk; - struct tcp_tw_bucket *tw; +static struct file_operations tcp_seq_fops = { + .open = tcp_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = ip_seq_release, +}; - read_lock(&head->lock); - for (sk = head->chain; sk; sk = sk->next, num++) { - if (!TCP_INET_FAMILY(sk->family)) - continue; - pos += TMPSZ; - if (pos <= offset) - continue; - get_tcp_sock(sk, tmpbuf, num); - len += sprintf(buffer + len, "%-*s\n", - TMPSZ - 1, tmpbuf); - if (pos >= offset + length) { - read_unlock(&head->lock); - goto out; - } - } - for (tw = (struct tcp_tw_bucket *)tcp_ehash[i + - tcp_ehash_size].chain; - tw; - tw = (struct tcp_tw_bucket *)tw->next, num++) { - if (!TCP_INET_FAMILY(tw->family)) - continue; - pos += TMPSZ; - if (pos <= offset) - continue; - get_timewait_sock(tw, tmpbuf, num); - len += sprintf(buffer + len, "%-*s\n", - TMPSZ - 1, tmpbuf); - if (pos >= offset + length) { - read_unlock(&head->lock); - goto out; - } - } - read_unlock(&head->lock); - } +int __init tcp_proc_init(void) +{ + int rc = 0; + struct proc_dir_entry *p = create_proc_entry("tcp", S_IRUGO, proc_net); -out: - local_bh_enable(); -out_no_bh: + if (p) + p->proc_fops = &tcp_seq_fops; + else + rc = -ENOMEM; + return rc; +} - begin = len - (pos - offset); - *start = buffer + begin; - len -= begin; - if (len > length) - len = length; - if (len < 0) - len = 0; - return len; +void __init tcp_proc_exit(void) +{ + remove_proc_entry("tcp", proc_net); } +#endif /* CONFIG_PROC_FS */ struct proto tcp_prot = { .name = "TCP", =================================================================== This BitKeeper patch contains the following changesets: 1.859 ## Wrapped with gzip_uu ## begin 664 bkpatch2986 M'XL(`.HQX#T``^5:^7/:R!+^6?HK)DZ]%-B`=7$OWEPDH>+8CNW4J]W-EDH6 M0U`!$I8&D^PZ__OKGM&-Q)%*O7U5S[L58(Z>K[N_/@;QE'P*J-^3+'M!Y:?D MG1>PGF1[+K69\V`U;&_1N/-AXMKS8.)TZBWHZU)U\.WG\Y?7,OR8$!>32WW"[VAC`P&,O/\!VL^#IY;;#KW MW`;S+3=84,;/?(R7/FJ*HL%_3;6M*\W6H]I2C/:CK8Y5U3)4.E8TH],R9(3_ M/`\[)T55-5WM*JK2?FRJ+:,COR9JH]/L$D4[5=5332>:WC.Z/_9:.M3F(`#24#OS8DSI_)[ M`O):'?DJ,:IHV.X^&8;3:CYJNW34G MX\Y=E]HM19\4FZ]4'GC'4%2CJRF/S6ZGI>X/S)J8#GS8Q*4U.ZK^V&ZIXU:S MU=7N=,-6[,XN7%EQ*5B*`@3B1-YU0(G^5G`FI9$55J[BJJXM5_%7* MR@(Y&7(E`7(`NPZ-4GFV^@LV/U\$6L-Q_89E-_S5EB!55:6KZ,WFH][N-D-Z MM0^EE]Y221V,\,]33*2:,I(EVO\`RT9M%;CUU''M^6I,R2]SQUU]Y5C,2="8 MGFU,1;!P;J2I.E+DJ3,9TPEY=7GQ9O36O+J^?&6^N>&S!M$Z;?FS3-W5@I,2 MMP?,8C0@?\O2[:LK\V;XT;RY?7$[-,]'-[?#B]'%VUI^YO)J>'$]_+@Q/H27 ME[#MW?#UQMSMZ,/0_/>+T6U-_MX'"`'S5S;C(!P(%($"011AXR]]60HW!9X] MDP@AQ\$WUUQ;#C.#&L$IT3&A<.HO=5^>\80!;U,>`C`UQ=/UOZP%F.54CW(0[) MQ:?S'U,P$,II0^27W^A:#1SM^A&8?FS>CW89^./X4T_F4.`WA*&V3(UBG8#769P+BY(-)]:P?2/Y)@_.5B>CYX$ MLRJ\Q>Z.`>%0,4D@`IOVPT4(>G0QO#7?O/@P.O^M$LSJ9Q-KXD>Q(_>Q^3MT0"F('*DC2@-O#=$SX%)W(9U.L2E#S"?0V["N, M!KXJ=G"0]W"0H4/DWI"!.0]S M'X?_Q#8D>1O&N28DA7#]RMWN_.\R'-*383%;0:GU;8CO[>&-^A=&=RU<;J_\ M?*`G<;091K"\?TA6^"RJ?,H0)6S:'NG1R9]+PB=+XC"6\CS`T?44#5!10R*$ M'V%5Q(Q,K!='>Q%-(EX!REW,*$$F)O&\3%R0LT$N@`0E[X`P$*CH8Y#4DV.Y M^T<-'AA@71F0G`'!`"&J/1F\'WL)G0>4'\K33'0*ZA#,0(70&^!`;L[],JVP M^/]!JDVY3\(L&^L;.DG+2H*#^)&J`]4]'/ST)Q*>'>6\H)*7E(Y2VMYII079X]<,<_4\MVE'&WU0\H0/#.FD/[:(Z=`"\/E<,B.H12R`0$ M([!(:.6M=2#UM9A?5@#R_6"V/H2%'?47X1EX*U@P\9DXK%Q=H69+W">T:O M<#+F6"^"5-8K/\37IIA?900K8=C^%"OC6#I3B)H57I6+5$O)+-8]3K2Q[N7) M16@?G1:U.2FO;73VZ&6.<@[6XN8M]1-:)LX'5W[6H,_?(05OH:NQD=GL:>GWGJ7 MIU&,030NIHE/PK8D$5S;(1I?;'1)ISRGX&G`#Y=-!&N/_E4_#CZ[1S5R^^'J MYG=,C;7P*]HCN'O-"1$:6^.Q3X.`^'01OR?(.?;5O%_1%25'T38_&F$^88OZ MV7I*@?>4^6ZP8+!@!7@(F![ME]M`W:9*5`75;2E$;1W`\S3' M=I.$=T'H-.0&I'JV6-ZM)C427;MV,#(55"@)O]CTZ7T^<,#I&Y+%FQ5_C`AE5',-H(*Y#)S1THC616=T%=**^)ZB-^CMPYCG!G$$ M>,L`W`HN:O#B3J*L$E5[(&$#B24,T&BOA. M(]("\4#/ES(V>CUIFZ.-YFSB4_ZDD=Z++Q\&7,LXULRQQ2PQ'X_A03"TH(N` M0NV#C@0L%,//3P.` M8D@`D_^@H>B7$LB7-;'+I8P313<4HB,,0P,+I:V'@`(+[YA_CD^#3Y :]9P]I?8L6"T&U+:UB6VWY?\`O0XPMI@G```` ` end - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/