From 9a57f7fabd383920585ed8b74eacd117c6551f2d Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 17 Nov 2008 02:41:00 -0800 Subject: net: sctp should update its inuse counter This patch is a preparation to namespace conversion of /proc/net/protocols In order to have relevant information for SCTP protocols, we should use sock_prot_inuse_add() to update a (percpu and pernamespace) counter of inuse sockets. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/sctp/socket.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net/sctp/socket.c') diff --git a/net/sctp/socket.c b/net/sctp/socket.c index a1b904529d5e..0c70eff0b757 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -3614,6 +3614,7 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk) SCTP_DBG_OBJCNT_INC(sock); atomic_inc(&sctp_sockets_allocated); + sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); return 0; } @@ -3628,6 +3629,7 @@ SCTP_STATIC void sctp_destroy_sock(struct sock *sk) ep = sctp_sk(sk)->ep; sctp_endpoint_free(ep); atomic_dec(&sctp_sockets_allocated); + sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); } /* API 4.1.7 shutdown() - TCP Style Syntax -- cgit v1.2.3 From 6f756a8c36bf54d0afb1d457082b3e3033d951a7 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 23 Nov 2008 17:34:03 -0800 Subject: net: Make sure BHs are disabled in sock_prot_inuse_add() The rule of calling sock_prot_inuse_add() is that BHs must be disabled. Some new calls were added where this was not true and this tiggers warnings as reported by Ilpo. Fix this by adding explicit BH disabling around those call sites. Signed-off-by: David S. Miller --- net/sctp/socket.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'net/sctp/socket.c') diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 0c70eff0b757..f03af84edf63 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -3614,7 +3614,11 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk) SCTP_DBG_OBJCNT_INC(sock); atomic_inc(&sctp_sockets_allocated); + + local_bh_disable(); sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); + local_bh_enable(); + return 0; } -- cgit v1.2.3 From 5bc0b3bfa758e4ae49c94e31c1edb9a5f10a8060 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 25 Nov 2008 13:53:27 -0800 Subject: net: Make sure BHs are disabled in sock_prot_inuse_add() prot->destroy is not called with BH disabled. So we must add explicit BH disable around call to sock_prot_inuse_add() in sctp_destroy_sock() Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/sctp/socket.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net/sctp/socket.c') diff --git a/net/sctp/socket.c b/net/sctp/socket.c index f03af84edf63..ba81fe3ccab8 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -3633,7 +3633,9 @@ SCTP_STATIC void sctp_destroy_sock(struct sock *sk) ep = sctp_sk(sk)->ep; sctp_endpoint_free(ep); atomic_dec(&sctp_sockets_allocated); + local_bh_disable(); sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); + local_bh_enable(); } /* API 4.1.7 shutdown() - TCP Style Syntax -- cgit v1.2.3 From 1748376b6626acf59c24e9592ac67b3fe2a0e026 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 25 Nov 2008 21:16:35 -0800 Subject: net: Use a percpu_counter for sockets_allocated Instead of using one atomic_t per protocol, use a percpu_counter for "sockets_allocated", to reduce cache line contention on heavy duty network servers. Note : We revert commit (248969ae31e1b3276fc4399d67ce29a5d81e6fd9 net: af_unix can make unix_nr_socks visbile in /proc), since it is not anymore used after sock_prot_inuse_add() addition Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/sctp/socket.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'net/sctp/socket.c') diff --git a/net/sctp/socket.c b/net/sctp/socket.c index ba81fe3ccab8..a2de585888d0 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -114,7 +114,7 @@ extern int sysctl_sctp_wmem[3]; static int sctp_memory_pressure; static atomic_t sctp_memory_allocated; -static atomic_t sctp_sockets_allocated; +struct percpu_counter sctp_sockets_allocated; static void sctp_enter_memory_pressure(struct sock *sk) { @@ -3613,7 +3613,7 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk) sp->hmac = NULL; SCTP_DBG_OBJCNT_INC(sock); - atomic_inc(&sctp_sockets_allocated); + percpu_counter_inc(&sctp_sockets_allocated); local_bh_disable(); sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); @@ -3632,7 +3632,7 @@ SCTP_STATIC void sctp_destroy_sock(struct sock *sk) /* Release our hold on the endpoint. */ ep = sctp_sk(sk)->ep; sctp_endpoint_free(ep); - atomic_dec(&sctp_sockets_allocated); + percpu_counter_dec(&sctp_sockets_allocated); local_bh_disable(); sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); local_bh_enable(); -- cgit v1.2.3 From e89c2095815d82eaa9fb85eff42f8b65b67a59cf Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Thu, 25 Dec 2008 16:54:58 -0800 Subject: sctp: Bring SCTP_MAXSEG socket option into ietf API extension compliance Brings maxseg socket option set/get into line with the latest ietf socket extensions API draft, while maintaining backwards compatibility. Signed-off-by: Wei Yongjun Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller --- net/sctp/socket.c | 130 ++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 107 insertions(+), 23 deletions(-) (limited to 'net/sctp/socket.c') diff --git a/net/sctp/socket.c b/net/sctp/socket.c index a2de585888d0..0738843876a1 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -2778,32 +2778,77 @@ static int sctp_setsockopt_mappedv4(struct sock *sk, char __user *optval, int op } /* - * 7.1.17 Set the maximum fragrmentation size (SCTP_MAXSEG) - * - * This socket option specifies the maximum size to put in any outgoing - * SCTP chunk. If a message is larger than this size it will be + * 8.1.16. Get or Set the Maximum Fragmentation Size (SCTP_MAXSEG) + * This option will get or set the maximum size to put in any outgoing + * SCTP DATA chunk. If a message is larger than this size it will be * fragmented by SCTP into the specified size. Note that the underlying * SCTP implementation may fragment into smaller sized chunks when the * PMTU of the underlying association is smaller than the value set by - * the user. + * the user. The default value for this option is '0' which indicates + * the user is NOT limiting fragmentation and only the PMTU will effect + * SCTP's choice of DATA chunk size. Note also that values set larger + * than the maximum size of an IP datagram will effectively let SCTP + * control fragmentation (i.e. the same as setting this option to 0). + * + * The following structure is used to access and modify this parameter: + * + * struct sctp_assoc_value { + * sctp_assoc_t assoc_id; + * uint32_t assoc_value; + * }; + * + * assoc_id: This parameter is ignored for one-to-one style sockets. + * For one-to-many style sockets this parameter indicates which + * association the user is performing an action upon. Note that if + * this field's value is zero then the endpoints default value is + * changed (effecting future associations only). + * assoc_value: This parameter specifies the maximum size in bytes. */ static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, int optlen) { + struct sctp_assoc_value params; struct sctp_association *asoc; struct sctp_sock *sp = sctp_sk(sk); int val; - if (optlen < sizeof(int)) + if (optlen == sizeof(int)) { + printk(KERN_WARNING + "SCTP: Use of int in maxseg socket option deprecated\n"); + printk(KERN_WARNING + "SCTP: Use struct sctp_assoc_value instead\n"); + if (copy_from_user(&val, optval, optlen)) + return -EFAULT; + params.assoc_id = 0; + } else if (optlen == sizeof(struct sctp_assoc_value)) { + if (copy_from_user(¶ms, optval, optlen)) + return -EFAULT; + val = params.assoc_value; + } else return -EINVAL; - if (get_user(val, (int __user *)optval)) - return -EFAULT; + if ((val != 0) && ((val < 8) || (val > SCTP_MAX_CHUNK_LEN))) return -EINVAL; - sp->user_frag = val; - /* Update the frag_point of the existing associations. */ - list_for_each_entry(asoc, &(sp->ep->asocs), asocs) { - asoc->frag_point = sctp_frag_point(sp, asoc->pathmtu); + asoc = sctp_id2assoc(sk, params.assoc_id); + if (!asoc && params.assoc_id && sctp_style(sk, UDP)) + return -EINVAL; + + if (asoc) { + if (val == 0) { + val = asoc->pathmtu; + val -= sp->pf->af->net_header_len; + val -= sizeof(struct sctphdr) + + sizeof(struct sctp_data_chunk); + } + + asoc->frag_point = val; + } else { + sp->user_frag = val; + + /* Update the frag_point of the existing associations. */ + list_for_each_entry(asoc, &(sp->ep->asocs), asocs) { + asoc->frag_point = sctp_frag_point(sp, asoc->pathmtu); + } } return 0; @@ -5100,30 +5145,69 @@ static int sctp_getsockopt_context(struct sock *sk, int len, } /* - * 7.1.17 Set the maximum fragrmentation size (SCTP_MAXSEG) - * - * This socket option specifies the maximum size to put in any outgoing - * SCTP chunk. If a message is larger than this size it will be + * 8.1.16. Get or Set the Maximum Fragmentation Size (SCTP_MAXSEG) + * This option will get or set the maximum size to put in any outgoing + * SCTP DATA chunk. If a message is larger than this size it will be * fragmented by SCTP into the specified size. Note that the underlying * SCTP implementation may fragment into smaller sized chunks when the * PMTU of the underlying association is smaller than the value set by - * the user. + * the user. The default value for this option is '0' which indicates + * the user is NOT limiting fragmentation and only the PMTU will effect + * SCTP's choice of DATA chunk size. Note also that values set larger + * than the maximum size of an IP datagram will effectively let SCTP + * control fragmentation (i.e. the same as setting this option to 0). + * + * The following structure is used to access and modify this parameter: + * + * struct sctp_assoc_value { + * sctp_assoc_t assoc_id; + * uint32_t assoc_value; + * }; + * + * assoc_id: This parameter is ignored for one-to-one style sockets. + * For one-to-many style sockets this parameter indicates which + * association the user is performing an action upon. Note that if + * this field's value is zero then the endpoints default value is + * changed (effecting future associations only). + * assoc_value: This parameter specifies the maximum size in bytes. */ static int sctp_getsockopt_maxseg(struct sock *sk, int len, char __user *optval, int __user *optlen) { - int val; + struct sctp_assoc_value params; + struct sctp_association *asoc; - if (len < sizeof(int)) + if (len == sizeof(int)) { + printk(KERN_WARNING + "SCTP: Use of int in maxseg socket option deprecated\n"); + printk(KERN_WARNING + "SCTP: Use struct sctp_assoc_value instead\n"); + params.assoc_id = 0; + } else if (len >= sizeof(struct sctp_assoc_value)) { + len = sizeof(struct sctp_assoc_value); + if (copy_from_user(¶ms, optval, sizeof(params))) + return -EFAULT; + } else return -EINVAL; - len = sizeof(int); + asoc = sctp_id2assoc(sk, params.assoc_id); + if (!asoc && params.assoc_id && sctp_style(sk, UDP)) + return -EINVAL; + + if (asoc) + params.assoc_value = asoc->frag_point; + else + params.assoc_value = sctp_sk(sk)->user_frag; - val = sctp_sk(sk)->user_frag; if (put_user(len, optlen)) return -EFAULT; - if (copy_to_user(optval, &val, len)) - return -EFAULT; + if (len == sizeof(int)) { + if (copy_to_user(optval, ¶ms.assoc_value, len)) + return -EFAULT; + } else { + if (copy_to_user(optval, ¶ms, len)) + return -EFAULT; + } return 0; } -- cgit v1.2.3 From ea686a2653c5586b1c7192958b9d521abde66e92 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Thu, 25 Dec 2008 16:56:45 -0800 Subject: sctp: Fix a typo in socket.c Just fix a typo in socket.c. Signed-off-by: Wei Yongjun Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller --- net/sctp/socket.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'net/sctp/socket.c') diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 0738843876a1..e432927310c9 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -2404,9 +2404,9 @@ static int sctp_setsockopt_delayed_ack(struct sock *sk, if (params.sack_delay == 0 && params.sack_freq == 0) return 0; } else if (optlen == sizeof(struct sctp_assoc_value)) { - printk(KERN_WARNING "SCTP: Use of struct sctp_sack_info " + printk(KERN_WARNING "SCTP: Use of struct sctp_assoc_value " "in delayed_ack socket option deprecated\n"); - printk(KERN_WARNING "SCTP: struct sctp_sack_info instead\n"); + printk(KERN_WARNING "SCTP: Use struct sctp_sack_info instead\n"); if (copy_from_user(¶ms, optval, optlen)) return -EFAULT; @@ -4221,9 +4221,9 @@ static int sctp_getsockopt_delayed_ack(struct sock *sk, int len, if (copy_from_user(¶ms, optval, len)) return -EFAULT; } else if (len == sizeof(struct sctp_assoc_value)) { - printk(KERN_WARNING "SCTP: Use of struct sctp_sack_info " + printk(KERN_WARNING "SCTP: Use of struct sctp_assoc_value " "in delayed_ack socket option deprecated\n"); - printk(KERN_WARNING "SCTP: struct sctp_sack_info instead\n"); + printk(KERN_WARNING "SCTP: Use struct sctp_sack_info instead\n"); if (copy_from_user(¶ms, optval, len)) return -EFAULT; } else -- cgit v1.2.3 From aea3c5c05d2c409e93bfa80dcedc06af7da6c13b Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Thu, 25 Dec 2008 16:57:24 -0800 Subject: sctp: Implement socket option SCTP_GET_ASSOC_NUMBER Implement socket option SCTP_GET_ASSOC_NUMBER of the latest ietf socket extensions API draft. 8.2.5. Get the Current Number of Associations (SCTP_GET_ASSOC_NUMBER) This option gets the current number of associations that are attached to a one-to-many style socket. The option value is an uint32_t. Signed-off-by: Wei Yongjun Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller --- net/sctp/socket.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'net/sctp/socket.c') diff --git a/net/sctp/socket.c b/net/sctp/socket.c index e432927310c9..9f5fe23773a9 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -5460,6 +5460,38 @@ num: return 0; } +/* + * 8.2.5. Get the Current Number of Associations (SCTP_GET_ASSOC_NUMBER) + * This option gets the current number of associations that are attached + * to a one-to-many style socket. The option value is an uint32_t. + */ +static int sctp_getsockopt_assoc_number(struct sock *sk, int len, + char __user *optval, int __user *optlen) +{ + struct sctp_sock *sp = sctp_sk(sk); + struct sctp_association *asoc; + u32 val = 0; + + if (sctp_style(sk, TCP)) + return -EOPNOTSUPP; + + if (len < sizeof(u32)) + return -EINVAL; + + len = sizeof(u32); + + list_for_each_entry(asoc, &(sp->ep->asocs), asocs) { + val++; + } + + if (put_user(len, optlen)) + return -EFAULT; + if (copy_to_user(optval, &val, len)) + return -EFAULT; + + return 0; +} + SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen) { @@ -5602,6 +5634,9 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, retval = sctp_getsockopt_local_auth_chunks(sk, len, optval, optlen); break; + case SCTP_GET_ASSOC_NUMBER: + retval = sctp_getsockopt_assoc_number(sk, len, optval, optlen); + break; default: retval = -ENOPROTOOPT; break; -- cgit v1.2.3 From 8510b937ae1e23583abdeb828cad5c518295c61d Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Thu, 25 Dec 2008 16:59:03 -0800 Subject: sctp: Add validity check for SCTP_PARTIAL_DELIVERY_POINT socket option The latest ietf socket extensions API draft said: 8.1.21. Set or Get the SCTP Partial Delivery Point Note also that the call will fail if the user attempts to set this value larger than the socket receive buffer size. This patch add this validity check for SCTP_PARTIAL_DELIVERY_POINT socket option. Signed-off-by: Wei Yongjun Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller --- net/sctp/socket.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'net/sctp/socket.c') diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 9f5fe23773a9..b14a8f33e42d 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -3010,14 +3010,21 @@ static int sctp_setsockopt_fragment_interleave(struct sock *sk, } /* - * 7.1.25. Set or Get the sctp partial delivery point + * 8.1.21. Set or Get the SCTP Partial Delivery Point * (SCTP_PARTIAL_DELIVERY_POINT) + * * This option will set or get the SCTP partial delivery point. This * point is the size of a message where the partial delivery API will be * invoked to help free up rwnd space for the peer. Setting this to a - * lower value will cause partial delivery's to happen more often. The + * lower value will cause partial deliveries to happen more often. The * calls argument is an integer that sets or gets the partial delivery - * point. + * point. Note also that the call will fail if the user attempts to set + * this value larger than the socket receive buffer size. + * + * Note that any single message having a length smaller than or equal to + * the SCTP partial delivery point will be delivered in one single read + * call as long as the user provided buffer is large enough to hold the + * message. */ static int sctp_setsockopt_partial_delivery_point(struct sock *sk, char __user *optval, @@ -3030,6 +3037,12 @@ static int sctp_setsockopt_partial_delivery_point(struct sock *sk, if (get_user(val, (int __user *)optval)) return -EFAULT; + /* Note: We double the receive buffer from what the user sets + * it to be, also initial rwnd is based on rcvbuf/2. + */ + if (val > (sk->sk_rcvbuf >> 1)) + return -EINVAL; + sctp_sk(sk)->pd_point = val; return 0; /* is this the right error code? */ -- cgit v1.2.3