Skip to content

Commit f7ae8d5

Browse files
Rémi Denis-Courmontdavem330
authored andcommitted
Phonet: allocate sock from accept syscall rather than soft IRQ
This moves most of the accept logic to process context like other socket stacks do. Then we can use a few more common socket helpers and simplify a bit. Signed-off-by: Rémi Denis-Courmont <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 44c9ab1 commit f7ae8d5

File tree

3 files changed

+121
-174
lines changed

3 files changed

+121
-174
lines changed

include/net/phonet/pep.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ struct pep_sock {
2828

2929
/* XXX: union-ify listening vs connected stuff ? */
3030
/* Listening socket stuff: */
31-
struct hlist_head ackq;
3231
struct hlist_head hlist;
3332

3433
/* Connected socket stuff: */

net/phonet/pep.c

Lines changed: 117 additions & 167 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
* TCP_ESTABLISHED connected pipe in enabled state
4343
*
4444
* pep_sock locking:
45-
* - sk_state, ackq, hlist: sock lock needed
45+
* - sk_state, hlist: sock lock needed
4646
* - listener: read only
4747
* - pipe_handle: read only
4848
*/
@@ -202,11 +202,12 @@ static int pep_accept_conn(struct sock *sk, struct sk_buff *skb)
202202
GFP_KERNEL);
203203
}
204204

205-
static int pep_reject_conn(struct sock *sk, struct sk_buff *skb, u8 code)
205+
static int pep_reject_conn(struct sock *sk, struct sk_buff *skb, u8 code,
206+
gfp_t priority)
206207
{
207208
static const u8 data[4] = { PAD, PAD, PAD, 0 /* sub-blocks */ };
208209
WARN_ON(code == PN_PIPE_NO_ERROR);
209-
return pep_reply(sk, skb, code, data, sizeof(data), GFP_ATOMIC);
210+
return pep_reply(sk, skb, code, data, sizeof(data), priority);
210211
}
211212

