Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6: (43 commits) via-velocity: Fix velocity driver unmapping incorrect size. mlx4_en: Remove redundant refill code on RX mlx4_en: Removed redundant check on lso header size mlx4_en: Cancel port_up check in transmit function mlx4_en: using stop/start_all_queues mlx4_en: Removed redundant skb->len check mlx4_en: Counting all the dropped packets on the TX side usbnet cdc_subset: fix issues talking to PXA gadgets Net: qla3xxx, remove sleeping in atomic ipv4: fix NULL pointer + success return in route lookup path isdn: clean up documentation index cfg80211: validate station settings cfg80211: allow setting station parameters in mesh cfg80211: allow adding/deleting stations on mesh ath5k: fix beacon_int handling MAINTAINERS: Fix Atheros pattern paths ath9k: restore PS mode, before we put the chip into FULL SLEEP state. ath9k: wait for beacon frame along with CAB acer-wmi: fix rfkill conversion ath5k: avoid PCI FATAL interrupts by restoring RETRY_TIMEOUT disabling ...
This commit is contained in:
@@ -54,6 +54,38 @@ static const u8 iprm_shutdown[8] =
|
||||
#define CB_TRGCLS(skb) ((skb)->cb + CB_TAG_LEN) /* iucv msg target class */
|
||||
#define CB_TRGCLS_LEN (TRGCLS_SIZE)
|
||||
|
||||
#define __iucv_sock_wait(sk, condition, timeo, ret) \
|
||||
do { \
|
||||
DEFINE_WAIT(__wait); \
|
||||
long __timeo = timeo; \
|
||||
ret = 0; \
|
||||
while (!(condition)) { \
|
||||
prepare_to_wait(sk->sk_sleep, &__wait, TASK_INTERRUPTIBLE); \
|
||||
if (!__timeo) { \
|
||||
ret = -EAGAIN; \
|
||||
break; \
|
||||
} \
|
||||
if (signal_pending(current)) { \
|
||||
ret = sock_intr_errno(__timeo); \
|
||||
break; \
|
||||
} \
|
||||
release_sock(sk); \
|
||||
__timeo = schedule_timeout(__timeo); \
|
||||
lock_sock(sk); \
|
||||
ret = sock_error(sk); \
|
||||
if (ret) \
|
||||
break; \
|
||||
} \
|
||||
finish_wait(sk->sk_sleep, &__wait); \
|
||||
} while (0)
|
||||
|
||||
#define iucv_sock_wait(sk, condition, timeo) \
|
||||
({ \
|
||||
int __ret = 0; \
|
||||
if (!(condition)) \
|
||||
__iucv_sock_wait(sk, condition, timeo, __ret); \
|
||||
__ret; \
|
||||
})
|
||||
|
||||
static void iucv_sock_kill(struct sock *sk);
|
||||
static void iucv_sock_close(struct sock *sk);
|
||||
@@ -238,6 +270,48 @@ static inline size_t iucv_msg_length(struct iucv_message *msg)
|
||||
return msg->length;
|
||||
}
|
||||
|
||||
/**
|
||||
* iucv_sock_in_state() - check for specific states
|
||||
* @sk: sock structure
|
||||
* @state: first iucv sk state
|
||||
* @state: second iucv sk state
|
||||
*
|
||||
* Returns true if the socket in either in the first or second state.
|
||||
*/
|
||||
static int iucv_sock_in_state(struct sock *sk, int state, int state2)
|
||||
{
|
||||
return (sk->sk_state == state || sk->sk_state == state2);
|
||||
}
|
||||
|
||||
/**
|
||||
* iucv_below_msglim() - function to check if messages can be sent
|
||||
* @sk: sock structure
|
||||
*
|
||||
* Returns true if the send queue length is lower than the message limit.
|
||||
* Always returns true if the socket is not connected (no iucv path for
|
||||
* checking the message limit).
|
||||
*/
|
||||
static inline int iucv_below_msglim(struct sock *sk)
|
||||
{
|
||||
struct iucv_sock *iucv = iucv_sk(sk);
|
||||
|
||||
if (sk->sk_state != IUCV_CONNECTED)
|
||||
return 1;
|
||||
return (skb_queue_len(&iucv->send_skb_q) < iucv->path->msglim);
|
||||
}
|
||||
|
||||
/**
|
||||
* iucv_sock_wake_msglim() - Wake up thread waiting on msg limit
|
||||
*/
|
||||
static void iucv_sock_wake_msglim(struct sock *sk)
|
||||
{
|
||||
read_lock(&sk->sk_callback_lock);
|
||||
if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
|
||||
wake_up_interruptible_all(sk->sk_sleep);
|
||||
sk_wake_async(sk, SOCK_WAKE_SPACE, POLL_OUT);
|
||||
read_unlock(&sk->sk_callback_lock);
|
||||
}
|
||||
|
||||
/* Timers */
|
||||
static void iucv_sock_timeout(unsigned long arg)
|
||||
{
|
||||
@@ -329,7 +403,9 @@ static void iucv_sock_close(struct sock *sk)
|
||||
timeo = sk->sk_lingertime;
|
||||
else
|
||||
timeo = IUCV_DISCONN_TIMEOUT;
|
||||
err = iucv_sock_wait_state(sk, IUCV_CLOSED, 0, timeo);
|
||||
err = iucv_sock_wait(sk,
|
||||
iucv_sock_in_state(sk, IUCV_CLOSED, 0),
|
||||
timeo);
|
||||
}
|
||||
|
||||
case IUCV_CLOSING: /* fall through */
|
||||
@@ -510,39 +586,6 @@ struct sock *iucv_accept_dequeue(struct sock *parent, struct socket *newsock)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int iucv_sock_wait_state(struct sock *sk, int state, int state2,
|
||||
unsigned long timeo)
|
||||
{
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
int err = 0;
|
||||
|
||||
add_wait_queue(sk->sk_sleep, &wait);
|
||||
while (sk->sk_state != state && sk->sk_state != state2) {
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
|
||||
if (!timeo) {
|
||||
err = -EAGAIN;
|
||||
break;
|
||||
}
|
||||
|
||||
if (signal_pending(current)) {
|
||||
err = sock_intr_errno(timeo);
|
||||
break;
|
||||
}
|
||||
|
||||
release_sock(sk);
|
||||
timeo = schedule_timeout(timeo);
|
||||
lock_sock(sk);
|
||||
|
||||
err = sock_error(sk);
|
||||
if (err)
|
||||
break;
|
||||
}
|
||||
set_current_state(TASK_RUNNING);
|
||||
remove_wait_queue(sk->sk_sleep, &wait);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Bind an unbound socket */
|
||||
static int iucv_sock_bind(struct socket *sock, struct sockaddr *addr,
|
||||
int addr_len)
|
||||
@@ -687,8 +730,9 @@ static int iucv_sock_connect(struct socket *sock, struct sockaddr *addr,
|
||||
}
|
||||
|
||||
if (sk->sk_state != IUCV_CONNECTED) {
|
||||
err = iucv_sock_wait_state(sk, IUCV_CONNECTED, IUCV_DISCONN,
|
||||
sock_sndtimeo(sk, flags & O_NONBLOCK));
|
||||
err = iucv_sock_wait(sk, iucv_sock_in_state(sk, IUCV_CONNECTED,
|
||||
IUCV_DISCONN),
|
||||
sock_sndtimeo(sk, flags & O_NONBLOCK));
|
||||
}
|
||||
|
||||
if (sk->sk_state == IUCV_DISCONN) {
|
||||
@@ -842,9 +886,11 @@ static int iucv_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
|
||||
struct iucv_message txmsg;
|
||||
struct cmsghdr *cmsg;
|
||||
int cmsg_done;
|
||||
long timeo;
|
||||
char user_id[9];
|
||||
char appl_id[9];
|
||||
int err;
|
||||
int noblock = msg->msg_flags & MSG_DONTWAIT;
|
||||
|
||||
err = sock_error(sk);
|
||||
if (err)
|
||||
@@ -864,108 +910,119 @@ static int iucv_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (sk->sk_state == IUCV_CONNECTED) {
|
||||
/* initialize defaults */
|
||||
cmsg_done = 0; /* check for duplicate headers */
|
||||
txmsg.class = 0;
|
||||
/* Return if the socket is not in connected state */
|
||||
if (sk->sk_state != IUCV_CONNECTED) {
|
||||
err = -ENOTCONN;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* iterate over control messages */
|
||||
for (cmsg = CMSG_FIRSTHDR(msg); cmsg;
|
||||
cmsg = CMSG_NXTHDR(msg, cmsg)) {
|
||||
/* initialize defaults */
|
||||
cmsg_done = 0; /* check for duplicate headers */
|
||||
txmsg.class = 0;
|
||||
|
||||
if (!CMSG_OK(msg, cmsg)) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
/* iterate over control messages */
|
||||
for (cmsg = CMSG_FIRSTHDR(msg); cmsg;
|
||||
cmsg = CMSG_NXTHDR(msg, cmsg)) {
|
||||
|
||||
if (cmsg->cmsg_level != SOL_IUCV)
|
||||
continue;
|
||||
|
||||
if (cmsg->cmsg_type & cmsg_done) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
cmsg_done |= cmsg->cmsg_type;
|
||||
|
||||
switch (cmsg->cmsg_type) {
|
||||
case SCM_IUCV_TRGCLS:
|
||||
if (cmsg->cmsg_len != CMSG_LEN(TRGCLS_SIZE)) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* set iucv message target class */
|
||||
memcpy(&txmsg.class,
|
||||
(void *) CMSG_DATA(cmsg), TRGCLS_SIZE);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* allocate one skb for each iucv message:
|
||||
* this is fine for SOCK_SEQPACKET (unless we want to support
|
||||
* segmented records using the MSG_EOR flag), but
|
||||
* for SOCK_STREAM we might want to improve it in future */
|
||||
if (!(skb = sock_alloc_send_skb(sk, len,
|
||||
msg->msg_flags & MSG_DONTWAIT,
|
||||
&err)))
|
||||
if (!CMSG_OK(msg, cmsg)) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
|
||||
if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) {
|
||||
err = -EFAULT;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* increment and save iucv message tag for msg_completion cbk */
|
||||
txmsg.tag = iucv->send_tag++;
|
||||
memcpy(CB_TAG(skb), &txmsg.tag, CB_TAG_LEN);
|
||||
skb_queue_tail(&iucv->send_skb_q, skb);
|
||||
if (cmsg->cmsg_level != SOL_IUCV)
|
||||
continue;
|
||||
|
||||
if (((iucv->path->flags & IUCV_IPRMDATA) & iucv->flags)
|
||||
&& skb->len <= 7) {
|
||||
err = iucv_send_iprm(iucv->path, &txmsg, skb);
|
||||
if (cmsg->cmsg_type & cmsg_done) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
cmsg_done |= cmsg->cmsg_type;
|
||||
|
||||
/* on success: there is no message_complete callback
|
||||
* for an IPRMDATA msg; remove skb from send queue */
|
||||
if (err == 0) {
|
||||
skb_unlink(skb, &iucv->send_skb_q);
|
||||
kfree_skb(skb);
|
||||
switch (cmsg->cmsg_type) {
|
||||
case SCM_IUCV_TRGCLS:
|
||||
if (cmsg->cmsg_len != CMSG_LEN(TRGCLS_SIZE)) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* this error should never happen since the
|
||||
* IUCV_IPRMDATA path flag is set... sever path */
|
||||
if (err == 0x15) {
|
||||
iucv_path_sever(iucv->path, NULL);
|
||||
skb_unlink(skb, &iucv->send_skb_q);
|
||||
err = -EPIPE;
|
||||
goto fail;
|
||||
}
|
||||
} else
|
||||
err = iucv_message_send(iucv->path, &txmsg, 0, 0,
|
||||
(void *) skb->data, skb->len);
|
||||
if (err) {
|
||||
if (err == 3) {
|
||||
user_id[8] = 0;
|
||||
memcpy(user_id, iucv->dst_user_id, 8);
|
||||
appl_id[8] = 0;
|
||||
memcpy(appl_id, iucv->dst_name, 8);
|
||||
pr_err("Application %s on z/VM guest %s"
|
||||
" exceeds message limit\n",
|
||||
user_id, appl_id);
|
||||
}
|
||||
/* set iucv message target class */
|
||||
memcpy(&txmsg.class,
|
||||
(void *) CMSG_DATA(cmsg), TRGCLS_SIZE);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* allocate one skb for each iucv message:
|
||||
* this is fine for SOCK_SEQPACKET (unless we want to support
|
||||
* segmented records using the MSG_EOR flag), but
|
||||
* for SOCK_STREAM we might want to improve it in future */
|
||||
skb = sock_alloc_send_skb(sk, len, noblock, &err);
|
||||
if (!skb)
|
||||
goto out;
|
||||
if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) {
|
||||
err = -EFAULT;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* wait if outstanding messages for iucv path has reached */
|
||||
timeo = sock_sndtimeo(sk, noblock);
|
||||
err = iucv_sock_wait(sk, iucv_below_msglim(sk), timeo);
|
||||
if (err)
|
||||
goto fail;
|
||||
|
||||
/* return -ECONNRESET if the socket is no longer connected */
|
||||
if (sk->sk_state != IUCV_CONNECTED) {
|
||||
err = -ECONNRESET;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* increment and save iucv message tag for msg_completion cbk */
|
||||
txmsg.tag = iucv->send_tag++;
|
||||
memcpy(CB_TAG(skb), &txmsg.tag, CB_TAG_LEN);
|
||||
skb_queue_tail(&iucv->send_skb_q, skb);
|
||||
|
||||
if (((iucv->path->flags & IUCV_IPRMDATA) & iucv->flags)
|
||||
&& skb->len <= 7) {
|
||||
err = iucv_send_iprm(iucv->path, &txmsg, skb);
|
||||
|
||||
/* on success: there is no message_complete callback
|
||||
* for an IPRMDATA msg; remove skb from send queue */
|
||||
if (err == 0) {
|
||||
skb_unlink(skb, &iucv->send_skb_q);
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
/* this error should never happen since the
|
||||
* IUCV_IPRMDATA path flag is set... sever path */
|
||||
if (err == 0x15) {
|
||||
iucv_path_sever(iucv->path, NULL);
|
||||
skb_unlink(skb, &iucv->send_skb_q);
|
||||
err = -EPIPE;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
} else {
|
||||
err = -ENOTCONN;
|
||||
goto out;
|
||||
} else
|
||||
err = iucv_message_send(iucv->path, &txmsg, 0, 0,
|
||||
(void *) skb->data, skb->len);
|
||||
if (err) {
|
||||
if (err == 3) {
|
||||
user_id[8] = 0;
|
||||
memcpy(user_id, iucv->dst_user_id, 8);
|
||||
appl_id[8] = 0;
|
||||
memcpy(appl_id, iucv->dst_name, 8);
|
||||
pr_err("Application %s on z/VM guest %s"
|
||||
" exceeds message limit\n",
|
||||
appl_id, user_id);
|
||||
err = -EAGAIN;
|
||||
} else
|
||||
err = -EPIPE;
|
||||
skb_unlink(skb, &iucv->send_skb_q);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
release_sock(sk);
|
||||
@@ -1581,7 +1638,11 @@ static void iucv_callback_txdone(struct iucv_path *path,
|
||||
|
||||
spin_unlock_irqrestore(&list->lock, flags);
|
||||
|
||||
kfree_skb(this);
|
||||
if (this) {
|
||||
kfree_skb(this);
|
||||
/* wake up any process waiting for sending */
|
||||
iucv_sock_wake_msglim(sk);
|
||||
}
|
||||
}
|
||||
BUG_ON(!this);
|
||||
|
||||
|
Reference in New Issue
Block a user