212213
/* Control requests are not sent by the pipe service and have a specific
@@ -365,7 +366,7 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb)
365366

366367
switch (hdr->message_id) {
367368
case PNS_PEP_CONNECT_REQ:
368-
pep_reject_conn(sk, skb, PN_PIPE_ERR_PEP_IN_USE);
369+
pep_reject_conn(sk, skb, PN_PIPE_ERR_PEP_IN_USE, GFP_ATOMIC);
369370
break;
370371

371372
case PNS_PEP_DISCONNECT_REQ:
@@ -574,104 +575,13 @@ static int pep_connresp_rcv(struct sock *sk, struct sk_buff *skb)
574575

575576
sk->sk_state = TCP_SYN_RECV;
576577
sk->sk_backlog_rcv = pipe_do_rcv;
577-
sk->sk_destruct = pipe_destruct;
578578
pn->rx_credits = 0;
579579
sk->sk_state_change(sk);
580580

581581
return pipe_handler_send_created_ind(sk);
582582
}
583583
#endif
584584

585-
static int pep_connreq_rcv(struct sock *sk, struct sk_buff *skb)
586-
{
587-
struct sock *newsk;
588-
struct pep_sock *newpn, *pn = pep_sk(sk);
589-
struct pnpipehdr *hdr;
590-
struct sockaddr_pn dst, src;
591-
u16 peer_type;
592-
u8 pipe_handle, enabled, n_sb;
593-
u8 aligned = 0;
594-
595-
if (!pskb_pull(skb, sizeof(*hdr) + 4))
596-
return -EINVAL;
597-
598-
hdr = pnp_hdr(skb);
599-
pipe_handle = hdr->pipe_handle;
600-
switch (hdr->state_after_connect) {
601-
case PN_PIPE_DISABLE:
602-
enabled = 0;
603-
break;
604-
case PN_PIPE_ENABLE:
605-
enabled = 1;
606-
break;
607-
default:
608-
pep_reject_conn(sk, skb, PN_PIPE_ERR_INVALID_PARAM);
609-
return -EINVAL;
610-
}
611-
peer_type = hdr->other_pep_type << 8;
612-
613-
/* Parse sub-blocks (options) */
614-
n_sb = hdr->data[4];
615-
while (n_sb > 0) {
616-
u8 type, buf[1], len = sizeof(buf);
617-
const u8 *data = pep_get_sb(skb, &type, &len, buf);
618-
619-
if (data == NULL)
620-
return -EINVAL;
621-
switch (type) {
622-
case PN_PIPE_SB_CONNECT_REQ_PEP_SUB_TYPE:
623-
if (len < 1)
624-
return -EINVAL;
625-
peer_type = (peer_type & 0xff00) | data[0];
626-
break;
627-
case PN_PIPE_SB_ALIGNED_DATA:
628-
aligned = data[0] != 0;
629-
break;
630-
}
631-
n_sb--;
632-
}
633-
634-
skb = skb_clone(skb, GFP_ATOMIC);
635-
if (!skb)
636-
return -ENOMEM;
637-
638-
/* Create a new to-be-accepted sock */
639-
newsk = sk_alloc(sock_net(sk), PF_PHONET, GFP_ATOMIC, sk->sk_prot);
640-
if (!newsk) {
641-
kfree_skb(skb);
642-
return -ENOMEM;
643-
}
644-
sock_init_data(NULL, newsk);
645-
newsk->sk_state = TCP_SYN_RECV;
646-
newsk->sk_backlog_rcv = pipe_do_rcv;
647-
newsk->sk_protocol = sk->sk_protocol;
648-
newsk->sk_destruct = pipe_destruct;
649-
650-
newpn = pep_sk(newsk);
651-
pn_skb_get_dst_sockaddr(skb, &dst);
652-
pn_skb_get_src_sockaddr(skb, &src);
653-
newpn->pn_sk.sobject = pn_sockaddr_get_object(&dst);
654-
newpn->pn_sk.dobject = pn_sockaddr_get_object(&src);
655-
newpn->pn_sk.resource = pn_sockaddr_get_resource(&dst);
656-
skb_queue_head_init(&newpn->ctrlreq_queue);
657-
newpn->pipe_handle = pipe_handle;
658-
atomic_set(&newpn->tx_credits, 0);
659-
newpn->peer_type = peer_type;
660-
newpn->rx_credits = 0;
661-
newpn->rx_fc = newpn->tx_fc = PN_LEGACY_FLOW_CONTROL;
662-
newpn->init_enable = enabled;
663-
newpn->aligned = aligned;
664-
665-
BUG_ON(!skb_queue_empty(&newsk->sk_receive_queue));
666-
skb_queue_head(&newsk->sk_receive_queue, skb);
667-
if (!sock_flag(sk, SOCK_DEAD))
668-
sk->sk_data_ready(sk, 0);
669-
670-
sk_acceptq_added(sk);
671-
sk_add_node(newsk, &pn->ackq);
672-
return 0;
673-
}
674-
675585
/* Listening sock must be locked */
676586
static struct sock *pep_find_pipe(const struct hlist_head *hlist,
677587
const struct sockaddr_pn *dst,
@@ -726,22 +636,18 @@ static int pep_do_rcv(struct sock *sk, struct sk_buff *skb)
726636
if (sknode)
727637
return sk_receive_skb(sknode, skb, 1);
728638

729-
/* Look for a pipe handle pending accept */
730-
sknode = pep_find_pipe(&pn->ackq, &dst, pipe_handle);
731-
if (sknode) {
732-
sock_put(sknode);
733-
if (net_ratelimit())
734-
printk(KERN_WARNING"Phonet unconnected PEP ignored");
735-
goto drop;
736-
}
737-
738639
switch (hdr->message_id) {
739640
case PNS_PEP_CONNECT_REQ:
740-
if (sk->sk_state == TCP_LISTEN && !sk_acceptq_is_full(sk))
741-
pep_connreq_rcv(sk, skb);
742-
else
743-
pep_reject_conn(sk, skb, PN_PIPE_ERR_PEP_IN_USE);
744-
break;
641+
if (sk->sk_state != TCP_LISTEN || sk_acceptq_is_full(sk)) {
642+
pep_reject_conn(sk, skb, PN_PIPE_ERR_PEP_IN_USE,
643+
GFP_ATOMIC);
644+
break;
645+
}
646+
skb_queue_head(&sk->sk_receive_queue, skb);
647+
sk_acceptq_added(sk);
648+
if (!sock_flag(sk, SOCK_DEAD))
649+
sk->sk_data_ready(sk, 0);
650+
return NET_RX_SUCCESS;
745651

746652
#ifdef CONFIG_PHONET_PIPECTRLR
747653
case PNS_PEP_CONNECT_RESP:
@@ -799,24 +705,16 @@ static void pep_sock_close(struct sock *sk, long timeout)
799705
sk_common_release(sk);
800706

801707
lock_sock(sk);
802-
if (sk->sk_state == TCP_LISTEN) {
803-
/* Destroy the listen queue */
804-
struct sock *sknode;
805-
struct hlist_node *p, *n;
806-
807-
sk_for_each_safe(sknode, p, n, &pn->ackq)
808-
sk_del_node_init(sknode);
809-
sk->sk_state = TCP_CLOSE;
810-
} else if ((1 << sk->sk_state) & (TCPF_SYN_RECV|TCPF_ESTABLISHED)) {
708+
if ((1 << sk->sk_state) & (TCPF_SYN_RECV|TCPF_ESTABLISHED)) {
811709
#ifndef CONFIG_PHONET_PIPECTRLR
812710
/* Forcefully remove dangling Phonet pipe */
813711
pipe_do_remove(sk);
814712
#else
815713
/* send pep disconnect request */
816714
pipe_handler_request(sk, PNS_PEP_DISCONNECT_REQ, PAD, NULL, 0);
817-
sk->sk_state = TCP_CLOSE;
818715
#endif
819716
}
717+
sk->sk_state = TCP_CLOSE;
820718

821719
ifindex = pn->ifindex;
822720
pn->ifindex = 0;
@@ -827,69 +725,121 @@ static void pep_sock_close(struct sock *sk, long timeout)
827725
sock_put(sk);
828726
}
829727

830-
static int pep_wait_connreq(struct sock *sk, int noblock)
728+
static struct sock *pep_sock_accept(struct sock *sk, int flags, int *errp)
831729
{
832-
struct task_struct *tsk = current;
833-
struct pep_sock *pn = pep_sk(sk);
834-
long timeo = sock_rcvtimeo(sk, noblock);
835-
836-
for (;;) {
837-
DEFINE_WAIT(wait);
730+
struct pep_sock *pn = pep_sk(sk), *newpn;
731+
struct sock *newsk = NULL;
732+
struct sk_buff *skb;
733+
struct pnpipehdr *hdr;
734+
struct sockaddr_pn dst, src;
735+
int err;
736+
u16 peer_type;
737+
u8 pipe_handle, enabled, n_sb;
738+
u8 aligned = 0;
838739

839-
if (sk->sk_state != TCP_LISTEN)
840-
return -EINVAL;
841-
if (!hlist_empty(&pn->ackq))
842-
break;
843-
if (!timeo)
844-
return -EWOULDBLOCK;
845-
if (signal_pending(tsk))
846-
return sock_intr_errno(timeo);
740+
skb = skb_recv_datagram(sk, 0, flags & O_NONBLOCK, errp);
741+
if (!skb)
742+
return NULL;
847743

848-
prepare_to_wait_exclusive(sk_sleep(sk), &wait,
849-
TASK_INTERRUPTIBLE);
850-
release_sock(sk);
851-
timeo = schedule_timeout(timeo);
852-
lock_sock(sk);
853-
finish_wait(sk_sleep(sk), &wait);
744+
lock_sock(sk);
745+
if (sk->sk_state != TCP_LISTEN) {
746+
err = -EINVAL;
747+
goto drop;
854748
}
749+
sk_acceptq_removed(sk);
855750

856-
return 0;
857-
}
751+
err = -EPROTO;
752+
if (!pskb_may_pull(skb, sizeof(*hdr) + 4))
753+
goto drop;
858754

859-
static struct sock *pep_sock_accept(struct sock *sk, int flags, int *errp)
860-
{
861-
struct pep_sock *pn = pep_sk(sk);
862-
struct sock *newsk = NULL;
863-
struct sk_buff *oskb;
864-
int err;
755+
hdr = pnp_hdr(skb);
756+
pipe_handle = hdr->pipe_handle;
757+
switch (hdr->state_after_connect) {
758+
case PN_PIPE_DISABLE:
759+
enabled = 0;
760+
break;
761+
case PN_PIPE_ENABLE:
762+
enabled = 1;
763+
break;
764+
default:
765+
pep_reject_conn(sk, skb, PN_PIPE_ERR_INVALID_PARAM,
766+
GFP_KERNEL);
767+
goto drop;
768+
}
769+
peer_type = hdr->other_pep_type << 8;
865770

866-
lock_sock(sk);
867-
err = pep_wait_connreq(sk, flags & O_NONBLOCK);
868-
if (err)
869-
goto out;
771+
/* Parse sub-blocks (options) */
772+
n_sb = hdr->data[4];
773+
while (n_sb > 0) {
774+
u8 type, buf[1], len = sizeof(buf);
775+
const u8 *data = pep_get_sb(skb, &type, &len, buf);
870776

871-
newsk = __sk_head(&pn->ackq);
777+
if (data == NULL)
778+
goto drop;
779+
switch (type) {
780+
case PN_PIPE_SB_CONNECT_REQ_PEP_SUB_TYPE:
781+
if (len < 1)
782+
goto drop;
783+
peer_type = (peer_type & 0xff00) | data[0];
784+
break;
785+
case PN_PIPE_SB_ALIGNED_DATA:
786+
aligned = data[0] != 0;
787+
break;
788+
}
789+
n_sb--;
790+
}
872791

873-
oskb = skb_dequeue(&newsk->sk_receive_queue);
874-
err = pep_accept_conn(newsk, oskb);
875-
if (err) {
876-
skb_queue_head(&newsk->sk_receive_queue, oskb);
792+
/* Check for duplicate pipe handle */
793+
newsk = pep_find_pipe(&pn->hlist, &dst, pipe_handle);
794+
if (unlikely(newsk)) {
795+
__sock_put(newsk);
877796
newsk = NULL;
878-
goto out;
797+
pep_reject_conn(sk, skb, PN_PIPE_ERR_PEP_IN_USE, GFP_KERNEL);
798+
goto drop;
799+
}
800+
801+
/* Create a new to-be-accepted sock */
802+
newsk = sk_alloc(sock_net(sk), PF_PHONET, GFP_KERNEL, sk->sk_prot);
803+
if (!newsk) {
804+
pep_reject_conn(sk, skb, PN_PIPE_ERR_OVERLOAD, GFP_KERNEL);
805+
err = -ENOBUFS;
806+
goto drop;
879807
}
880-
kfree_skb(oskb);
881808

809+
sock_init_data(NULL, newsk);
810+
newsk->sk_state = TCP_SYN_RECV;
811+
newsk->sk_backlog_rcv = pipe_do_rcv;
812+
newsk->sk_protocol = sk->sk_protocol;
813+
newsk->sk_destruct = pipe_destruct;
814+
815+
newpn = pep_sk(newsk);
816+
pn_skb_get_dst_sockaddr(skb, &dst);
817+
pn_skb_get_src_sockaddr(skb, &src);
818+
newpn->pn_sk.sobject = pn_sockaddr_get_object(&dst);
819+
newpn->pn_sk.dobject = pn_sockaddr_get_object(&src);
820+
newpn->pn_sk.resource = pn_sockaddr_get_resource(&dst);
882821
sock_hold(sk);
883-
pep_sk(newsk)->listener = sk;
822+
newpn->listener = sk;
823+
skb_queue_head_init(&newpn->ctrlreq_queue);
824+
newpn->pipe_handle = pipe_handle;
825+
atomic_set(&newpn->tx_credits, 0);
826+
newpn->ifindex = 0;
827+
newpn->peer_type = peer_type;
828+
newpn->rx_credits = 0;
829+
newpn->rx_fc = newpn->tx_fc = PN_LEGACY_FLOW_CONTROL;
830+
newpn->init_enable = enabled;
831+
newpn->aligned = aligned;
884832

885-
sock_hold(newsk);
886-
sk_del_node_init(newsk);
887-
sk_acceptq_removed(sk);
833+
err = pep_accept_conn(newsk, skb);
834+
if (err) {
835+
sock_put(newsk);
836+
newsk = NULL;
837+
goto drop;
838+
}
888839
sk_add_node(newsk, &pn->hlist);
889-
__sock_put(newsk);
890-
891-
out:
840+
drop:
892841
release_sock(sk);
842+
kfree_skb(skb);
893843
*errp = err;
894844
return newsk;
895845
}
@@ -937,7 +887,7 @@ static int pep_init(struct sock *sk)
937887
{
938888
struct pep_sock *pn = pep_sk(sk);
939889

940-
INIT_HLIST_HEAD(&pn->ackq);
890+
sk->sk_destruct = pipe_destruct;
941891
INIT_HLIST_HEAD(&pn->hlist);
942892
skb_queue_head_init(&pn->ctrlreq_queue);
943893
pn->pipe_handle = PN_PIPE_INVALID_HANDLE;

0 commit comments

Comments
 (0)