diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-03-27 23:54:12 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-03-27 23:54:12 +0000 |
commit | d3e71cb08747743fce908122bab08b479eb403a5 (patch) | |
tree | cbec6948fdbdee9af81cf3ecfb504070d2745d7b /net | |
parent | fe7ff1706e323d0e5ed83972960a1ecc1ee538b3 (diff) |
Merge with Linux 2.3.99-pre3.
Diffstat (limited to 'net')
52 files changed, 1615 insertions, 1226 deletions
diff --git a/net/802/tr.c b/net/802/tr.c index 2d836d9c5..4133c2207 100644 --- a/net/802/tr.c +++ b/net/802/tr.c @@ -237,8 +237,9 @@ static void tr_source_route(struct sk_buff *skb,struct trh_hdr *trh,struct net_d rif_cache entry; unsigned char *olddata; unsigned char mcast_func_addr[] = {0xC0,0x00,0x00,0x04,0x00,0x00}; + unsigned long flags ; - spin_lock_bh(&rif_lock); + spin_lock_irqsave(&rif_lock,flags); /* * Broadcasts are single route as stated in RFC 1042 @@ -308,7 +309,7 @@ printk("source routing for %02X %02X %02X %02X %02X %02X\n",trh->daddr[0], else slack = 18 - ((ntohs(trh->rcf) & TR_RCF_LEN_MASK)>>8); olddata = skb->data; - spin_unlock_bh(&rif_lock); + spin_unlock_irqrestore(&rif_lock,flags); skb_pull(skb, slack); memmove(skb->data, olddata, sizeof(struct trh_hdr) - slack); @@ -418,8 +419,9 @@ static void rif_check_expire(unsigned long dummy) { int i; unsigned long now=jiffies; + unsigned long flags ; - spin_lock(&rif_lock); + spin_lock_irqsave(&rif_lock,flags); for(i=0; i < RIF_TABLE_SIZE;i++) { @@ -439,7 +441,7 @@ static void rif_check_expire(unsigned long dummy) } } - spin_unlock(&rif_lock); + spin_unlock_irqrestore(&rif_lock,flags); /* * Reset the timer diff --git a/net/atm/Makefile b/net/atm/Makefile index 1c525f601..a43d790b1 100644 --- a/net/atm/Makefile +++ b/net/atm/Makefile @@ -16,10 +16,6 @@ ifeq ($(CONFIG_ATM),y) O_OBJS = addr.o pvc.o signaling.o svc.o OX_OBJS = common.o atm_misc.o raw.o resources.o -ifeq ($(CONFIG_MMU_HACKS),y) -O_OBJS += mmuio.o -endif - ifeq ($(CONFIG_ATM_CLIP),y) O_OBJS += clip.o NEED_IPCOM = ipcommon.o @@ -36,10 +32,11 @@ OX_OBJS += proc.o endif ifeq ($(CONFIG_ATM_LANE),y) -O_OBJS += lec.o lane_mpoa_init.o +O_OBJS += lec.o +OX_OBJS += lane_mpoa_init.o else ifeq ($(CONFIG_ATM_LANE),m) - O_OBJS += lane_mpoa_init.o + OX_OBJS += lane_mpoa_init.o M_OBJS += lec.o endif endif diff --git a/net/atm/addr.c b/net/atm/addr.c index f7d52a824..8bca9d1c3 100644 --- a/net/atm/addr.c +++ b/net/atm/addr.c @@ -1,11 +1,11 @@ /* net/atm/addr.c - Local ATM address registry */ -/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */ +/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */ #include <linux/atm.h> #include <linux/atmdev.h> -#include <linux/wait.h> +#include <linux/sched.h> #include <asm/uaccess.h> #include "signaling.h" @@ -41,23 +41,7 @@ static int identical(struct sockaddr_atmsvc *a,struct sockaddr_atmsvc *b) * (which may involve page faults and therefore rescheduling) */ - -static volatile int local_lock = 0; -static wait_queue_head_t local_wait; - - -static void lock_local(void) -{ - while (local_lock) sleep_on(&local_wait); - local_lock = 1; -} - - -static void unlock_local(void) -{ - local_lock = 0; - wake_up(&local_wait); -} +static DECLARE_MUTEX(local_lock); static void notify_sigd(struct atm_dev *dev) @@ -73,13 +57,13 @@ void reset_addr(struct atm_dev *dev) { struct atm_dev_addr *this; - lock_local(); + down(&local_lock); while (dev->local) { this = dev->local; dev->local = this->next; kfree(this); } - unlock_local(); + up(&local_lock); notify_sigd(dev); } @@ -91,20 +75,20 @@ int add_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr) error = check_addr(addr); if (error) return error; - lock_local(); + down(&local_lock); for (walk = &dev->local; *walk; walk = &(*walk)->next) if (identical(&(*walk)->addr,addr)) { - unlock_local(); + up(&local_lock); return -EEXIST; } *walk = kmalloc(sizeof(struct atm_dev_addr),GFP_KERNEL); if (!*walk) { - unlock_local(); + up(&local_lock); return -ENOMEM; } (*walk)->addr = *addr; (*walk)->next = NULL; - unlock_local(); + up(&local_lock); notify_sigd(dev); return 0; } @@ -117,17 +101,17 @@ int del_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr) error = check_addr(addr); if (error) return error; - lock_local(); + down(&local_lock); for (walk = &dev->local; *walk; walk = &(*walk)->next) if (identical(&(*walk)->addr,addr)) break; if (!*walk) { - unlock_local(); + up(&local_lock); return -ENOENT; } this = *walk; *walk = this->next; kfree(this); - unlock_local(); + up(&local_lock); notify_sigd(dev); return 0; } @@ -138,27 +122,21 @@ int get_addr(struct atm_dev *dev,struct sockaddr_atmsvc *u_buf,int size) struct atm_dev_addr *walk; int total; - lock_local(); + down(&local_lock); total = 0; for (walk = dev->local; walk; walk = walk->next) { total += sizeof(struct sockaddr_atmsvc); if (total > size) { - unlock_local(); + up(&local_lock); return -E2BIG; } if (copy_to_user(u_buf,&walk->addr, sizeof(struct sockaddr_atmsvc))) { - unlock_local(); + up(&local_lock); return -EFAULT; } u_buf++; } - unlock_local(); + up(&local_lock); return total; } - - -void init_addr(void) -{ - init_waitqueue_head(&local_wait); -} diff --git a/net/atm/addr.h b/net/atm/addr.h index fcd134023..84a98e7c0 100644 --- a/net/atm/addr.h +++ b/net/atm/addr.h @@ -1,6 +1,6 @@ /* net/atm/addr.h - Local ATM address registry */ -/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */ +/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */ #ifndef NET_ATM_ADDR_H @@ -14,6 +14,5 @@ void reset_addr(struct atm_dev *dev); int add_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr); int del_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr); int get_addr(struct atm_dev *dev,struct sockaddr_atmsvc *u_buf,int size); -void init_addr(void); #endif diff --git a/net/atm/atm_misc.c b/net/atm/atm_misc.c index 9e2785ed6..c8e19d2bc 100644 --- a/net/atm/atm_misc.c +++ b/net/atm/atm_misc.c @@ -1,12 +1,14 @@ /* net/atm/atm_misc.c - Various functions for use by ATM drivers */ -/* Written 1995-1999 by Werner Almesberger, EPFL ICA */ +/* Written 1995-2000 by Werner Almesberger, EPFL ICA */ #include <linux/module.h> #include <linux/atm.h> #include <linux/atmdev.h> #include <linux/skbuff.h> +#include <linux/sonet.h> +#include <linux/bitops.h> #include <asm/atomic.h> #include <asm/errno.h> @@ -16,7 +18,7 @@ int atm_charge(struct atm_vcc *vcc,int truesize) atm_force_charge(vcc,truesize); if (atomic_read(&vcc->rx_inuse) <= vcc->sk->rcvbuf) return 1; atm_return(vcc,truesize); - vcc->stats->rx_drop++; + atomic_inc(&vcc->stats->rx_drop); return 0; } @@ -36,7 +38,7 @@ struct sk_buff *atm_alloc_charge(struct atm_vcc *vcc,int pdu_size, } } atm_return(vcc,guess); - vcc->stats->rx_drop++; + atomic_inc(&vcc->stats->rx_drop); return NULL; } @@ -46,7 +48,7 @@ static int check_ci(struct atm_vcc *vcc,short vpi,int vci) struct atm_vcc *walk; for (walk = vcc->dev->vccs; walk; walk = walk->next) - if ((walk->flags & ATM_VF_ADDR) && walk->vpi == vpi && + if (test_bit(ATM_VF_ADDR,&walk->flags) && walk->vpi == vpi && walk->vci == vci && ((walk->qos.txtp.traffic_class != ATM_NONE && vcc->qos.txtp.traffic_class != ATM_NONE) || (walk->qos.rxtp.traffic_class != ATM_NONE && @@ -135,7 +137,25 @@ int atm_pcr_goal(struct atm_trafprm *tp) } +void sonet_copy_stats(struct k_sonet_stats *from,struct sonet_stats *to) +{ +#define __HANDLE_ITEM(i) to->i = atomic_read(&from->i) + __SONET_ITEMS +#undef __HANDLE_ITEM +} + + +void sonet_subtract_stats(struct k_sonet_stats *from,struct sonet_stats *to) +{ +#define __HANDLE_ITEM(i) atomic_sub(to->i,&from->i) + __SONET_ITEMS +#undef __HANDLE_ITEM +} + + EXPORT_SYMBOL(atm_charge); EXPORT_SYMBOL(atm_alloc_charge); EXPORT_SYMBOL(atm_find_ci); EXPORT_SYMBOL(atm_pcr_goal); +EXPORT_SYMBOL(sonet_copy_stats); +EXPORT_SYMBOL(sonet_subtract_stats); diff --git a/net/atm/clip.c b/net/atm/clip.c index 98d51c094..37610d6d6 100644 --- a/net/atm/clip.c +++ b/net/atm/clip.c @@ -21,6 +21,7 @@ #include <linux/in.h> /* for struct sockaddr_in */ #include <linux/if.h> /* for IFF_UP */ #include <linux/inetdevice.h> +#include <linux/bitops.h> #include <net/route.h> /* for struct rtable and routing */ #include <net/icmp.h> /* icmp_send */ #include <asm/param.h> /* for HZ */ @@ -196,6 +197,7 @@ void clip_push(struct atm_vcc *vcc,struct sk_buff *skb) atm_return(vcc,skb->truesize); skb->dev = clip_vcc->entry ? clip_vcc->entry->neigh->dev : clip_devs; /* clip_vcc->entry == NULL if we don't have an IP address yet */ + skb->rx_dev = NULL; if (!skb->dev) { kfree_skb(skb); return; @@ -431,7 +433,7 @@ return 0; } clip_priv->stats.tx_packets++; clip_priv->stats.tx_bytes += skb->len; - (void) vcc->dev->ops->send(vcc,skb); + (void) vcc->send(vcc,skb); if (atm_may_send(vcc,0)) { entry->vccs->xoff = 0; return 0; @@ -462,7 +464,6 @@ int clip_mkip(struct atm_vcc *vcc,int timeout) struct clip_vcc *clip_vcc; struct sk_buff_head copy; struct sk_buff *skb; - unsigned long flags; if (!vcc->push) return -EBADFD; clip_vcc = kmalloc(sizeof(struct clip_vcc),GFP_KERNEL); @@ -477,12 +478,9 @@ int clip_mkip(struct atm_vcc *vcc,int timeout) clip_vcc->idle_timeout = timeout*HZ; clip_vcc->old_push = vcc->push; clip_vcc->old_pop = vcc->pop; - save_flags(flags); - cli(); vcc->push = clip_push; vcc->pop = clip_pop; skb_migrate(&vcc->recvq,©); - restore_flags(flags); /* re-process everything received between connection setup and MKIP */ while ((skb = skb_dequeue(©))) if (!clip_devs) { @@ -710,7 +708,7 @@ static struct atm_dev atmarpd_dev = { 999, /* dummy device number */ NULL,NULL, /* pretend not to have any VCCs */ NULL,NULL, /* no data */ - 0, /* no flags */ + { 0 }, /* no flags */ NULL, /* no local address */ { 0 } /* no ESI, no statistics */ }; @@ -729,7 +727,8 @@ int atm_init_atmarp(struct atm_vcc *vcc) add_timer(&idle_timer); } atmarpd = vcc; - vcc->flags |= ATM_VF_READY | ATM_VF_META; + set_bit(ATM_VF_META,&vcc->flags); + set_bit(ATM_VF_READY,&vcc->flags); /* allow replies and avoid getting closed if signaling dies */ bind_vcc(vcc,&atmarpd_dev); vcc->push = NULL; diff --git a/net/atm/common.c b/net/atm/common.c index c4288203c..9625061eb 100644 --- a/net/atm/common.c +++ b/net/atm/common.c @@ -19,9 +19,11 @@ #include <linux/sched.h> #include <linux/time.h> /* struct timeval */ #include <linux/skbuff.h> +#include <linux/bitops.h> #include <net/sock.h> /* struct sock */ #include <asm/uaccess.h> +#include <asm/atomic.h> #include <asm/poll.h> #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) @@ -96,7 +98,7 @@ int atm_create(struct socket *sock,int protocol,int family) if (sock->type == SOCK_STREAM) return -EINVAL; if (!(sk = alloc_atm_vcc_sk(family))) return -ENOMEM; vcc = sk->protinfo.af_atm; - vcc->flags = 0; + memset(&vcc->flags,0,sizeof(vcc->flags)); vcc->dev = NULL; vcc->family = sock->ops->family; vcc->alloc_tx = alloc_tx; @@ -126,7 +128,7 @@ void atm_release_vcc_sk(struct sock *sk,int free_sk) struct sk_buff *skb; vcc = sk->protinfo.af_atm; - vcc->flags &= ~ATM_VF_READY; + clear_bit(ATM_VF_READY,&vcc->flags); if (vcc->dev) { if (vcc->dev->ops->close) vcc->dev->ops->close(vcc); if (vcc->push) vcc->push(vcc,NULL); /* atmarpd has no push */ @@ -156,9 +158,8 @@ int atm_release(struct socket *sock) void atm_async_release_vcc(struct atm_vcc *vcc,int reply) { - vcc->flags |= ATM_VF_CLOSE; + set_bit(ATM_VF_CLOSE,&vcc->flags); vcc->reply = reply; - /*vcc->flags &= ~ATM_VF_READY;*/ wake_up(&vcc->sleep); } @@ -204,6 +205,7 @@ static int atm_do_connect_dev(struct atm_vcc *vcc,struct atm_dev *dev,int vpi, if (vci > 0 && vci < ATM_NOT_RSV_VCI && !capable(CAP_NET_BIND_SERVICE)) return -EPERM; error = 0; + bind_vcc(vcc,dev); switch (vcc->qos.aal) { case ATM_AAL0: error = atm_init_aal0(vcc); @@ -226,8 +228,10 @@ static int atm_do_connect_dev(struct atm_vcc *vcc,struct atm_dev *dev,int vpi, } if (!error) error = adjust_tp(&vcc->qos.txtp,vcc->qos.aal); if (!error) error = adjust_tp(&vcc->qos.rxtp,vcc->qos.aal); - if (error) return error; - bind_vcc(vcc,dev); + if (error) { + bind_vcc(vcc,NULL); + return error; + } DPRINTK("VCC %d.%d, AAL %d\n",vpi,vci,vcc->qos.aal); DPRINTK(" TX: %d, PCR %d..%d, SDU %d\n",vcc->qos.txtp.traffic_class, vcc->qos.txtp.min_pcr,vcc->qos.txtp.max_pcr,vcc->qos.txtp.max_sdu); @@ -257,8 +261,8 @@ static int atm_do_connect(struct atm_vcc *vcc,int itf,int vpi,int vci) int atm_connect_vcc(struct atm_vcc *vcc,int itf,short vpi,int vci) { if (vpi != ATM_VPI_UNSPEC && vci != ATM_VCI_UNSPEC) - vcc->flags &= ~ATM_VF_PARTIAL; - else if (vcc->flags & ATM_VF_PARTIAL) return -EINVAL; + clear_bit(ATM_VF_PARTIAL,&vcc->flags); + else if (test_bit(ATM_VF_PARTIAL,&vcc->flags)) return -EINVAL; printk(KERN_DEBUG "atm_connect (TX: cl %d,bw %d-%d,sdu %d; " "RX: cl %d,bw %d-%d,sdu %d,AAL %s%d)\n", vcc->qos.txtp.traffic_class,vcc->qos.txtp.min_pcr, @@ -267,7 +271,7 @@ int atm_connect_vcc(struct atm_vcc *vcc,int itf,short vpi,int vci) vcc->qos.rxtp.max_pcr,vcc->qos.rxtp.max_sdu, vcc->qos.aal == ATM_AAL5 ? "" : vcc->qos.aal == ATM_AAL0 ? "" : " ??? code ",vcc->qos.aal == ATM_AAL0 ? 0 : vcc->qos.aal); - if (!(vcc->flags & ATM_VF_HASQOS)) return -EBADFD; + if (!test_bit(ATM_VF_HASQOS,&vcc->flags)) return -EBADFD; if (vcc->qos.txtp.traffic_class == ATM_ANYCLASS || vcc->qos.rxtp.traffic_class == ATM_ANYCLASS) return -EINVAL; @@ -285,7 +289,7 @@ int atm_connect_vcc(struct atm_vcc *vcc,int itf,short vpi,int vci) if (!dev) return -ENODEV; } if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC) - vcc->flags |= ATM_VF_PARTIAL; + set_bit(ATM_VF_PARTIAL,&vcc->flags); return 0; } @@ -300,7 +304,8 @@ int atm_connect(struct socket *sock,int itf,short vpi,int vci) if (!(vpi || vci)) return -EINVAL; error = atm_connect_vcc(ATM_SD(sock),itf,vpi,vci); if (error) return error; - if (ATM_SD(sock)->flags & ATM_VF_READY) sock->state = SS_CONNECTED; + if (test_bit(ATM_VF_READY,&ATM_SD(sock)->flags)) + sock->state = SS_CONNECTED; return 0; } @@ -308,11 +313,10 @@ int atm_connect(struct socket *sock,int itf,short vpi,int vci) int atm_recvmsg(struct socket *sock,struct msghdr *m,int total_len, int flags,struct scm_cookie *scm) { + DECLARE_WAITQUEUE(wait,current); struct atm_vcc *vcc; struct sk_buff *skb; - unsigned long cpu_flags; int eff_len,error; - void *buff; int size; @@ -322,28 +326,33 @@ int atm_recvmsg(struct socket *sock,struct msghdr *m,int total_len, buff = m->msg_iov->iov_base; size = m->msg_iov->iov_len; vcc = ATM_SD(sock); - save_flags(cpu_flags); - cli(); + add_wait_queue(&vcc->sleep,&wait); + set_current_state(TASK_INTERRUPTIBLE); + error = 1; /* <= 0 is error */ while (!(skb = skb_dequeue(&vcc->recvq))) { - if (vcc->flags & (ATM_VF_RELEASED | ATM_VF_CLOSE)) { - restore_flags(cpu_flags); - return vcc->reply; + if (test_bit(ATM_VF_RELEASED,&vcc->flags) || + test_bit(ATM_VF_CLOSE,&vcc->flags)) { + error = vcc->reply; + break; } - if (!(vcc->flags & ATM_VF_READY)) { - restore_flags(cpu_flags); - return 0; + if (!test_bit(ATM_VF_READY,&vcc->flags)) { + error = 0; + break; } if (flags & MSG_DONTWAIT) { - restore_flags(cpu_flags); - return -EAGAIN; + error = -EAGAIN; + break; } - interruptible_sleep_on(&vcc->sleep); + schedule(); + set_current_state(TASK_INTERRUPTIBLE); if (signal_pending(current)) { - restore_flags(cpu_flags); - return -ERESTARTSYS; + error = -ERESTARTSYS; + break; } } - restore_flags(cpu_flags); + set_current_state(TASK_RUNNING); + remove_wait_queue(&vcc->sleep,&wait); + if (error <= 0) return error; vcc->timestamp = skb->stamp; eff_len = skb->len > size ? size : skb->len; if (vcc->dev->ops->feedback) @@ -383,10 +392,10 @@ int atm_recvmsg(struct socket *sock,struct msghdr *m,int total_len, int atm_sendmsg(struct socket *sock,struct msghdr *m,int total_len, struct scm_cookie *scm) { + DECLARE_WAITQUEUE(wait,current); struct atm_vcc *vcc; struct sk_buff *skb; int eff,error; - const void *buff; int size; @@ -396,19 +405,40 @@ int atm_sendmsg(struct socket *sock,struct msghdr *m,int total_len, buff = m->msg_iov->iov_base; size = m->msg_iov->iov_len; vcc = ATM_SD(sock); - if (vcc->flags & (ATM_VF_RELEASED | ATM_VF_CLOSE)) return vcc->reply; - if (!(vcc->flags & ATM_VF_READY)) return -EPIPE; + if (test_bit(ATM_VF_RELEASED,&vcc->flags) || + test_bit(ATM_VF_CLOSE,&vcc->flags)) + return vcc->reply; + if (!test_bit(ATM_VF_READY,&vcc->flags)) return -EPIPE; if (!size) return 0; /* verify_area is done by net/socket.c */ eff = (size+3) & ~3; /* align to word boundary */ + add_wait_queue(&vcc->wsleep,&wait); + set_current_state(TASK_INTERRUPTIBLE); + error = 0; while (!(skb = vcc->alloc_tx(vcc,eff))) { - if (m->msg_flags & MSG_DONTWAIT) return -EAGAIN; - interruptible_sleep_on(&vcc->wsleep); - if (signal_pending(current)) return -ERESTARTSYS; - if (vcc->flags & (ATM_VF_RELEASED | ATM_VF_CLOSE)) - return vcc->reply; - if (!(vcc->flags & ATM_VF_READY)) return -EPIPE; + if (m->msg_flags & MSG_DONTWAIT) { + error = -EAGAIN; + break; + } + schedule(); + set_current_state(TASK_INTERRUPTIBLE); + if (signal_pending(current)) { + error = -ERESTARTSYS; + break; + } + if (test_bit(ATM_VF_RELEASED,&vcc->flags) || + test_bit(ATM_VF_CLOSE,&vcc->flags)) { + error = vcc->reply; + break; + } + if (!test_bit(ATM_VF_READY,&vcc->flags)) { + error = -EPIPE; + break; + } } + set_current_state(TASK_RUNNING); + remove_wait_queue(&vcc->wsleep,&wait); + if (error) return error; skb->dev = NULL; /* for paths shared with net_device interfaces */ ATM_SKB(skb)->iovcnt = 0; ATM_SKB(skb)->atm_options = vcc->atm_options; @@ -433,7 +463,9 @@ unsigned int atm_poll(struct file *file,struct socket *sock,poll_table *wait) mask = 0; if (skb_peek(&vcc->recvq) || skb_peek(&vcc->listenq)) mask |= POLLIN | POLLRDNORM; - if (vcc->flags & (ATM_VF_RELEASED | ATM_VF_CLOSE)) mask |= POLLHUP; + if (test_bit(ATM_VF_RELEASED,&vcc->flags) || + test_bit(ATM_VF_CLOSE,&vcc->flags)) + mask |= POLLHUP; if (sock->state != SS_CONNECTING) { if (vcc->qos.txtp.traffic_class != ATM_NONE && vcc->qos.txtp.max_sdu+atomic_read(&vcc->tx_inuse)+ @@ -448,20 +480,38 @@ unsigned int atm_poll(struct file *file,struct socket *sock,poll_table *wait) } -static int fetch_stats(struct atm_dev *dev,struct atm_dev_stats *arg,int zero) +static void copy_aal_stats(struct k_atm_aal_stats *from, + struct atm_aal_stats *to) { - unsigned long flags; - int error; +#define __HANDLE_ITEM(i) to->i = atomic_read(&from->i) + __AAL_STAT_ITEMS +#undef __HANDLE_ITEM +} - error = 0; - save_flags(flags); - cli(); - if (arg) - error = copy_to_user(arg,&dev->stats, - sizeof(struct atm_dev_stats)); - if (zero && !error) - memset(&dev->stats,0,sizeof(struct atm_dev_stats)); - restore_flags(flags); + +static void subtract_aal_stats(struct k_atm_aal_stats *from, + struct atm_aal_stats *to) +{ +#define __HANDLE_ITEM(i) atomic_sub(to->i,&from->i) + __AAL_STAT_ITEMS +#undef __HANDLE_ITEM +} + + +static int fetch_stats(struct atm_dev *dev,struct atm_dev_stats *arg,int zero) +{ + struct atm_dev_stats tmp; + int error = 0; + + copy_aal_stats(&dev->stats.aal0,&tmp.aal0); + copy_aal_stats(&dev->stats.aal34,&tmp.aal34); + copy_aal_stats(&dev->stats.aal5,&tmp.aal5); + if (arg) error = copy_to_user(arg,&tmp,sizeof(tmp)); + if (zero && !error) { + subtract_aal_stats(&dev->stats.aal0,&tmp.aal0); + subtract_aal_stats(&dev->stats.aal34,&tmp.aal34); + subtract_aal_stats(&dev->stats.aal5,&tmp.aal5); + } return error ? -EFAULT : 0; } @@ -478,7 +528,8 @@ int atm_ioctl(struct socket *sock,unsigned int cmd,unsigned long arg) switch (cmd) { case SIOCOUTQ: if (sock->state != SS_CONNECTED || - !(vcc->flags & ATM_VF_READY)) return -EINVAL; + !test_bit(ATM_VF_READY,&vcc->flags)) + return -EINVAL; return put_user(vcc->sk->sndbuf- atomic_read(&vcc->tx_inuse)-ATM_PDU_OVHD, (int *) arg) ? -EFAULT : 0; @@ -522,6 +573,14 @@ int atm_ioctl(struct socket *sock,unsigned int cmd,unsigned long arg) return 0; case ATMSIGD_CTRL: if (!capable(CAP_NET_ADMIN)) return -EPERM; + /* + * The user/kernel protocol for exchanging signalling + * info uses kernel pointers as opaque references, + * so the holder of the file descriptor can scribble + * on the kernel... so we should make sure that we + * have the same privledges that /proc/kcore needs + */ + if (!capable(CAP_SYS_RAWIO)) return -EPERM; error = sigd_attach(vcc); if (!error) sock->state = SS_CONNECTED; return error; @@ -668,6 +727,12 @@ int atm_ioctl(struct socket *sock,unsigned int cmd,unsigned long arg) write the length" */ return put_user(size, &((struct atmif_sioc *) arg)->length) ? -EFAULT : 0; + case ATM_SETLOOP: + if (__ATM_LM_XTRMT((int) (long) buf) && + __ATM_LM_XTLOC((int) (long) buf) > + __ATM_LM_XTRMT((int) (long) buf)) + return -EINVAL; + /* fall through */ case ATM_SETCIRANGE: case SONET_GETSTATZ: case SONET_SETDIAG: @@ -689,6 +754,14 @@ int atm_ioctl(struct socket *sock,unsigned int cmd,unsigned long arg) int atm_change_qos(struct atm_vcc *vcc,struct atm_qos *qos) { + /* + * Don't let the QoS change the already connected AAL type nor the + * traffic class. + */ + if (qos->aal != vcc->qos.aal || + qos->rxtp.traffic_class != vcc->qos.rxtp.traffic_class || + qos->txtp.traffic_class != vcc->qos.txtp.traffic_class) + return -EINVAL; if (!vcc->dev->ops->change_qos) return -EOPNOTSUPP; if (vcc->family == AF_ATMPVC) return vcc->dev->ops->change_qos(vcc,qos,ATM_MF_SET); @@ -751,7 +824,7 @@ static int atm_do_setsockopt(struct socket *sock,int level,int optname, if (sock->state != SS_UNCONNECTED) return -EBADFD; vcc->qos = qos; - vcc->flags |= ATM_VF_HASQOS; + set_bit(ATM_VF_HASQOS,&vcc->flags); return 0; } case SO_SETCLP: @@ -777,7 +850,8 @@ static int atm_do_getsockopt(struct socket *sock,int level,int optname, vcc = ATM_SD(sock); switch (optname) { case SO_ATMQOS: - if (!(vcc->flags & ATM_VF_HASQOS)) return -EINVAL; + if (!test_bit(ATM_VF_HASQOS,&vcc->flags)) + return -EINVAL; return copy_to_user(optval,&vcc->qos,sizeof(vcc->qos)) ? -EFAULT : 0; case SO_SETCLP: @@ -787,7 +861,8 @@ static int atm_do_getsockopt(struct socket *sock,int level,int optname, { struct sockaddr_atmpvc pvc; - if (!vcc->dev || !(vcc->flags & ATM_VF_ADDR)) + if (!vcc->dev || + !test_bit(ATM_VF_ADDR,&vcc->flags)) return -ENOTCONN; pvc.sap_family = AF_ATMPVC; pvc.sap_addr.itf = vcc->dev->number; diff --git a/net/atm/ipcommon.c b/net/atm/ipcommon.c index 4bf7a1918..d7c4a4d3a 100644 --- a/net/atm/ipcommon.c +++ b/net/atm/ipcommon.c @@ -1,6 +1,6 @@ /* net/atm/ipcommon.c - Common items for all ways of doing IP over ATM */ -/* Written 1996,1997 by Werner Almesberger, EPFL LRC */ +/* Written 1996-2000 by Werner Almesberger, EPFL LRC/ICA */ #include <linux/string.h> @@ -32,20 +32,26 @@ const unsigned char llc_oui[] = { /* * skb_migrate moves the list at FROM to TO, emptying FROM in the process. - * This function should live in skbuff.c or skbuff.h. Note that skb_migrate - * is not atomic, so turn off interrupts when using it. + * This function should live in skbuff.c or skbuff.h. */ void skb_migrate(struct sk_buff_head *from,struct sk_buff_head *to) { - struct sk_buff *skb,*prev; + struct sk_buff *skb; + unsigned long flags; - for (skb = ((struct sk_buff *) from)->next; - skb != (struct sk_buff *) from; skb = skb->next) skb->list = to; - prev = from->prev; - from->next->prev = (struct sk_buff *) to; - prev->next = (struct sk_buff *) to; + spin_lock_irqsave(&from->lock,flags); *to = *from; - skb_queue_head_init(from); + from->prev = (struct sk_buff *) from; + from->next = (struct sk_buff *) from; + from->qlen = 0; + spin_unlock_irqrestore(&from->lock,flags); + spin_lock_init(&to->lock); + for (skb = ((struct sk_buff *) to)->next; + skb != (struct sk_buff *) from; skb = skb->next) skb->list = to; + if (to->next == (struct sk_buff *) from) + to->next = (struct sk_buff *) to; + to->next->prev = (struct sk_buff *) to; + to->prev->next = (struct sk_buff *) to; } diff --git a/net/atm/ipcommon.h b/net/atm/ipcommon.h index 105e090d7..30a5583b0 100644 --- a/net/atm/ipcommon.h +++ b/net/atm/ipcommon.h @@ -1,6 +1,6 @@ /* net/atm/ipcommon.h - Common items for all ways of doing IP over ATM */ -/* Written 1996-1998 by Werner Almesberger, EPFL LRC/ICA */ +/* Written 1996-2000 by Werner Almesberger, EPFL LRC/ICA */ #ifndef NET_ATM_IPCOMMON_H @@ -15,6 +15,10 @@ extern struct net_device *clip_devs; +/* + * Moves all skbs from "from" to "to". The operation is atomic for "from", but + * not for "to". "to" may only be accessed after skb_migrate finishes. + */ void skb_migrate(struct sk_buff_head *from,struct sk_buff_head *to); diff --git a/net/atm/lane_mpoa_init.c b/net/atm/lane_mpoa_init.c index d1938c187..469685703 100644 --- a/net/atm/lane_mpoa_init.c +++ b/net/atm/lane_mpoa_init.c @@ -37,6 +37,18 @@ void atm_mpoa_init(void) #endif #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) +#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) +rwlock_t lane_bridge_hook_lock = RW_LOCK_UNLOCKED; +struct net_bridge_fdb_entry *(*br_fdb_get_hook)(struct net_bridge *br, + unsigned char *addr) = NULL; +void (*br_fdb_put_hook)(struct net_bridge_fdb_entry *ent) = NULL; +#if defined(CONFIG_ATM_LANE_MODULE) || defined(CONFIG_BRIDGE_MODULE) +EXPORT_SYMBOL(lane_bridge_hook_lock); +EXPORT_SYMBOL(br_fdb_get_hook); +EXPORT_SYMBOL(br_fdb_put_hook); +#endif /* defined(CONFIG_ATM_LANE_MODULE) || defined(CONFIG_BRIDGE_MODULE) */ +#endif /* defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) */ + void atm_lane_init(void) { #ifndef CONFIG_ATM_LANE_MODULE /* not module */ diff --git a/net/atm/lec.c b/net/atm/lec.c index 8c6d8d4af..701ece763 100644 --- a/net/atm/lec.c +++ b/net/atm/lec.c @@ -6,6 +6,7 @@ #include <linux/config.h> #include <linux/kernel.h> +#include <linux/bitops.h> /* We are ethernet device */ #include <linux/if_ether.h> @@ -29,9 +30,11 @@ #include <linux/atmdev.h> #include <linux/atmlec.h> -/* Bridge */ -#ifdef CONFIG_BRIDGE -#include <net/br.h> +/* Proxy LEC knows about bridging */ +#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) +#include <linux/if_bridge.h> +#include "../bridge/br_private.h" +unsigned char bridge_ula[] = {0x01, 0x80, 0xc2, 0x00, 0x00}; #endif /* Modular too */ @@ -88,23 +91,19 @@ struct net_device **get_dev_lec (void) { return &dev_lec[0]; } -#ifdef CONFIG_BRIDGE +#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) static void handle_bridge(struct sk_buff *skb, struct net_device *dev) { struct ethhdr *eth; char *buff; struct lec_priv *priv; - unsigned char bridge_ula[ETH_ALEN] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 }; /* Check if this is a BPDU. If so, ask zeppelin to send - * LE_TOPOLOGY_REQUEST with the value of Topology Change bit - * in the Config BPDU*/ + * LE_TOPOLOGY_REQUEST with the same value of Topology Change bit + * as the Config BPDU has */ eth = (struct ethhdr *)skb->data; buff = skb->data + skb->dev->hard_header_len; - if ((memcmp(eth->h_dest, bridge_ula, ETH_ALEN) == 0) && - *buff++ == BRIDGE_LLC1_DSAP && - *buff++ == BRIDGE_LLC1_SSAP && - *buff++ == BRIDGE_LLC1_CTRL) { + if (*buff++ == 0x42 && *buff++ == 0x42 && *buff++ == 0x03) { struct sk_buff *skb2; struct atmlec_msg *mesg; @@ -113,7 +112,8 @@ static void handle_bridge(struct sk_buff *skb, struct net_device *dev) skb2->len = sizeof(struct atmlec_msg); mesg = (struct atmlec_msg *)skb2->data; mesg->type = l_topology_change; - mesg->content.normal.flag = *(skb->nh.raw + BRIDGE_BPDU_8021_CONFIG_FLAG_OFFSET) & TOPOLOGY_CHANGE; + buff += 4; + mesg->content.normal.flag = *buff & 0x01; /* 0x01 is topology change */ priv = (struct lec_priv *)dev->priv; atm_force_charge(priv->lecd, skb2->truesize); @@ -123,7 +123,7 @@ static void handle_bridge(struct sk_buff *skb, struct net_device *dev) return; } -#endif /* CONFIG_BRIDGE */ +#endif /* defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) */ /* * Modelled after tr_type_trans @@ -219,10 +219,10 @@ lec_send_packet(struct sk_buff *skb, struct net_device *dev) DPRINTK("skbuff head:%lx data:%lx tail:%lx end:%lx\n", (long)skb->head, (long)skb->data, (long)skb->tail, (long)skb->end); -#ifdef CONFIG_BRIDGE - if (skb->pkt_bridged == IS_BRIDGED) +#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) + if (memcmp(skb->data, bridge_ula, sizeof(bridge_ula)) == 0) handle_bridge(skb, dev); -#endif /* CONFIG_BRIDGE */ +#endif /* Make sure we have room for lec_id */ if (skb_headroom(skb) < 2) { @@ -303,7 +303,7 @@ lec_send_packet(struct sk_buff *skb, struct net_device *dev) send_vcc = lec_arp_resolve(priv, dst, is_rdesc, &entry); DPRINTK("%s:send_vcc:%p vcc_flags:%x, entry:%p\n", dev->name, send_vcc, send_vcc?send_vcc->flags:0, entry); - if (!send_vcc || !(send_vcc->flags & ATM_VF_READY)) { + if (!send_vcc || !test_bit(ATM_VF_READY,&send_vcc->flags)) { if (entry && (entry->tx_wait.qlen < LEC_UNRES_QUE_LEN)) { DPRINTK("%s:lec_send_packet: queuing packet, ", dev->name); DPRINTK("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n", @@ -339,7 +339,7 @@ lec_send_packet(struct sk_buff *skb, struct net_device *dev) send_vcc->vpi, send_vcc->vci); priv->stats.tx_packets++; priv->stats.tx_bytes += skb2->len; - send_vcc->dev->ops->send(send_vcc, skb2); + send_vcc->send(send_vcc, skb2); } ATM_SKB(skb)->vcc = send_vcc; @@ -348,7 +348,7 @@ lec_send_packet(struct sk_buff *skb, struct net_device *dev) ATM_SKB(skb)->atm_options = send_vcc->atm_options; priv->stats.tx_packets++; priv->stats.tx_bytes += skb->len; - send_vcc->dev->ops->send(send_vcc, skb); + send_vcc->send(send_vcc, skb); #if 0 /* Should we wait for card's device driver to notify us? */ @@ -463,32 +463,44 @@ lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb) priv->lecid=(unsigned short)(0xffff&mesg->content.normal.flag); break; case l_should_bridge: { -#ifdef CONFIG_BRIDGE - struct fdb *f; - extern Port_data port_info[]; +#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) + struct net_bridge_fdb_entry *f; DPRINTK("%s: bridge zeppelin asks about 0x%02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, mesg->content.proxy.mac_addr[0], mesg->content.proxy.mac_addr[1], mesg->content.proxy.mac_addr[2], mesg->content.proxy.mac_addr[3], mesg->content.proxy.mac_addr[4], mesg->content.proxy.mac_addr[5]); - f = br_avl_find_addr(mesg->content.proxy.mac_addr); /* bridge/br.c */ + + read_lock(&lane_bridge_hook_lock); + if (br_fdb_get_hook == NULL || dev->br_port == NULL) { + read_unlock(&lane_bridge_hook_lock); + break; + } + + f = br_fdb_get_hook(dev->br_port->br, mesg->content.proxy.mac_addr); if (f != NULL && - port_info[f->port].dev != dev && - port_info[f->port].state == Forwarding) { + f->dst->dev != dev && + f->dst->state == BR_STATE_FORWARDING) { /* hit from bridge table, send LE_ARP_RESPONSE */ struct sk_buff *skb2; DPRINTK("%s: entry found, responding to zeppelin\n", dev->name); skb2 = alloc_skb(sizeof(struct atmlec_msg), GFP_ATOMIC); - if (skb2 == NULL) break; + if (skb2 == NULL) { + br_fdb_put_hook(f); + read_unlock(&lane_bridge_hook_lock); + break; + } skb2->len = sizeof(struct atmlec_msg); memcpy(skb2->data, mesg, sizeof(struct atmlec_msg)); atm_force_charge(priv->lecd, skb2->truesize); skb_queue_tail(&priv->lecd->recvq, skb2); wake_up(&priv->lecd->sleep); } -#endif /* CONFIG_BRIDGE */ + if (f != NULL) br_fdb_put_hook(f); + read_unlock(&lane_bridge_hook_lock); +#endif /* defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) */ } break; default: @@ -537,7 +549,7 @@ static struct atm_dev lecatm_dev = { 999, /*dummy device number*/ NULL,NULL, /*no VCCs*/ NULL,NULL, /*no data*/ - 0, /*no flags*/ + { 0 }, /*no flags*/ NULL, /* no local address*/ { 0 } /*no ESI or rest of the atm_dev struct things*/ }; @@ -684,6 +696,7 @@ lec_push(struct atm_vcc *vcc, struct sk_buff *skb) lec_arp_check_empties(priv, vcc, skb); } skb->dev = dev; + skb->rx_dev = NULL; skb->data += 2; /* skip lec_id */ #ifdef CONFIG_TR if (priv->is_trdev) skb->protocol = tr_type_trans(skb, dev); @@ -777,7 +790,8 @@ lecd_attach(struct atm_vcc *vcc, int arg) bind_vcc(vcc, &lecatm_dev); vcc->proto_data = dev_lec[i]; - vcc->flags |= ATM_VF_READY | ATM_VF_META; + set_bit(ATM_VF_META,&vcc->flags); + set_bit(ATM_VF_READY,&vcc->flags); /* Set default values to these variables */ priv->maximum_unknown_frame_count = 1; @@ -1055,8 +1069,8 @@ lec_arp_clear_vccs(struct lec_arp_table *entry) if (entry->vcc) { entry->vcc->push = entry->old_push; #if 0 /* August 6, 1998 */ - entry->vcc->flags |= ATM_VF_RELEASED; - entry->vcc->flags &= ~ATM_VF_READY; + set_bit(ATM_VF_RELEASED,&entry->vcc->flags); + clear_bit(ATM_VF_READY,&entry->vcc->flags); entry->vcc->push(entry->vcc, NULL); #endif atm_async_release_vcc(entry->vcc, -EPIPE); @@ -1065,8 +1079,8 @@ lec_arp_clear_vccs(struct lec_arp_table *entry) if (entry->recv_vcc) { entry->recv_vcc->push = entry->old_recv_push; #if 0 - entry->recv_vcc->flags |= ATM_VF_RELEASED; - entry->recv_vcc->flags &= ~ATM_VF_READY; + set_bit(ATM_VF_RELEASED,&entry->vcc->flags); + clear_bit(ATM_VF_READY,&entry->vcc->flags); entry->recv_vcc->push(entry->recv_vcc, NULL); #endif atm_async_release_vcc(entry->recv_vcc, -EPIPE); diff --git a/net/atm/lec.h b/net/atm/lec.h index 4a94c2b6d..df08e6803 100644 --- a/net/atm/lec.h +++ b/net/atm/lec.h @@ -9,10 +9,19 @@ #ifndef _LEC_H_ #define _LEC_H_ +#include <linux/config.h> #include <linux/atmdev.h> #include <linux/netdevice.h> #include <linux/atmlec.h> +#if defined (CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) +#include <linux/if_bridge.h> +extern rwlock_t lane_bridge_hook_lock; +struct net_bridge_fdb_entry *(*br_fdb_get_hook)(struct net_bridge *br, + unsigned char *addr); +void (*br_fdb_put_hook)(struct net_bridge_fdb_entry *ent); +#endif /* defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) */ + #define LEC_HEADER_LEN 16 struct lecdatahdr_8023 { diff --git a/net/atm/mpc.c b/net/atm/mpc.c index b9247334f..deeb737f5 100644 --- a/net/atm/mpc.c +++ b/net/atm/mpc.c @@ -2,6 +2,7 @@ #include <linux/string.h> #include <linux/timer.h> #include <linux/init.h> +#include <linux/bitops.h> /* We are an ethernet device */ #include <linux/if_ether.h> @@ -522,7 +523,7 @@ static int send_via_shortcut(struct sk_buff *skb, struct mpoa_client *mpc) atomic_add(skb->truesize, &entry->shortcut->tx_inuse); ATM_SKB(skb)->iovcnt = 0; /* just to be safe ... */ ATM_SKB(skb)->atm_options = entry->shortcut->atm_options; - entry->shortcut->dev->ops->send(entry->shortcut, skb); + entry->shortcut->send(entry->shortcut, skb); entry->packets_fwded++; return 0; @@ -739,7 +740,7 @@ static struct atm_dev mpc_dev = { NULL, /* last VCC */ NULL, /* per-device data */ NULL, /* private PHY data */ - 0, /* device flags */ + { 0 }, /* device flags */ NULL, /* local ATM address */ { 0 } /* no ESI */ /* rest of the members will be 0 */ @@ -780,7 +781,8 @@ int atm_mpoa_mpoad_attach (struct atm_vcc *vcc, int arg) mpc->mpoad_vcc = vcc; bind_vcc(vcc, &mpc_dev); - vcc->flags |= ATM_VF_READY | ATM_VF_META; + set_bit(ATM_VF_META,&vcc->flags); + set_bit(ATM_VF_READY,&vcc->flags); if (mpc->dev) { char empty[ATM_ESA_LEN]; diff --git a/net/atm/proc.c b/net/atm/proc.c index 904dc43ba..79ab6e045 100644 --- a/net/atm/proc.c +++ b/net/atm/proc.c @@ -33,6 +33,7 @@ #include <linux/if_arp.h> #include <linux/init.h> /* for __init */ #include <asm/uaccess.h> +#include <asm/atomic.h> #include <asm/param.h> /* for HZ */ #include "resources.h" #include "common.h" /* atm_proc_init prototype */ @@ -64,10 +65,12 @@ static struct file_operations proc_spec_atm_operations = { }; static void add_stats(char *buf,const char *aal, - const struct atm_aal_stats *stats) + const struct k_atm_aal_stats *stats) { - sprintf(strchr(buf,0),"%s ( %d %d %d %d %d )",aal,stats->tx, - stats->tx_err,stats->rx,stats->rx_err,stats->rx_drop); + sprintf(strchr(buf,0),"%s ( %d %d %d %d %d )",aal, + atomic_read(&stats->tx),atomic_read(&stats->tx_err), + atomic_read(&stats->rx),atomic_read(&stats->rx_err), + atomic_read(&stats->rx_drop)); } @@ -217,7 +220,7 @@ static void vc_info(struct atm_vcc *vcc,char *buf) default: here += sprintf(here,"%3d",vcc->family); } - here += sprintf(here," %04x %5d %7d/%7d %7d/%7d\n",vcc->flags, + here += sprintf(here," %04x %5d %7d/%7d %7d/%7d\n",vcc->flags.bits, vcc->reply, atomic_read(&vcc->tx_inuse),vcc->sk->sndbuf, atomic_read(&vcc->rx_inuse),vcc->sk->rcvbuf); @@ -583,7 +586,7 @@ int __init atm_proc_init(void) struct proc_dir_entry *devices = NULL,*pvc = NULL,*svc = NULL; struct proc_dir_entry *arp = NULL,*lec = NULL,*vc = NULL; - atm_proc_root = proc_mkdir("atm", &proc_root); + atm_proc_root = proc_mkdir("net/atm",NULL); if (!atm_proc_root) return -ENOMEM; CREATE_ENTRY(devices); @@ -605,6 +608,6 @@ cleanup: if (arp) remove_proc_entry("arp",atm_proc_root); if (lec) remove_proc_entry("lec",atm_proc_root); if (vc) remove_proc_entry("vc",atm_proc_root); - remove_proc_entry("atm",&proc_root); + remove_proc_entry("net/atm",NULL); return -ENOMEM; } diff --git a/net/atm/pvc.c b/net/atm/pvc.c index 4b6817eb9..2493f04aa 100644 --- a/net/atm/pvc.c +++ b/net/atm/pvc.c @@ -1,6 +1,6 @@ /* net/atm/pvc.c - ATM PVC sockets */ -/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */ +/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */ #include <linux/config.h> @@ -13,6 +13,7 @@ #include <linux/kernel.h> /* printk */ #include <linux/init.h> #include <linux/skbuff.h> +#include <linux/bitops.h> #include <net/sock.h> /* for sock_no_* */ #ifdef CONFIG_ATM_CLIP #include <net/atmclip.h> @@ -42,8 +43,8 @@ static int pvc_bind(struct socket *sock,struct sockaddr *sockaddr, addr = (struct sockaddr_atmpvc *) sockaddr; if (addr->sap_family != AF_ATMPVC) return -EAFNOSUPPORT; vcc = ATM_SD(sock); - if (!(vcc->flags & ATM_VF_HASQOS)) return -EBADFD; - if (vcc->flags & ATM_VF_PARTIAL) { + if (!test_bit(ATM_VF_HASQOS,&vcc->flags)) return -EBADFD; + if (test_bit(ATM_VF_PARTIAL,&vcc->flags)) { if (vcc->vpi != ATM_VPI_UNSPEC) addr->sap_addr.vpi = vcc->vpi; if (vcc->vci != ATM_VCI_UNSPEC) addr->sap_addr.vci = vcc->vci; } @@ -65,7 +66,7 @@ static int pvc_getname(struct socket *sock,struct sockaddr *sockaddr, struct sockaddr_atmpvc *addr; struct atm_vcc *vcc = ATM_SD(sock); - if (!vcc->dev || !(vcc->flags & ATM_VF_ADDR)) return -ENOTCONN; + if (!vcc->dev || !test_bit(ATM_VF_ADDR,&vcc->flags)) return -ENOTCONN; *sockaddr_len = sizeof(struct sockaddr_atmpvc); addr = (struct sockaddr_atmpvc *) sockaddr; addr->sap_family = AF_ATMPVC; diff --git a/net/atm/raw.c b/net/atm/raw.c index 355382502..0899c9f93 100644 --- a/net/atm/raw.c +++ b/net/atm/raw.c @@ -38,16 +38,34 @@ static void atm_pop_raw(struct atm_vcc *vcc,struct sk_buff *skb) { DPRINTK("APopR (%d) %d -= %d\n",vcc->vci,vcc->tx_inuse,skb->truesize); atomic_sub(skb->truesize+ATM_PDU_OVHD,&vcc->tx_inuse); - dev_kfree_skb_irq(skb); + dev_kfree_skb_any(skb); wake_up(&vcc->wsleep); } +static int atm_send_aal0(struct atm_vcc *vcc,struct sk_buff *skb) +{ + /* + * Note that if vpi/vci are _ANY or _UNSPEC the below will + * still work + */ + if (!capable(CAP_NET_ADMIN) && + (((u32 *) skb->data)[0] & (ATM_HDR_VPI_MASK | ATM_HDR_VCI_MASK)) != + ((vcc->vpi << ATM_HDR_VPI_SHIFT) | (vcc->vci << ATM_HDR_VCI_SHIFT))) + { + kfree_skb(skb); + return -EADDRNOTAVAIL; + } + return vcc->dev->ops->send(vcc,skb); +} + + int atm_init_aal0(struct atm_vcc *vcc) { vcc->push = atm_push_raw; vcc->pop = atm_pop_raw; vcc->push_oam = NULL; + vcc->send = atm_send_aal0; return 0; } @@ -57,6 +75,7 @@ int atm_init_aal34(struct atm_vcc *vcc) vcc->push = atm_push_raw; vcc->pop = atm_pop_raw; vcc->push_oam = NULL; + vcc->send = vcc->dev->ops->send; return 0; } @@ -66,6 +85,7 @@ int atm_init_aal5(struct atm_vcc *vcc) vcc->push = atm_push_raw; vcc->pop = atm_pop_raw; vcc->push_oam = NULL; + vcc->send = vcc->dev->ops->send; return 0; } diff --git a/net/atm/resources.c b/net/atm/resources.c index 116682f5b..9502367ef 100644 --- a/net/atm/resources.c +++ b/net/atm/resources.c @@ -1,6 +1,6 @@ /* net/atm/resources.c - Staticly allocated resources */ -/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */ +/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */ #include <linux/config.h> @@ -9,6 +9,7 @@ #include <linux/atmdev.h> #include <linux/kernel.h> /* for barrier */ #include <linux/module.h> +#include <linux/bitops.h> #include <net/sock.h> /* for struct sock */ #include <asm/segment.h> /* for get_fs_long and put_fs_long */ @@ -66,7 +67,7 @@ struct atm_dev *atm_find_dev(int number) struct atm_dev *atm_dev_register(const char *type,const struct atmdev_ops *ops, - int number,unsigned long flags) + int number,atm_dev_flags_t *flags) { struct atm_dev *dev; @@ -91,8 +92,9 @@ struct atm_dev *atm_dev_register(const char *type,const struct atmdev_ops *ops, dev->dev_data = NULL; barrier(); dev->ops = ops; - dev->flags = flags; - memset((void *) &dev->stats,0,sizeof(struct atm_dev_stats)); + if (flags) dev->flags = *flags; + else memset(&dev->flags,0,sizeof(dev->flags)); + memset((void *) &dev->stats,0,sizeof(dev->stats)); #ifdef CONFIG_PROC_FS if (ops->proc_read) if (atm_proc_dev_register(dev) < 0) { @@ -118,7 +120,7 @@ void atm_dev_deregister(struct atm_dev *dev) void shutdown_atm_dev(struct atm_dev *dev) { if (dev->vccs) { - dev->flags |= ATM_DF_CLOSE; + set_bit(ATM_DF_CLOSE,&dev->flags); return; } if (dev->ops->dev_close) dev->ops->dev_close(dev); @@ -165,7 +167,7 @@ static void unlink_vcc(struct atm_vcc *vcc,struct atm_dev *hold_dev) if (vcc->next) vcc->next->prev = vcc->prev; else if (vcc->dev) vcc->dev->last = vcc->prev; if (vcc->dev && vcc->dev != hold_dev && !vcc->dev->vccs && - (vcc->dev->flags & ATM_DF_CLOSE)) + test_bit(ATM_DF_CLOSE,&vcc->dev->flags)) shutdown_atm_dev(vcc->dev); } diff --git a/net/atm/signaling.c b/net/atm/signaling.c index 46e22d50c..0240aa874 100644 --- a/net/atm/signaling.c +++ b/net/atm/signaling.c @@ -12,6 +12,7 @@ #include <linux/atmsap.h> #include <linux/atmsvc.h> #include <linux/atmdev.h> +#include <linux/bitops.h> #include "resources.h" #include "signaling.h" @@ -30,29 +31,33 @@ struct atm_vcc *sigd = NULL; -static wait_queue_head_t sigd_sleep; +static DECLARE_WAIT_QUEUE_HEAD(sigd_sleep); static void sigd_put_skb(struct sk_buff *skb) { #ifdef WAIT_FOR_DEMON static unsigned long silence = 0; -#endif + DECLARE_WAITQUEUE(wait,current); + add_wait_queue(&sigd_sleep,&wait); while (!sigd) { -#ifdef WAIT_FOR_DEMON + set_current_state(TASK_UNINTERRUPTIBLE); if (time_after(jiffies, silence) || silence == 0) { printk(KERN_INFO "atmsvc: waiting for signaling demon " "...\n"); silence = (jiffies+30*HZ)|1; } - sleep_on(&sigd_sleep); + schedule(); + } + remove_wait_queue(&sigd_sleep,&wait); #else + if (!sigd) { printk(KERN_WARNING "atmsvc: no signaling demon\n"); kfree_skb(skb); return; -#endif } +#endif atm_force_charge(sigd,skb->truesize); skb_queue_tail(&sigd->recvq,skb); wake_up(&sigd->sleep); @@ -63,7 +68,8 @@ static void modify_qos(struct atm_vcc *vcc,struct atmsvc_msg *msg) { struct sk_buff *skb; - if ((vcc->flags & ATM_VF_RELEASED) || !(vcc->flags & ATM_VF_READY)) + if (test_bit(ATM_VF_RELEASED,&vcc->flags) || + !test_bit(ATM_VF_READY,&vcc->flags)) return; msg->type = as_error; if (!vcc->dev->ops->change_qos) msg->reply = -EOPNOTSUPP; @@ -114,7 +120,8 @@ static int sigd_send(struct atm_vcc *vcc,struct sk_buff *skb) session_vcc->qos = msg->qos; break; case as_error: - vcc->flags &= ~(ATM_VF_REGIS | ATM_VF_READY); + clear_bit(ATM_VF_REGIS,&vcc->flags); + clear_bit(ATM_VF_READY,&vcc->flags); vcc->reply = msg->reply; break; case as_indicate: @@ -133,8 +140,8 @@ static int sigd_send(struct atm_vcc *vcc,struct sk_buff *skb) } return 0; case as_close: - vcc->flags |= ATM_VF_RELEASED; - vcc->flags &= ~ATM_VF_READY; + set_bit(ATM_VF_RELEASED,&vcc->flags); + clear_bit(ATM_VF_READY,&vcc->flags); vcc->reply = msg->reply; break; case as_modify: @@ -177,7 +184,7 @@ void sigd_enq(struct atm_vcc *vcc,enum atmsvc_msg_type type, if (!pvc) memset(&msg->pvc,0,sizeof(msg->pvc)); else msg->pvc = *pvc; sigd_put_skb(skb); - if (vcc) vcc->flags |= ATM_VF_REGIS; + if (vcc) set_bit(ATM_VF_REGIS,&vcc->flags); } @@ -185,8 +192,8 @@ static void purge_vccs(struct atm_vcc *vcc) { while (vcc) { if (vcc->family == PF_ATMSVC && - !(vcc->flags & ATM_VF_META)) { - vcc->flags |= ATM_VF_RELEASED; + !test_bit(ATM_VF_META,&vcc->flags)) { + set_bit(ATM_VF_RELEASED,&vcc->flags); vcc->reply = -EUNATCH; wake_up(&vcc->sleep); } @@ -223,7 +230,7 @@ static struct atm_dev sigd_dev = { 999, /* dummy device number */ NULL,NULL, /* pretend not to have any VCCs */ NULL,NULL, /* no data */ - 0, /* no flags */ + { 0 }, /* no flags */ NULL, /* no local address */ { 0 } /* no ESI, no statistics */ }; @@ -235,13 +242,8 @@ int sigd_attach(struct atm_vcc *vcc) DPRINTK("sigd_attach\n"); sigd = vcc; bind_vcc(vcc,&sigd_dev); - vcc->flags |= ATM_VF_READY | ATM_VF_META; + set_bit(ATM_VF_META,&vcc->flags); + set_bit(ATM_VF_READY,&vcc->flags); wake_up(&sigd_sleep); return 0; } - - -void signaling_init(void) -{ - init_waitqueue_head(&sigd_sleep); -} diff --git a/net/atm/signaling.h b/net/atm/signaling.h index dbb8c21e1..30d5d51d4 100644 --- a/net/atm/signaling.h +++ b/net/atm/signaling.h @@ -21,6 +21,5 @@ void sigd_enq(struct atm_vcc *vcc,enum atmsvc_msg_type type, struct atm_vcc *listen_vcc,const struct sockaddr_atmpvc *pvc, const struct sockaddr_atmsvc *svc); int sigd_attach(struct atm_vcc *vcc); -void signaling_init(void); #endif diff --git a/net/atm/svc.c b/net/atm/svc.c index 82ea22072..47b991557 100644 --- a/net/atm/svc.c +++ b/net/atm/svc.c @@ -17,6 +17,7 @@ #include <linux/atmsap.h> #include <linux/atmsvc.h> #include <linux/atmdev.h> +#include <linux/bitops.h> #include <net/sock.h> /* for sock_no_* */ #include <asm/uaccess.h> @@ -59,13 +60,18 @@ static int svc_shutdown(struct socket *sock,int how) static void svc_disconnect(struct atm_vcc *vcc) { + DECLARE_WAITQUEUE(wait,current); struct sk_buff *skb; DPRINTK("svc_disconnect %p\n",vcc); - if (vcc->flags & ATM_VF_REGIS) { + if (test_bit(ATM_VF_REGIS,&vcc->flags)) { sigd_enq(vcc,as_close,NULL,NULL,NULL); - while (!(vcc->flags & ATM_VF_RELEASED) && sigd) - sleep_on(&vcc->sleep); + add_wait_queue(&vcc->sleep,&wait); + while (!test_bit(ATM_VF_RELEASED,&vcc->flags) && sigd) { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule(); + } + remove_wait_queue(&vcc->sleep,&wait); } /* beware - socket is still in use by atmsigd until the last as_indicate has been answered */ @@ -75,8 +81,10 @@ static void svc_disconnect(struct atm_vcc *vcc) the reason */ dev_kfree_skb(skb); } - vcc->flags &= ~(ATM_VF_REGIS | ATM_VF_RELEASED | ATM_VF_CLOSE); - /* may retry later */ + clear_bit(ATM_VF_REGIS,&vcc->flags); + clear_bit(ATM_VF_RELEASED,&vcc->flags); + clear_bit(ATM_VF_CLOSE,&vcc->flags); + /* ... may retry later */ } @@ -87,7 +95,7 @@ static int svc_release(struct socket *sock) if (!sock->sk) return 0; vcc = ATM_SD(sock); DPRINTK("svc_release %p\n",vcc); - vcc->flags &= ~ATM_VF_READY; + clear_bit(ATM_VF_READY,&vcc->flags); atm_release_vcc_sk(sock->sk,0); svc_disconnect(vcc); /* VCC pointer is used as a reference, so we must not free it @@ -101,6 +109,7 @@ static int svc_release(struct socket *sock) static int svc_bind(struct socket *sock,struct sockaddr *sockaddr, int sockaddr_len) { + DECLARE_WAITQUEUE(wait,current); struct sockaddr_atmsvc *addr; struct atm_vcc *vcc; @@ -108,19 +117,25 @@ static int svc_bind(struct socket *sock,struct sockaddr *sockaddr, if (sock->state == SS_CONNECTED) return -EISCONN; if (sock->state != SS_UNCONNECTED) return -EINVAL; vcc = ATM_SD(sock); - if (vcc->flags & ATM_VF_SESSION) return -EINVAL; + if (test_bit(ATM_VF_SESSION,&vcc->flags)) return -EINVAL; addr = (struct sockaddr_atmsvc *) sockaddr; if (addr->sas_family != AF_ATMSVC) return -EAFNOSUPPORT; - vcc->flags &= ~ATM_VF_BOUND; /* failing rebind will kill old binding */ + clear_bit(ATM_VF_BOUND,&vcc->flags); + /* failing rebind will kill old binding */ /* @@@ check memory (de)allocation on rebind */ - if (!(vcc->flags & ATM_VF_HASQOS)) return -EBADFD; + if (!test_bit(ATM_VF_HASQOS,&vcc->flags)) return -EBADFD; vcc->local = *addr; vcc->reply = WAITING; sigd_enq(vcc,as_bind,NULL,NULL,&vcc->local); - while (vcc->reply == WAITING && sigd) sleep_on(&vcc->sleep); - vcc->flags &= ~ATM_VF_REGIS; /* doesn't count */ + add_wait_queue(&vcc->sleep,&wait); + while (vcc->reply == WAITING && sigd) { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule(); + } + remove_wait_queue(&vcc->sleep,&wait); + clear_bit(ATM_VF_REGIS,&vcc->flags); /* doesn't count */ if (!sigd) return -EUNATCH; - if (!vcc->reply) vcc->flags |= ATM_VF_BOUND; + if (!vcc->reply) set_bit(ATM_VF_BOUND,&vcc->flags); return vcc->reply; } @@ -128,6 +143,7 @@ static int svc_bind(struct socket *sock,struct sockaddr *sockaddr, static int svc_connect(struct socket *sock,struct sockaddr *sockaddr, int sockaddr_len,int flags) { + DECLARE_WAITQUEUE(wait,current); struct sockaddr_atmsvc *addr; struct atm_vcc *vcc = ATM_SD(sock); int error; @@ -141,11 +157,13 @@ static int svc_connect(struct socket *sock,struct sockaddr *sockaddr, if (vcc->reply) return vcc->reply; } else { + int error; + if (sock->state != SS_UNCONNECTED) return -EINVAL; - if (vcc->flags & ATM_VF_SESSION) return -EINVAL; + if (test_bit(ATM_VF_SESSION,&vcc->flags)) return -EINVAL; addr = (struct sockaddr_atmsvc *) sockaddr; if (addr->sas_family != AF_ATMSVC) return -EAFNOSUPPORT; - if (!(vcc->flags & ATM_VF_HASQOS)) return -EBADFD; + if (!test_bit(ATM_VF_HASQOS,&vcc->flags)) return -EBADFD; if (vcc->qos.txtp.traffic_class == ATM_ANYCLASS || vcc->qos.rxtp.traffic_class == ATM_ANYCLASS) return -EINVAL; @@ -158,34 +176,46 @@ static int svc_connect(struct socket *sock,struct sockaddr *sockaddr, sock->state = SS_CONNECTING; return -EINPROGRESS; } + add_wait_queue(&vcc->sleep,&wait); + error = 0; while (vcc->reply == WAITING && sigd) { - interruptible_sleep_on(&vcc->sleep); - if (signal_pending(current)) { - DPRINTK("*ABORT*\n"); - /* - * This is tricky: - * Kernel ---close--> Demon - * Kernel <--close--- Demon - * or - * Kernel ---close--> Demon - * Kernel <--error--- Demon - * or - * Kernel ---close--> Demon - * Kernel <--okay---- Demon - * Kernel <--close--- Demon - */ - sigd_enq(vcc,as_close,NULL,NULL,NULL); - while (vcc->reply == WAITING && sigd) - sleep_on(&vcc->sleep); - if (!vcc->reply) - while (!(vcc->flags & ATM_VF_RELEASED) - && sigd) sleep_on(&vcc->sleep); - vcc->flags &= ~(ATM_VF_REGIS | ATM_VF_RELEASED - | ATM_VF_CLOSE); - /* we're gone now but may connect later */ - return -EINTR; + set_current_state(TASK_INTERRUPTIBLE); + schedule(); + if (!signal_pending(current)) continue; + DPRINTK("*ABORT*\n"); + /* + * This is tricky: + * Kernel ---close--> Demon + * Kernel <--close--- Demon + * or + * Kernel ---close--> Demon + * Kernel <--error--- Demon + * or + * Kernel ---close--> Demon + * Kernel <--okay---- Demon + * Kernel <--close--- Demon + */ + sigd_enq(vcc,as_close,NULL,NULL,NULL); + while (vcc->reply == WAITING && sigd) { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule(); } + if (!vcc->reply) + while (!test_bit(ATM_VF_RELEASED,&vcc->flags) + && sigd) { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule(); + } + remove_wait_queue(&vcc->sleep,&wait); + clear_bit(ATM_VF_REGIS,&vcc->flags); + clear_bit(ATM_VF_RELEASED,&vcc->flags); + clear_bit(ATM_VF_CLOSE,&vcc->flags); + /* we're gone now but may connect later */ + error = -EINTR; + break; } + remove_wait_queue(&vcc->sleep,&wait); + if (error) return error; if (!sigd) return -EUNATCH; if (vcc->reply) return vcc->reply; } @@ -209,16 +239,22 @@ static int svc_connect(struct socket *sock,struct sockaddr *sockaddr, static int svc_listen(struct socket *sock,int backlog) { + DECLARE_WAITQUEUE(wait,current); struct atm_vcc *vcc = ATM_SD(sock); DPRINTK("svc_listen %p\n",vcc); /* let server handle listen on unbound sockets */ - if (vcc->flags & ATM_VF_SESSION) return -EINVAL; + if (test_bit(ATM_VF_SESSION,&vcc->flags)) return -EINVAL; vcc->reply = WAITING; sigd_enq(vcc,as_listen,NULL,NULL,&vcc->local); - while (vcc->reply == WAITING && sigd) sleep_on(&vcc->sleep); + add_wait_queue(&vcc->sleep,&wait); + while (vcc->reply == WAITING && sigd) { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule(); + } + remove_wait_queue(&vcc->sleep,&wait); if (!sigd) return -EUNATCH; - vcc->flags |= ATM_VF_LISTEN; + set_bit(ATM_VF_LISTEN,&vcc->flags); vcc->backlog_quota = backlog > 0 ? backlog : ATM_BACKLOG_DEFAULT; return vcc->reply; } @@ -240,18 +276,32 @@ static int svc_accept(struct socket *sock,struct socket *newsock,int flags) DPRINTK("svc_accept %p -> %p\n",old_vcc,new_vcc); while (1) { + DECLARE_WAITQUEUE(wait,current); + + add_wait_queue(&old_vcc->sleep,&wait); while (!(skb = skb_dequeue(&old_vcc->listenq)) && sigd) { - if (old_vcc->flags & ATM_VF_RELEASED) break; - if (old_vcc->flags & ATM_VF_CLOSE) - return old_vcc->reply; - if (flags & O_NONBLOCK) return -EAGAIN; - interruptible_sleep_on(&old_vcc->sleep); - if (signal_pending(current)) return -ERESTARTSYS; + if (test_bit(ATM_VF_RELEASED,&old_vcc->flags)) break; + if (test_bit(ATM_VF_CLOSE,&old_vcc->flags)) { + error = old_vcc->reply; + break; + } + if (flags & O_NONBLOCK) { + error = -EAGAIN; + break; + } + set_current_state(TASK_INTERRUPTIBLE); + schedule(); + if (signal_pending(current)) { + error = -ERESTARTSYS; + break; + } } + remove_wait_queue(&old_vcc->sleep,&wait); + if (error) return error; if (!skb) return -EUNATCH; msg = (struct atmsvc_msg *) skb->data; new_vcc->qos = msg->qos; - new_vcc->flags |= ATM_VF_HASQOS; + set_bit(ATM_VF_HASQOS,&new_vcc->flags); new_vcc->remote = msg->svc; new_vcc->local = msg->local; new_vcc->sap = msg->sap; @@ -267,8 +317,12 @@ static int svc_accept(struct socket *sock,struct socket *newsock,int flags) /* wait should be short, so we ignore the non-blocking flag */ new_vcc->reply = WAITING; sigd_enq(new_vcc,as_accept,old_vcc,NULL,NULL); - while (new_vcc->reply == WAITING && sigd) - sleep_on(&new_vcc->sleep); + add_wait_queue(&new_vcc->sleep,&wait); + while (new_vcc->reply == WAITING && sigd) { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule(); + } + remove_wait_queue(&new_vcc->sleep,&wait); if (!sigd) return -EUNATCH; if (!new_vcc->reply) break; if (new_vcc->reply != -ERESTARTSYS) return new_vcc->reply; @@ -293,6 +347,7 @@ static int svc_getname(struct socket *sock,struct sockaddr *sockaddr, int svc_change_qos(struct atm_vcc *vcc,struct atm_qos *qos) { + DECLARE_WAITQUEUE(wait,current); struct atm_qos save_qos; vcc->reply = WAITING; @@ -300,8 +355,13 @@ int svc_change_qos(struct atm_vcc *vcc,struct atm_qos *qos) vcc->qos = *qos; sigd_enq(vcc,as_modify,NULL,NULL,&vcc->local); vcc->qos = save_qos; - while (vcc->reply == WAITING && !(vcc->flags & ATM_VF_RELEASED) && - sigd) sleep_on(&vcc->sleep); + add_wait_queue(&vcc->sleep,&wait); + while (vcc->reply == WAITING && !test_bit(ATM_VF_RELEASED,&vcc->flags) + && sigd) { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule(); + } + remove_wait_queue(&vcc->sleep,&wait); if (!sigd) return -EUNATCH; return vcc->reply; } @@ -317,7 +377,7 @@ static int svc_setsockopt(struct socket *sock,int level,int optname, return atm_setsockopt(sock,level,optname,optval,optlen); vcc = ATM_SD(sock); if (copy_from_user(&vcc->sap,optval,optlen)) return -EFAULT; - vcc->flags |= ATM_VF_HASSAP; + set_bit(ATM_VF_HASSAP,&vcc->flags); return 0; } @@ -393,6 +453,4 @@ void __init atmsvc_proto_init(struct net_proto *pro) printk(KERN_ERR "ATMSVC: can't register"); return; } - signaling_init(); - init_addr(); } diff --git a/net/bridge/br.c b/net/bridge/br.c index ec59ff622..89ee1e0d5 100644 --- a/net/bridge/br.c +++ b/net/bridge/br.c @@ -5,7 +5,7 @@ * Authors: * Lennert Buytenhek <buytenh@gnu.org> * - * $Id: br.c,v 1.39 2000/02/18 16:47:11 davem Exp $ + * $Id: br.c,v 1.40 2000/03/21 21:08:47 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -13,6 +13,7 @@ * 2 of the License, or (at your option) any later version. */ +#include <linux/config.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/miscdevice.h> @@ -23,6 +24,10 @@ #include <asm/uaccess.h> #include "br_private.h" +#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) +#include "../atm/lec.h" +#endif + void br_dec_use_count() { MOD_DEC_USE_COUNT; @@ -39,6 +44,12 @@ static int __init br_init(void) br_handle_frame_hook = br_handle_frame; br_ioctl_hook = br_ioctl_deviceless_stub; +#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) + write_lock(&lane_bridge_hook_lock); + br_fdb_get_hook = br_fdb_get; + br_fdb_put_hook = br_fdb_put; + write_unlock(&lane_bridge_hook_lock); +#endif register_netdevice_notifier(&br_device_notifier); return 0; @@ -59,6 +70,12 @@ static void __exit br_deinit(void) unregister_netdevice_notifier(&br_device_notifier); br_call_ioctl_atomic(__br_clear_ioctl_hook); net_call_rx_atomic(__br_clear_frame_hook); +#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) + write_lock(&lane_bridge_hook_lock); + br_fdb_get_hook = NULL; + br_fdb_put_hook = NULL; + write_unlock(&lane_bridge_hook_lock); +#endif } EXPORT_NO_SYMBOLS; diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c index e6fa6b379..fc549d76a 100644 --- a/net/bridge/br_input.c +++ b/net/bridge/br_input.c @@ -5,7 +5,7 @@ * Authors: * Lennert Buytenhek <buytenh@gnu.org> * - * $Id: br_input.c,v 1.3 2000/02/24 19:48:06 davem Exp $ + * $Id: br_input.c,v 1.4 2000/03/21 21:08:47 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -19,7 +19,7 @@ #include <linux/if_bridge.h> #include "br_private.h" -unsigned char bridge_ula[5] = { 0x01, 0x80, 0xc2, 0x00, 0x00 }; +unsigned char bridge_ula[6] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 }; static void br_pass_frame_up(struct net_bridge *br, struct sk_buff *skb) { @@ -53,6 +53,8 @@ static void __br_handle_frame(struct sk_buff *skb) p->state == BR_STATE_DISABLED) goto freeandout; + skb_push(skb, skb->data - skb->mac.raw); + if (br->dev.flags & IFF_PROMISC) { struct sk_buff *skb2; @@ -81,8 +83,6 @@ static void __br_handle_frame(struct sk_buff *skb) if (!memcmp(dest, bridge_ula, 5) && !(dest[5] & 0xF0)) goto handle_special_frame; - skb_push(skb, skb->data - skb->mac.raw); - if (p->state == BR_STATE_LEARNING || p->state == BR_STATE_FORWARDING) br_fdb_insert(br, p, skb->mac.ethernet->h_source, 0); diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 084e81b4b..76c14be9c 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -4,7 +4,7 @@ * Authors: * Lennert Buytenhek <buytenh@gnu.org> * - * $Id: br_private.h,v 1.1 2000/02/18 16:47:12 davem Exp $ + * $Id: br_private.h,v 1.2 2000/03/21 21:08:47 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -114,7 +114,7 @@ struct net_bridge }; struct notifier_block br_device_notifier; -unsigned char bridge_ula[5]; +unsigned char bridge_ula[6]; /* br.c */ void br_dec_use_count(void); diff --git a/net/core/dev.c b/net/core/dev.c index b09b3b9a4..f14753618 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -651,7 +651,7 @@ int dev_queue_xmit(struct sk_buff *skb) qdisc_run(dev); spin_unlock_bh(&dev->queue_lock); - return ret; + return ret == NET_XMIT_BYPASS ? NET_XMIT_SUCCESS : ret; } /* The device has no queue. Common case for software devices: diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index 2823c2c7e..c3f3b29f7 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -1,7 +1,7 @@ /* * Linux NET3: IP/IP protocol decoder. * - * Version: $Id: ipip.c,v 1.31 2000/03/17 14:41:51 davem Exp $ + * Version: $Id: ipip.c,v 1.32 2000/03/21 06:13:54 davem Exp $ * * Authors: * Sam Lantinga (slouken@cs.ucdavis.edu) 02/01/95 diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index 41a61e010..c507acc31 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile @@ -21,6 +21,8 @@ OX_OBJS += ip_conntrack_standalone.o O_OBJS += $(IP_NF_CONNTRACK_OBJ) else ifeq ($(CONFIG_IP_NF_CONNTRACK),m) + MI_OBJS += $(IP_NF_CONNTRACK_OBJ) + MIX_OBJS += ip_conntrack_standalone.o M_OBJS += ip_conntrack.o endif endif @@ -37,7 +39,7 @@ ifeq ($(CONFIG_IP_NF_FTP),y) OX_OBJS += ip_conntrack_ftp.o else ifeq ($(CONFIG_IP_NF_FTP),m) - M_OBJS += ip_conntrack_ftp.o + MX_OBJS += ip_conntrack_ftp.o endif endif @@ -129,6 +131,8 @@ O_OBJS += ip_nat_rule.o $(IP_NF_NAT_OBJ) endif else ifeq ($(CONFIG_IP_NF_NAT),m) + MI_OBJS += ip_nat_rule.o $(IP_NF_NAT_OBJ) + MIX_OBJS += ip_nat_standalone.o M_OBJS += iptable_nat.o ifeq ($(CONFIG_IP_NF_FTP),m) M_OBJS += ip_nat_ftp.o diff --git a/net/ipv4/netfilter/ip_conntrack_ftp.c b/net/ipv4/netfilter/ip_conntrack_ftp.c index 9137d13ea..23ccf74cf 100644 --- a/net/ipv4/netfilter/ip_conntrack_ftp.c +++ b/net/ipv4/netfilter/ip_conntrack_ftp.c @@ -1,7 +1,4 @@ /* FTP extension for IP connection tracking. */ -#ifdef MODULE -#define EXPORT_SYMTAB -#endif #include <linux/module.h> #include <linux/netfilter.h> #include <linux/ip.h> diff --git a/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilter/ip_conntrack_standalone.c index ce79c3263..a69be542d 100644 --- a/net/ipv4/netfilter/ip_conntrack_standalone.c +++ b/net/ipv4/netfilter/ip_conntrack_standalone.c @@ -7,9 +7,6 @@ /* (c) 1999 Paul `Rusty' Russell. Licenced under the GNU General Public Licence. */ -#ifdef MODULE -#define EXPORT_SYMTAB -#endif #include <linux/types.h> #include <linux/ip.h> #include <linux/netfilter.h> diff --git a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c index bf278d6f9..603111063 100644 --- a/net/ipv4/netfilter/ip_nat_standalone.c +++ b/net/ipv4/netfilter/ip_nat_standalone.c @@ -7,9 +7,6 @@ /* (c) 1999 Paul `Rusty' Russell. Licenced under the GNU General Public Licence. */ -#ifdef MODULE -#define EXPORT_SYMTAB -#endif #include <linux/types.h> #include <linux/ip.h> #include <linux/netfilter.h> diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c index d5ca01aa6..532538321 100644 --- a/net/ipv4/netfilter/ip_queue.c +++ b/net/ipv4/netfilter/ip_queue.c @@ -491,7 +491,7 @@ netlink_send_peer(ipq_queue_element_t *e) skb = netlink_build_message(e, &status); if (skb == NULL) return status; - return netlink_unicast(nfnl, skb, nlq->peer.pid, 0); + return netlink_unicast(nfnl, skb, nlq->peer.pid, MSG_DONTWAIT); } static struct sk_buff * diff --git a/net/ipv4/route.c b/net/ipv4/route.c index c683f2f23..afab828fb 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -5,7 +5,7 @@ * * ROUTE - implementation of the IP router. * - * Version: $Id: route.c,v 1.82 2000/03/17 14:41:52 davem Exp $ + * Version: $Id: route.c,v 1.83 2000/03/23 05:34:13 davem Exp $ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> @@ -205,9 +205,6 @@ static __inline__ unsigned rt_hash_code(u32 daddr, u32 saddr, u8 tos) return (hash^(hash>>8)) & rt_hash_mask; } -#ifndef CONFIG_PROC_FS -static int rt_cache_get_info(char *buffer, char **start, off_t offset, int length) { return 0; } -#else static int rt_cache_get_info(char *buffer, char **start, off_t offset, int length) { int len=0; @@ -267,7 +264,6 @@ done: len = length; return len; } -#endif static __inline__ void rt_free(struct rtable *rt) { @@ -2204,7 +2200,6 @@ ctl_table ipv4_route_table[] = { #ifdef CONFIG_NET_CLS_ROUTE struct ip_rt_acct *ip_rt_acct; -#ifdef CONFIG_PROC_FS static int ip_rt_acct_read(char *buffer, char **start, off_t offset, int length, int *eof, void *data) { @@ -2243,7 +2238,6 @@ static int ip_rt_acct_read(char *buffer, char **start, off_t offset, return 0; } #endif -#endif void __init ip_rt_init(void) { diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 7d3e49bed..471eb9e70 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp.c,v 1.164 2000/03/08 19:36:40 davem Exp $ + * Version: $Id: tcp.c,v 1.165 2000/03/23 05:30:32 davem Exp $ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> @@ -1337,20 +1337,21 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg, break; } - if (sk->done) { - copied = -ENOTCONN; + if (sk->shutdown & RCV_SHUTDOWN) { + if (!(flags&MSG_PEEK)) + sk->done = 1; break; } if (sk->state == TCP_CLOSE) { - if (!(flags&MSG_PEEK)) + if (sk->done) { + copied = -ENOTCONN; + break; + } else if (!(flags&MSG_PEEK)) sk->done = 1; break; } - if (sk->shutdown & RCV_SHUTDOWN) - break; - if (!timeo) { copied = -EAGAIN; break; diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index d431c682c..575ec3036 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_input.c,v 1.189 2000/02/27 19:52:55 davem Exp $ + * Version: $Id: tcp_input.c,v 1.190 2000/03/21 19:34:23 davem Exp $ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> @@ -1944,10 +1944,8 @@ queue_and_out: if (eaten) { kfree_skb(skb); - } else if (!sk->dead) { - wake_up_interruptible(sk->sleep); - sock_wake_async(sk->socket,1, POLL_IN); - } + } else + sk->data_ready(sk, 0); return; } @@ -2531,8 +2529,7 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb, /* FIN bit check is not done since if FIN is set in * this frame, the pred_flags won't match up. -DaveM */ - wake_up_interruptible(sk->sleep); - sock_wake_async(sk->socket,1, POLL_IN); + sk->data_ready(sk, 0); } tcp_event_data_recv(tp, skb); diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 1edee9f51..456f12968 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_ipv4.c,v 1.202 2000/03/17 14:41:53 davem Exp $ + * Version: $Id: tcp_ipv4.c,v 1.203 2000/03/22 17:55:03 davem Exp $ * * IPv4 specific functions * @@ -2015,7 +2015,7 @@ static void get_tcp_sock(struct sock *sp, char *tmpbuf, int i) timer_expires = jiffies; sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X" - " %02X %08X:%08X %02X:%08lX %08X %5d %8d %ld %d %p %u %u %u %u", + " %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %u %u %u %u", i, src, srcp, dest, destp, sp->state, tp->write_seq-tp->snd_una, tp->rcv_nxt-tp->copied_seq, timer_active, timer_expires-jiffies, diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index c52797d70..8b8db60d8 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -6,7 +6,7 @@ * Pedro Roque <roque@di.fc.ul.pt> * Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> * - * $Id: sit.c,v 1.36 2000/03/17 14:42:08 davem Exp $ + * $Id: sit.c,v 1.37 2000/03/21 06:14:00 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/net/irda/ircomm/ircomm_param.c b/net/irda/ircomm/ircomm_param.c index 3c9ff35da..1cef4d5d8 100644 --- a/net/irda/ircomm/ircomm_param.c +++ b/net/irda/ircomm/ircomm_param.c @@ -6,10 +6,10 @@ * Status: Experimental. * Author: Dag Brattli <dagb@cs.uit.no> * Created at: Mon Jun 7 10:25:11 1999 - * Modified at: Tue Dec 14 15:26:30 1999 + * Modified at: Sun Jan 30 14:32:03 2000 * Modified by: Dag Brattli <dagb@cs.uit.no> * - * Copyright (c) 1999 Dag Brattli, All Rights Reserved. + * Copyright (c) 1999-2000 Dag Brattli, All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -40,19 +40,27 @@ #include <net/irda/ircomm_param.h> -static int ircomm_param_service_type(void *instance, param_t *param, int get); -static int ircomm_param_port_type(void *instance, param_t *param, int get); -static int ircomm_param_port_name(void *instance, param_t *param, int get); -static int ircomm_param_service_type(void *instance, param_t *param, int get); -static int ircomm_param_data_rate(void *instance, param_t *param, int get); -static int ircomm_param_data_format(void *instance, param_t *param, int get); -static int ircomm_param_flow_control(void *instance, param_t *param, int get); -static int ircomm_param_xon_xoff(void *instance, param_t *param, int get); -static int ircomm_param_enq_ack(void *instance, param_t *param, int get); -static int ircomm_param_line_status(void *instance, param_t *param, int get); -static int ircomm_param_dte(void *instance, param_t *param, int get); -static int ircomm_param_dce(void *instance, param_t *param, int get); -static int ircomm_param_poll(void *instance, param_t *param, int get); +static int ircomm_param_service_type(void *instance, irda_param_t *param, + int get); +static int ircomm_param_port_type(void *instance, irda_param_t *param, + int get); +static int ircomm_param_port_name(void *instance, irda_param_t *param, + int get); +static int ircomm_param_service_type(void *instance, irda_param_t *param, + int get); +static int ircomm_param_data_rate(void *instance, irda_param_t *param, + int get); +static int ircomm_param_data_format(void *instance, irda_param_t *param, + int get); +static int ircomm_param_flow_control(void *instance, irda_param_t *param, + int get); +static int ircomm_param_xon_xoff(void *instance, irda_param_t *param, int get); +static int ircomm_param_enq_ack(void *instance, irda_param_t *param, int get); +static int ircomm_param_line_status(void *instance, irda_param_t *param, + int get); +static int ircomm_param_dte(void *instance, irda_param_t *param, int get); +static int ircomm_param_dce(void *instance, irda_param_t *param, int get); +static int ircomm_param_poll(void *instance, irda_param_t *param, int get); static pi_minor_info_t pi_minor_call_table_common[] = { { ircomm_param_service_type, PV_INT_8_BITS }, @@ -170,7 +178,8 @@ int ircomm_param_request(struct ircomm_tty_cb *self, __u8 pi, int flush) * query and then the remote device sends its initial paramters * */ -static int ircomm_param_service_type(void *instance, param_t *param, int get) +static int ircomm_param_service_type(void *instance, irda_param_t *param, + int get) { struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; __u8 service_type = param->pv.b; /* We know it's a one byte integer */ @@ -229,7 +238,7 @@ static int ircomm_param_service_type(void *instance, param_t *param, int get) * Since we only advertise serial service, this parameter should only * be equal to IRCOMM_SERIAL. */ -static int ircomm_param_port_type(void *instance, param_t *param, int get) +static int ircomm_param_port_type(void *instance, irda_param_t *param, int get) { struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; @@ -253,7 +262,7 @@ static int ircomm_param_port_type(void *instance, param_t *param, int get) * Exchange port name * */ -static int ircomm_param_port_name(void *instance, param_t *param, int get) +static int ircomm_param_port_name(void *instance, irda_param_t *param, int get) { struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; @@ -276,7 +285,7 @@ static int ircomm_param_port_name(void *instance, param_t *param, int get) * Exchange data rate to be used in this settings * */ -static int ircomm_param_data_rate(void *instance, param_t *param, int get) +static int ircomm_param_data_rate(void *instance, irda_param_t *param, int get) { struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; @@ -299,7 +308,8 @@ static int ircomm_param_data_rate(void *instance, param_t *param, int get) * Exchange data format to be used in this settings * */ -static int ircomm_param_data_format(void *instance, param_t *param, int get) +static int ircomm_param_data_format(void *instance, irda_param_t *param, + int get) { struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; @@ -320,7 +330,8 @@ static int ircomm_param_data_format(void *instance, param_t *param, int get) * Exchange flow control settings to be used in this settings * */ -static int ircomm_param_flow_control(void *instance, param_t *param, int get) +static int ircomm_param_flow_control(void *instance, irda_param_t *param, + int get) { struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; @@ -343,7 +354,7 @@ static int ircomm_param_flow_control(void *instance, param_t *param, int get) * Exchange XON/XOFF characters * */ -static int ircomm_param_xon_xoff(void *instance, param_t *param, int get) +static int ircomm_param_xon_xoff(void *instance, irda_param_t *param, int get) { struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; @@ -370,7 +381,7 @@ static int ircomm_param_xon_xoff(void *instance, param_t *param, int get) * Exchange ENQ/ACK characters * */ -static int ircomm_param_enq_ack(void *instance, param_t *param, int get) +static int ircomm_param_enq_ack(void *instance, irda_param_t *param, int get) { struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; @@ -397,7 +408,8 @@ static int ircomm_param_enq_ack(void *instance, param_t *param, int get) * * */ -static int ircomm_param_line_status(void *instance, param_t *param, int get) +static int ircomm_param_line_status(void *instance, irda_param_t *param, + int get) { IRDA_DEBUG(2, __FUNCTION__ "(), not impl.\n"); @@ -410,7 +422,7 @@ static int ircomm_param_line_status(void *instance, param_t *param, int get) * If we get here, there must be some sort of null-modem connection, and * we are probably working in server mode as well. */ -static int ircomm_param_dte(void *instance, param_t *param, int get) +static int ircomm_param_dte(void *instance, irda_param_t *param, int get) { struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; __u8 dte; @@ -453,7 +465,7 @@ static int ircomm_param_dte(void *instance, param_t *param, int get) * * */ -static int ircomm_param_dce(void *instance, param_t *param, int get) +static int ircomm_param_dce(void *instance, irda_param_t *param, int get) { struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; __u8 dce; @@ -485,7 +497,7 @@ static int ircomm_param_dce(void *instance, param_t *param, int get) * Called when the peer device is polling for the line settings * */ -static int ircomm_param_poll(void *instance, param_t *param, int get) +static int ircomm_param_poll(void *instance, irda_param_t *param, int get) { struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; diff --git a/net/irda/irda_device.c b/net/irda/irda_device.c index 9968e0e95..ca2903316 100644 --- a/net/irda/irda_device.c +++ b/net/irda/irda_device.c @@ -254,7 +254,7 @@ int irda_device_is_receiving(struct net_device *dev) return req.ifr_receiving; } -void irda_task_next_state(struct irda_task *task, TASK_STATE state) +void irda_task_next_state(struct irda_task *task, IRDA_TASK_STATE state) { IRDA_DEBUG(2, __FUNCTION__ "(), state = %s\n", task_state[state]); @@ -354,8 +354,9 @@ int irda_task_kick(struct irda_task *task) * called from interrupt context, so it's not possible to use * schedule_timeout() */ -struct irda_task *irda_task_execute(void *instance, TASK_CALLBACK function, - TASK_CALLBACK finished, +struct irda_task *irda_task_execute(void *instance, + IRDA_TASK_CALLBACK function, + IRDA_TASK_CALLBACK finished, struct irda_task *parent, void *param) { struct irda_task *task; diff --git a/net/irda/irlan/irlan_eth.c b/net/irda/irlan/irlan_eth.c index 5ee81ec03..32b09e25d 100644 --- a/net/irda/irlan/irlan_eth.c +++ b/net/irda/irlan/irlan_eth.c @@ -6,13 +6,13 @@ * Status: Experimental. * Author: Dag Brattli <dagb@cs.uit.no> * Created at: Thu Oct 15 08:37:58 1998 - * Modified at: Thu Nov 4 14:50:52 1999 + * Modified at: Tue Mar 21 09:06:41 2000 * Modified by: Dag Brattli <dagb@cs.uit.no> * Sources: skeleton.c by Donald Becker <becker@CESDIS.gsfc.nasa.gov> * slip.c by Laurence Culhane, <loz@holmes.demon.co.uk> * Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org> * - * Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved. + * Copyright (c) 1998-2000 Dag Brattli, All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -25,6 +25,7 @@ * ********************************************************************/ +#include <linux/config.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/inetdevice.h> @@ -331,6 +332,7 @@ void irlan_eth_send_gratuitous_arp(struct net_device *dev) * is useful if we have changed access points on the same * subnet. */ +#ifdef CONFIG_INET IRDA_DEBUG(4, "IrLAN: Sending gratuitous ARP\n"); in_dev = in_dev_get(dev); if (in_dev == NULL) @@ -345,6 +347,7 @@ void irlan_eth_send_gratuitous_arp(struct net_device *dev) NULL, dev->dev_addr, NULL); read_unlock(&in_dev->lock); in_dev_put(in_dev); +#endif /* CONFIG_INET */ } /* diff --git a/net/irda/irttp.c b/net/irda/irttp.c index 46c2ae85e..e9d120efb 100644 --- a/net/irda/irttp.c +++ b/net/irda/irttp.c @@ -60,7 +60,8 @@ static void irttp_flush_queues(struct tsap_cb *self); static void irttp_fragment_skb(struct tsap_cb *self, struct sk_buff *skb); static void irttp_start_todo_timer(struct tsap_cb *self, int timeout); static struct sk_buff *irttp_reassemble_skb(struct tsap_cb *self); -static int irttp_param_max_sdu_size(void *instance, param_t *param, int get); +static int irttp_param_max_sdu_size(void *instance, irda_param_t *param, + int get); /* Information for parsing parameters in IrTTP */ static pi_minor_info_t pi_minor_call_table[] = { @@ -1405,7 +1406,8 @@ static void irttp_fragment_skb(struct tsap_cb *self, struct sk_buff *skb) * will be called both when this parameter needs to be inserted into, and * extracted from the connect frames */ -static int irttp_param_max_sdu_size(void *instance, param_t *param, int get) +static int irttp_param_max_sdu_size(void *instance, irda_param_t *param, + int get) { struct tsap_cb *self; diff --git a/net/irda/parameters.c b/net/irda/parameters.c index 263c2e2a4..b43bbd70e 100644 --- a/net/irda/parameters.c +++ b/net/irda/parameters.c @@ -6,10 +6,10 @@ * Status: Experimental. * Author: Dag Brattli <dagb@cs.uit.no> * Created at: Mon Jun 7 10:25:11 1999 - * Modified at: Tue Dec 14 16:03:57 1999 + * Modified at: Sun Jan 30 14:08:39 2000 * Modified by: Dag Brattli <dagb@cs.uit.no> * - * Copyright (c) 1999 Dag Brattli, All Rights Reserved. + * Copyright (c) 1999-2000 Dag Brattli, All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -78,7 +78,7 @@ static PV_HANDLER pv_insert_table[] = { static int irda_insert_no_value(void *self, __u8 *buf, int len, __u8 pi, PV_TYPE type, PI_HANDLER func) { - param_t p; + irda_param_t p; int ret; p.pi = pi; @@ -105,7 +105,7 @@ static int irda_insert_no_value(void *self, __u8 *buf, int len, __u8 pi, static int irda_extract_no_value(void *self, __u8 *buf, int len, __u8 pi, PV_TYPE type, PI_HANDLER func) { - param_t p; + irda_param_t p; int ret; /* Extract values anyway, since handler may need them */ @@ -129,7 +129,7 @@ static int irda_extract_no_value(void *self, __u8 *buf, int len, __u8 pi, static int irda_insert_integer(void *self, __u8 *buf, int len, __u8 pi, PV_TYPE type, PI_HANDLER func) { - param_t p; + irda_param_t p; int n = 0; int err; @@ -202,7 +202,7 @@ static int irda_insert_integer(void *self, __u8 *buf, int len, __u8 pi, static int irda_extract_integer(void *self, __u8 *buf, int len, __u8 pi, PV_TYPE type, PI_HANDLER func) { - param_t p; + irda_param_t p; int n = 0; int err; @@ -273,7 +273,7 @@ static int irda_extract_string(void *self, __u8 *buf, int len, __u8 pi, PV_TYPE type, PI_HANDLER func) { char str[33]; - param_t p; + irda_param_t p; int err; IRDA_DEBUG(2, __FUNCTION__ "()\n"); @@ -319,7 +319,7 @@ static int irda_extract_string(void *self, __u8 *buf, int len, __u8 pi, static int irda_extract_octseq(void *self, __u8 *buf, int len, __u8 pi, PV_TYPE type, PI_HANDLER func) { - param_t p; + irda_param_t p; p.pi = pi; /* In case handler needs to know */ p.pl = buf[1]; /* Extract lenght of value */ @@ -346,10 +346,10 @@ static int irda_extract_octseq(void *self, __u8 *buf, int len, __u8 pi, */ int irda_param_pack(__u8 *buf, char *fmt, ...) { + irda_pv_t arg; va_list args; char *p; int n = 0; - pv_t arg; va_start(args, fmt); @@ -392,10 +392,10 @@ int irda_param_pack(__u8 *buf, char *fmt, ...) */ int irda_param_unpack(__u8 *buf, char *fmt, ...) { + irda_pv_t arg; va_list args; char *p; int n = 0; - pv_t arg; va_start(args, fmt); diff --git a/net/irda/qos.c b/net/irda/qos.c index 2c2c39b85..10a7765cb 100644 --- a/net/irda/qos.c +++ b/net/irda/qos.c @@ -6,10 +6,10 @@ * Status: Stable * Author: Dag Brattli <dagb@cs.uit.no> * Created at: Tue Sep 9 00:00:26 1997 - * Modified at: Sun Dec 12 13:47:09 1999 + * Modified at: Sun Jan 30 14:29:16 2000 * Modified by: Dag Brattli <dagb@cs.uit.no> * - * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, + * Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>, * All Rights Reserved. * * This program is free software; you can redistribute it and/or @@ -43,13 +43,18 @@ #define CI_BZIP2 27 /* Random pick */ #endif -static int irlap_param_baud_rate(void *instance, param_t *param, int get); -static int irlap_param_link_disconnect(void *instance, param_t *parm, int get); -static int irlap_param_max_turn_time(void *instance, param_t *param, int get); -static int irlap_param_data_size(void *instance, param_t *param, int get); -static int irlap_param_window_size(void *instance, param_t *param, int get); -static int irlap_param_additional_bofs(void *instance, param_t *parm, int get); -static int irlap_param_min_turn_time(void *instance, param_t *param, int get); +static int irlap_param_baud_rate(void *instance, irda_param_t *param, int get); +static int irlap_param_link_disconnect(void *instance, irda_param_t *parm, + int get); +static int irlap_param_max_turn_time(void *instance, irda_param_t *param, + int get); +static int irlap_param_data_size(void *instance, irda_param_t *param, int get); +static int irlap_param_window_size(void *instance, irda_param_t *param, + int get); +static int irlap_param_additional_bofs(void *instance, irda_param_t *parm, + int get); +static int irlap_param_min_turn_time(void *instance, irda_param_t *param, + int get); __u32 min_turn_times[] = { 10000, 5000, 1000, 500, 100, 50, 10, 0 }; /* us */ __u32 baud_rates[] = { 2400, 9600, 19200, 38400, 57600, 115200, 576000, @@ -345,7 +350,7 @@ int irlap_insert_qos_negotiation_params(struct irlap_cb *self, * Negotiate data-rate * */ -static int irlap_param_baud_rate(void *instance, param_t *param, int get) +static int irlap_param_baud_rate(void *instance, irda_param_t *param, int get) { __u16 final; @@ -380,7 +385,8 @@ static int irlap_param_baud_rate(void *instance, param_t *param, int get) * Negotiate link disconnect/threshold time. * */ -static int irlap_param_link_disconnect(void *instance, param_t *param, int get) +static int irlap_param_link_disconnect(void *instance, irda_param_t *param, + int get) { __u16 final; @@ -413,7 +419,8 @@ static int irlap_param_link_disconnect(void *instance, param_t *param, int get) * will be negotiated independently for each station * */ -static int irlap_param_max_turn_time(void *instance, param_t *param, int get) +static int irlap_param_max_turn_time(void *instance, irda_param_t *param, + int get) { struct irlap_cb *self = (struct irlap_cb *) instance; @@ -435,7 +442,7 @@ static int irlap_param_max_turn_time(void *instance, param_t *param, int get) * will be negotiated independently for each station * */ -static int irlap_param_data_size(void *instance, param_t *param, int get) +static int irlap_param_data_size(void *instance, irda_param_t *param, int get) { struct irlap_cb *self = (struct irlap_cb *) instance; @@ -457,7 +464,8 @@ static int irlap_param_data_size(void *instance, param_t *param, int get) * will be negotiated independently for each station * */ -static int irlap_param_window_size(void *instance, param_t *param, int get) +static int irlap_param_window_size(void *instance, irda_param_t *param, + int get) { struct irlap_cb *self = (struct irlap_cb *) instance; @@ -478,7 +486,7 @@ static int irlap_param_window_size(void *instance, param_t *param, int get) * Negotiate additional BOF characters. This is a type 1 parameter and * will be negotiated independently for each station. */ -static int irlap_param_additional_bofs(void *instance, param_t *param, int get) +static int irlap_param_additional_bofs(void *instance, irda_param_t *param, int get) { struct irlap_cb *self = (struct irlap_cb *) instance; @@ -499,7 +507,8 @@ static int irlap_param_additional_bofs(void *instance, param_t *param, int get) * Negotiate the minimum turn around time. This is a type 1 parameter and * will be negotiated independently for each station */ -static int irlap_param_min_turn_time(void *instance, param_t *param, int get) +static int irlap_param_min_turn_time(void *instance, irda_param_t *param, + int get) { struct irlap_cb *self = (struct irlap_cb *) instance; diff --git a/net/khttpd/main.c b/net/khttpd/main.c index 418037907..a9568ef0d 100644 --- a/net/khttpd/main.c +++ b/net/khttpd/main.c @@ -198,7 +198,6 @@ static int ManagementDaemon(void *unused) DECLARE_WAIT_QUEUE_HEAD(WQ); - MOD_INC_USE_COUNT; sprintf(current->comm,"khttpd manager"); lock_kernel(); /* This seems to be required for exit_mm */ @@ -347,6 +346,8 @@ static int ManagementDaemon(void *unused) int __init khttpd_init(void) { int I; + + MOD_INC_USE_COUNT; I=0; while (I<CONFIG_KHTTPD_NUMCPU) diff --git a/net/khttpd/security.c b/net/khttpd/security.c index bd578941d..7e0780a26 100644 --- a/net/khttpd/security.c +++ b/net/khttpd/security.c @@ -113,10 +113,11 @@ struct file *OpenFileForSecurity(char *Filename) #endif /* Rule no. 3 -- Does the file exist ? */ - + lock_kernel(); filp = filp_open(Filename, 0, O_RDONLY, NULL); + unlock_kernel(); if ((IS_ERR(filp))||(filp==NULL)||(filp->f_dentry==NULL)) { diff --git a/net/sched/sch_atm.c b/net/sched/sch_atm.c index a3b25f2a7..021d7d658 100644 --- a/net/sched/sch_atm.c +++ b/net/sched/sch_atm.c @@ -276,7 +276,7 @@ static int atm_tc_change(struct Qdisc *sch, u32 classid, u32 parent, goto err_out; } /* @@@ should check if the socket is really operational or we'll crash - on vcc->dev->ops->send */ + on vcc->send */ if (classid) { if (TC_H_MAJ(classid ^ sch->handle)) { DPRINTK("atm_tc_change: classid mismatch\n"); @@ -449,8 +449,21 @@ static int atm_tc_enqueue(struct sk_buff *skb,struct Qdisc *sch) sch->stats.packets++; flow->stats.bytes += skb->len; flow->stats.packets++; - sch->q.qlen++; - return 0; + /* + * Okay, this may seem weird. We pretend we've dropped the packet if + * it goes via ATM. The reason for this is that the outer qdisc + * expects to be able to q->dequeue the packet later on if we return + * success at this place. Also, sch->q.qdisc needs to reflect whether + * there is a packet egligible for dequeuing or not. Note that the + * statistics of the outer qdisc are necessarily wrong because of all + * this. There's currently no correct solution for this. + */ + if (flow == &p->link) { + sch->q.qlen++; + return 0; + } + tasklet_schedule(&p->task); + return NET_XMIT_BYPASS; } @@ -477,11 +490,9 @@ static void sch_atm_dequeue(unsigned long data) */ while ((skb = flow->q->dequeue(flow->q))) { if (!atm_may_send(flow->vcc,skb->truesize)) { - if (flow->q->ops->requeue(skb,flow->q)) - sch->q.qlen--; + (void) flow->q->ops->requeue(skb,flow->q); break; } - sch->q.qlen--; D2PRINTK("atm_tc_deqeueue: sending on class %p\n",flow); /* remove any LL header somebody else has attached */ skb_pull(skb,(char *) skb->nh.iph-(char *) skb->data); @@ -501,7 +512,7 @@ static void sch_atm_dequeue(unsigned long data) atomic_add(skb->truesize,&flow->vcc->tx_inuse); ATM_SKB(skb)->iovcnt = 0; /* atm.atm_options are already set by atm_tc_enqueue */ - (void) flow->vcc->dev->ops->send(flow->vcc,skb); + (void) flow->vcc->send(flow->vcc,skb); } } diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c index af9923ec8..b8c0a7be8 100644 --- a/net/sunrpc/auth.c +++ b/net/sunrpc/auth.c @@ -4,12 +4,9 @@ * Generic RPC authentication API. * * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de> - * - * Modified May 1999, Horst von Brand <vonbrand@sleipnir.valparaiso.cl> */ #include <linux/types.h> -#include <linux/string.h> #include <linux/sched.h> #include <linux/malloc.h> #include <linux/errno.h> @@ -84,6 +81,15 @@ rpcauth_init_credcache(struct rpc_auth *auth) auth->au_nextgc = jiffies + (auth->au_expire >> 1); } +static inline void +rpcauth_crdestroy(struct rpc_auth *auth, struct rpc_cred *cred) +{ + if (auth->au_ops->crdestroy) + auth->au_ops->crdestroy(cred); + else + rpc_free(cred); +} + /* * Clear the RPC credential cache */ @@ -115,18 +121,15 @@ static void rpcauth_gc_credcache(struct rpc_auth *auth) { struct rpc_cred **q, *cred, *free = NULL; - int i, safe = 0; + int i; dprintk("RPC: gc'ing RPC credentials for auth %p\n", auth); spin_lock(&rpc_credcache_lock); for (i = 0; i < RPC_CREDCACHE_NR; i++) { q = &auth->au_credcache[i]; while ((cred = *q) != NULL) { - if (++safe > 500) { - printk("RPC: rpcauth_gc_credcache looping!\n"); - break; - } - if (!cred->cr_count && time_before(cred->cr_expire, jiffies)) { + if (!cred->cr_count && + time_before(cred->cr_expire, jiffies)) { *q = cred->cr_next; cred->cr_next = free; free = cred; @@ -138,7 +141,7 @@ rpcauth_gc_credcache(struct rpc_auth *auth) spin_unlock(&rpc_credcache_lock); while ((cred = free) != NULL) { free = cred->cr_next; - rpc_free(cred); + rpcauth_crdestroy(auth, cred); } auth->au_nextgc = jiffies + auth->au_expire; } @@ -146,7 +149,7 @@ rpcauth_gc_credcache(struct rpc_auth *auth) /* * Insert credential into cache */ -inline void +void rpcauth_insert_credcache(struct rpc_auth *auth, struct rpc_cred *cred) { int nr; @@ -155,8 +158,8 @@ rpcauth_insert_credcache(struct rpc_auth *auth, struct rpc_cred *cred) spin_lock(&rpc_credcache_lock); cred->cr_next = auth->au_credcache[nr]; auth->au_credcache[nr] = cred; - cred->cr_expire = jiffies + auth->au_expire; cred->cr_count++; + cred->cr_expire = jiffies + auth->au_expire; spin_unlock(&rpc_credcache_lock); } @@ -164,13 +167,13 @@ rpcauth_insert_credcache(struct rpc_auth *auth, struct rpc_cred *cred) * Look up a process' credentials in the authentication cache */ static struct rpc_cred * -rpcauth_lookup_credcache(struct rpc_task *task) +rpcauth_lookup_credcache(struct rpc_auth *auth, int taskflags) { - struct rpc_auth *auth = task->tk_auth; struct rpc_cred **q, *cred = NULL; - int nr; + int nr = 0; - nr = RPC_DO_ROOTOVERRIDE(task)? 0 : (current->uid % RPC_CREDCACHE_NR); + if (!(taskflags & RPC_TASK_ROOTCREDS)) + nr = current->uid % RPC_CREDCACHE_NR; if (time_before(auth->au_nextgc, jiffies)) rpcauth_gc_credcache(auth); @@ -178,7 +181,8 @@ rpcauth_lookup_credcache(struct rpc_task *task) spin_lock(&rpc_credcache_lock); q = &auth->au_credcache[nr]; while ((cred = *q) != NULL) { - if (auth->au_ops->crmatch(task, cred)) { + if (!(cred->cr_flags & RPCAUTH_CRED_DEAD) && + auth->au_ops->crmatch(cred, taskflags)) { *q = cred->cr_next; break; } @@ -187,7 +191,7 @@ rpcauth_lookup_credcache(struct rpc_task *task) spin_unlock(&rpc_credcache_lock); if (!cred) - cred = auth->au_ops->crcreate(task); + cred = auth->au_ops->crcreate(taskflags); if (cred) rpcauth_insert_credcache(auth, cred); @@ -198,7 +202,7 @@ rpcauth_lookup_credcache(struct rpc_task *task) /* * Remove cred handle from cache */ -static inline void +static void rpcauth_remove_credcache(struct rpc_auth *auth, struct rpc_cred *cred) { struct rpc_cred **q, *cr; @@ -210,7 +214,8 @@ rpcauth_remove_credcache(struct rpc_auth *auth, struct rpc_cred *cred) while ((cr = *q) != NULL) { if (cred == cr) { *q = cred->cr_next; - return; + cred->cr_next = NULL; + break; } q = &cred->cr_next; } @@ -218,58 +223,78 @@ rpcauth_remove_credcache(struct rpc_auth *auth, struct rpc_cred *cred) } struct rpc_cred * -rpcauth_lookupcred(struct rpc_task *task) +rpcauth_lookupcred(struct rpc_auth *auth, int taskflags) +{ + dprintk("RPC: looking up %s cred\n", + auth->au_ops->au_name); + return rpcauth_lookup_credcache(auth, taskflags); +} + +struct rpc_cred * +rpcauth_bindcred(struct rpc_task *task) { + struct rpc_auth *auth = task->tk_auth; + dprintk("RPC: %4d looking up %s cred\n", task->tk_pid, task->tk_auth->au_ops->au_name); - return task->tk_cred = rpcauth_lookup_credcache(task); + task->tk_msg.rpc_cred = rpcauth_lookup_credcache(auth, task->tk_flags); + if (task->tk_msg.rpc_cred == 0) + task->tk_status = -ENOMEM; + return task->tk_msg.rpc_cred; } int -rpcauth_matchcred(struct rpc_task *task, struct rpc_cred *cred) +rpcauth_matchcred(struct rpc_auth *auth, struct rpc_cred *cred, int taskflags) { - struct rpc_auth *auth = task->tk_auth; - - dprintk("RPC: %4d matching %s cred %p\n", - task->tk_pid, auth->au_ops->au_name, task->tk_cred); - return auth->au_ops->crmatch(task, cred); + dprintk("RPC: matching %s cred %d\n", + auth->au_ops->au_name, taskflags); + return auth->au_ops->crmatch(cred, taskflags); } void rpcauth_holdcred(struct rpc_task *task) { dprintk("RPC: %4d holding %s cred %p\n", - task->tk_pid, task->tk_auth->au_ops->au_name, task->tk_cred); - if (task->tk_cred) - task->tk_cred->cr_count++; + task->tk_pid, task->tk_auth->au_ops->au_name, task->tk_msg.rpc_cred); + if (task->tk_msg.rpc_cred) { + task->tk_msg.rpc_cred->cr_count++; + task->tk_msg.rpc_cred->cr_expire = jiffies + task->tk_auth->au_expire; + } } void -rpcauth_releasecred(struct rpc_task *task) +rpcauth_releasecred(struct rpc_auth *auth, struct rpc_cred *cred) { - struct rpc_auth *auth = task->tk_auth; - struct rpc_cred *cred; - - dprintk("RPC: %4d releasing %s cred %p\n", - task->tk_pid, auth->au_ops->au_name, task->tk_cred); - if ((cred = task->tk_cred) != NULL) { + if (cred != NULL && cred->cr_count > 0) { cred->cr_count--; if (cred->cr_flags & RPCAUTH_CRED_DEAD) { rpcauth_remove_credcache(auth, cred); if (!cred->cr_count) - auth->au_ops->crdestroy(cred); + rpcauth_crdestroy(auth, cred); } - task->tk_cred = NULL; } } +void +rpcauth_unbindcred(struct rpc_task *task) +{ + struct rpc_auth *auth = task->tk_auth; + struct rpc_cred *cred = task->tk_msg.rpc_cred; + + dprintk("RPC: %4d releasing %s cred %p\n", + task->tk_pid, auth->au_ops->au_name, cred); + + rpcauth_releasecred(auth, cred); + task->tk_msg.rpc_cred = NULL; +} + u32 * rpcauth_marshcred(struct rpc_task *task, u32 *p) { struct rpc_auth *auth = task->tk_auth; dprintk("RPC: %4d marshaling %s cred %p\n", - task->tk_pid, auth->au_ops->au_name, task->tk_cred); + task->tk_pid, auth->au_ops->au_name, task->tk_msg.rpc_cred); return auth->au_ops->crmarshal(task, p, task->tk_flags & RPC_CALL_REALUID); } @@ -280,7 +305,7 @@ rpcauth_checkverf(struct rpc_task *task, u32 *p) struct rpc_auth *auth = task->tk_auth; dprintk("RPC: %4d validating %s cred %p\n", - task->tk_pid, auth->au_ops->au_name, task->tk_cred); + task->tk_pid, auth->au_ops->au_name, task->tk_msg.rpc_cred); return auth->au_ops->crvalidate(task, p); } @@ -290,7 +315,7 @@ rpcauth_refreshcred(struct rpc_task *task) struct rpc_auth *auth = task->tk_auth; dprintk("RPC: %4d refreshing %s cred %p\n", - task->tk_pid, auth->au_ops->au_name, task->tk_cred); + task->tk_pid, auth->au_ops->au_name, task->tk_msg.rpc_cred); task->tk_status = auth->au_ops->crrefresh(task); return task->tk_status; } @@ -299,14 +324,14 @@ void rpcauth_invalcred(struct rpc_task *task) { dprintk("RPC: %4d invalidating %s cred %p\n", - task->tk_pid, task->tk_auth->au_ops->au_name, task->tk_cred); - if (task->tk_cred) - task->tk_cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE; + task->tk_pid, task->tk_auth->au_ops->au_name, task->tk_msg.rpc_cred); + if (task->tk_msg.rpc_cred) + task->tk_msg.rpc_cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE; } int rpcauth_uptodatecred(struct rpc_task *task) { - return !(task->tk_cred) || - (task->tk_cred->cr_flags & RPCAUTH_CRED_UPTODATE); + return !(task->tk_msg.rpc_cred) || + (task->tk_msg.rpc_cred->cr_flags & RPCAUTH_CRED_UPTODATE); } diff --git a/net/sunrpc/auth_null.c b/net/sunrpc/auth_null.c index be6d19637..d2e645acd 100644 --- a/net/sunrpc/auth_null.c +++ b/net/sunrpc/auth_null.c @@ -38,6 +38,7 @@ static void nul_destroy(struct rpc_auth *auth) { dprintk("RPC: destroying NULL authenticator %p\n", auth); + rpcauth_free_credcache(auth); rpc_free(auth); } @@ -45,15 +46,12 @@ nul_destroy(struct rpc_auth *auth) * Create NULL creds for current process */ static struct rpc_cred * -nul_create_cred(struct rpc_task *task) +nul_create_cred(int flags) { struct rpc_cred *cred; - if (!(cred = (struct rpc_cred *) rpc_malloc(task, sizeof(*cred)))) { - task->tk_status = -ENOMEM; + if (!(cred = (struct rpc_cred *) rpc_allocate(flags, sizeof(*cred)))) return NULL; - } - cred->cr_count = 0; cred->cr_flags = RPCAUTH_CRED_UPTODATE; @@ -73,7 +71,7 @@ nul_destroy_cred(struct rpc_cred *cred) * Match cred handle against current process */ static int -nul_match(struct rpc_task *task, struct rpc_cred *cred) +nul_match(struct rpc_cred *cred, int taskflags) { return 1; } diff --git a/net/sunrpc/auth_unix.c b/net/sunrpc/auth_unix.c index 6596085b3..8033ed6c1 100644 --- a/net/sunrpc/auth_unix.c +++ b/net/sunrpc/auth_unix.c @@ -4,12 +4,9 @@ * UNIX-style authentication; no AUTH_SHORT support * * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de> - * - * Modified May 1999 Horst von Brand <vonbrand@sleipnir.valparaiso.cl> */ #include <linux/types.h> -#include <linux/string.h> #include <linux/malloc.h> #include <linux/socket.h> #include <linux/in.h> @@ -63,7 +60,7 @@ unx_destroy(struct rpc_auth *auth) } static struct rpc_cred * -unx_create_cred(struct rpc_task *task) +unx_create_cred(int flags) { struct unx_cred *cred; int i; @@ -71,14 +68,12 @@ unx_create_cred(struct rpc_task *task) dprintk("RPC: allocating UNIX cred for uid %d gid %d\n", current->uid, current->gid); - if (!(cred = (struct unx_cred *) rpc_malloc(task, sizeof(*cred)))) { - task->tk_status = -ENOMEM; + if (!(cred = (struct unx_cred *) rpc_allocate(flags, sizeof(*cred)))) return NULL; - } cred->uc_count = 0; cred->uc_flags = RPCAUTH_CRED_UPTODATE; - if (RPC_DO_ROOTOVERRIDE(task)) { + if (flags & RPC_TASK_ROOTCREDS) { cred->uc_uid = cred->uc_fsuid = 0; cred->uc_gid = cred->uc_fsgid = 0; cred->uc_gids[0] = NOGROUP; @@ -119,7 +114,7 @@ authunix_fake_cred(struct rpc_task *task, uid_t uid, gid_t gid) cred->uc_fsgid = gid; cred->uc_gids[0] = (gid_t) NOGROUP; - return task->tk_cred = (struct rpc_cred *) cred; + return task->tk_msg.rpc_cred = (struct rpc_cred *) cred; } static void @@ -134,12 +129,12 @@ unx_destroy_cred(struct rpc_cred *cred) * request root creds (e.g. for NFS swapping). */ static int -unx_match(struct rpc_task * task, struct rpc_cred *rcred) +unx_match(struct rpc_cred *rcred, int taskflags) { struct unx_cred *cred = (struct unx_cred *) rcred; int i; - if (!RPC_DO_ROOTOVERRIDE(task)) { + if (!(taskflags & RPC_TASK_ROOTCREDS)) { int groups; if (cred->uc_uid != current->uid @@ -169,7 +164,7 @@ static u32 * unx_marshal(struct rpc_task *task, u32 *p, int ruid) { struct rpc_clnt *clnt = task->tk_client; - struct unx_cred *cred = (struct unx_cred *) task->tk_cred; + struct unx_cred *cred = (struct unx_cred *) task->tk_msg.rpc_cred; u32 *base, *hold; int i, n; @@ -210,7 +205,7 @@ unx_marshal(struct rpc_task *task, u32 *p, int ruid) static int unx_refresh(struct rpc_task *task) { - task->tk_cred->cr_flags |= RPCAUTH_CRED_UPTODATE; + task->tk_msg.rpc_cred->cr_flags |= RPCAUTH_CRED_UPTODATE; return task->tk_status = -EACCES; } diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index b4d6bd81a..806e14bce 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -42,14 +42,13 @@ static DECLARE_WAIT_QUEUE_HEAD(destroy_wait); -static void call_bind(struct rpc_task *task); static void call_reserve(struct rpc_task *task); static void call_reserveresult(struct rpc_task *task); static void call_allocate(struct rpc_task *task); static void call_encode(struct rpc_task *task); static void call_decode(struct rpc_task *task); +static void call_bind(struct rpc_task *task); static void call_transmit(struct rpc_task *task); -static void call_receive(struct rpc_task *task); static void call_status(struct rpc_task *task); static void call_refresh(struct rpc_task *task); static void call_refreshresult(struct rpc_task *task); @@ -98,7 +97,7 @@ rpc_create_client(struct rpc_xprt *xprt, char *servname, clnt->cl_port = xprt->addr.sin_port; clnt->cl_prog = program->number; clnt->cl_vers = version->number; - clnt->cl_prot = IPPROTO_UDP; + clnt->cl_prot = xprt->prot; clnt->cl_stats = program->stats; clnt->cl_bindwait = RPC_INIT_WAITQ("bindwait"); @@ -117,10 +116,10 @@ out: return clnt; out_no_clnt: - printk("RPC: out of memory in rpc_create_client\n"); + printk(KERN_INFO "RPC: out of memory in rpc_create_client\n"); goto out; out_no_auth: - printk("RPC: Couldn't create auth handle (flavor %d)\n", + printk(KERN_INFO "RPC: Couldn't create auth handle (flavor %d)\n", flavor); rpc_free(clnt); clnt = NULL; @@ -140,7 +139,7 @@ rpc_shutdown_client(struct rpc_clnt *clnt) clnt->cl_protname, clnt->cl_server); while (clnt->cl_users) { #ifdef RPC_DEBUG - printk("rpc_shutdown_client: client %s, tasks=%d\n", + dprintk("RPC: rpc_shutdown_client: client %s, tasks=%d\n", clnt->cl_protname, clnt->cl_users); #endif /* Don't let rpc_release_client destroy us */ @@ -240,42 +239,72 @@ void rpc_clnt_sigunmask(struct rpc_clnt *clnt, sigset_t *oldset) /* * New rpc_call implementation */ -int -rpc_do_call(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp, - int flags, rpc_action func, void *data) +int rpc_call_sync(struct rpc_clnt *clnt, struct rpc_message *msg, int flags) { struct rpc_task my_task, *task = &my_task; sigset_t oldset; - int async, status; + int status; /* If this client is slain all further I/O fails */ if (clnt->cl_dead) return -EIO; + if (flags & RPC_TASK_ASYNC) { + printk("rpc_call_sync: Illegal flag combination for synchronous task\n"); + flags &= ~RPC_TASK_ASYNC; + } + rpc_clnt_sigmask(clnt, &oldset); /* Create/initialize a new RPC task */ - if ((async = (flags & RPC_TASK_ASYNC)) != 0) { - if (!func) - func = rpc_default_callback; - status = -ENOMEM; - if (!(task = rpc_new_task(clnt, func, flags))) - goto out; - task->tk_calldata = data; - } else { - rpc_init_task(task, clnt, NULL, flags); - } + rpc_init_task(task, clnt, NULL, flags); + rpc_call_setup(task, msg, 0); - /* Bind the user cred, set up the call info struct and - * execute the task */ - if (rpcauth_lookupcred(task) != NULL) { - rpc_call_setup(task, proc, argp, resp, 0); - rpc_execute(task); - } else - async = 0; + /* Set up the call info struct and execute the task */ + if (task->tk_status == 0) + status = rpc_execute(task); + else + status = task->tk_status; + rpc_release_task(task); + + rpc_clnt_sigunmask(clnt, &oldset); + + return status; +} - status = 0; - if (!async) { +/* + * New rpc_call implementation + */ +int +rpc_call_async(struct rpc_clnt *clnt, struct rpc_message *msg, int flags, + rpc_action callback, void *data) +{ + struct rpc_task *task; + sigset_t oldset; + int status; + + /* If this client is slain all further I/O fails */ + if (clnt->cl_dead) + return -EIO; + + flags |= RPC_TASK_ASYNC; + + rpc_clnt_sigmask(clnt, &oldset); + + /* Create/initialize a new RPC task */ + if (!callback) + callback = rpc_default_callback; + status = -ENOMEM; + if (!(task = rpc_new_task(clnt, callback, flags))) + goto out; + task->tk_calldata = data; + + rpc_call_setup(task, msg, 0); + + /* Set up the call info struct and execute the task */ + if (task->tk_status == 0) + status = rpc_execute(task); + else { status = task->tk_status; rpc_release_task(task); } @@ -288,18 +317,24 @@ out: void -rpc_call_setup(struct rpc_task *task, u32 proc, - void *argp, void *resp, int flags) +rpc_call_setup(struct rpc_task *task, struct rpc_message *msg, int flags) { - task->tk_action = call_bind; - task->tk_proc = proc; - task->tk_argp = argp; - task->tk_resp = resp; + task->tk_msg = *msg; task->tk_flags |= flags; + /* Bind the user cred */ + if (task->tk_msg.rpc_cred != NULL) { + rpcauth_holdcred(task); + } else + rpcauth_bindcred(task); + + if (task->tk_status == 0) + task->tk_action = call_reserve; + else + task->tk_action = NULL; /* Increment call count */ - if (task->tk_proc < task->tk_client->cl_maxproc) - rpcproc_count(task->tk_client, proc)++; + if (task->tk_msg.rpc_proc < task->tk_client->cl_maxproc) + rpcproc_count(task->tk_client, task->tk_msg.rpc_proc)++; } /* @@ -313,27 +348,8 @@ rpc_restart_call(struct rpc_task *task) rpc_release_task(task); return; } - task->tk_action = call_bind; - rpcproc_count(task->tk_client, task->tk_proc)++; -} - -/* - * 0. Get the server port number if not yet set - */ -static void -call_bind(struct rpc_task *task) -{ - struct rpc_clnt *clnt = task->tk_client; - struct rpc_xprt *xprt = clnt->cl_xprt; - - if (xprt->stream && !xprt->connected) - task->tk_action = call_reconnect; - else - task->tk_action = call_reserve; - task->tk_status = 0; - - if (!clnt->cl_port) - rpc_getport(task, clnt); + task->tk_action = call_reserve; + rpcproc_count(task->tk_client, task->tk_msg.rpc_proc)++; } /* @@ -344,26 +360,22 @@ call_reserve(struct rpc_task *task) { struct rpc_clnt *clnt = task->tk_client; - dprintk("RPC: %4d call_reserve\n", task->tk_pid); - if (!clnt->cl_port) { - printk(KERN_NOTICE "%s: couldn't bind to server %s - %s.\n", - clnt->cl_protname, clnt->cl_server, - clnt->cl_softrtry? "giving up" : "retrying"); - if (!clnt->cl_softrtry) { - task->tk_action = call_bind; - rpc_delay(task, 5*HZ); - return; - } + if (task->tk_msg.rpc_proc > clnt->cl_maxproc) { + printk(KERN_WARNING "%s (vers %d): bad procedure number %d\n", + clnt->cl_protname, clnt->cl_vers, task->tk_msg.rpc_proc); rpc_exit(task, -EIO); return; } + + dprintk("RPC: %4d call_reserve\n", task->tk_pid); if (!rpcauth_uptodatecred(task)) { task->tk_action = call_refresh; return; } + + task->tk_status = 0; task->tk_action = call_reserveresult; task->tk_timeout = clnt->cl_timeout.to_resrvval; - task->tk_status = 0; clnt->cl_stats->rpccnt++; xprt_reserve(task); } @@ -374,6 +386,8 @@ call_reserve(struct rpc_task *task) static void call_reserveresult(struct rpc_task *task) { + int status = task->tk_status; + dprintk("RPC: %4d call_reserveresult (status %d)\n", task->tk_pid, task->tk_status); /* @@ -382,7 +396,7 @@ call_reserveresult(struct rpc_task *task) */ if ((task->tk_status >= 0 && !task->tk_rqstp) || (task->tk_status < 0 && task->tk_rqstp)) - printk("call_reserveresult: status=%d, request=%p??\n", + printk(KERN_ERR "call_reserveresult: status=%d, request=%p??\n", task->tk_status, task->tk_rqstp); if (task->tk_status >= 0) { @@ -390,11 +404,11 @@ call_reserveresult(struct rpc_task *task) return; } - switch (task->tk_status) { + task->tk_status = 0; + switch (status) { case -EAGAIN: case -ENOBUFS: task->tk_timeout = task->tk_client->cl_timeout.to_resrvval; - task->tk_status = 0; task->tk_action = call_reserve; break; case -ETIMEDOUT: @@ -402,11 +416,11 @@ call_reserveresult(struct rpc_task *task) task->tk_action = call_timeout; break; default: - task->tk_action = NULL; if (!task->tk_rqstp) { - printk("RPC: task has no request, exit EIO\n"); + printk(KERN_INFO "RPC: task has no request, exit EIO\n"); rpc_exit(task, -EIO); - } + } else + rpc_exit(task, status); } } @@ -428,13 +442,13 @@ call_allocate(struct rpc_task *task) /* FIXME: compute buffer requirements more exactly using * auth->au_wslack */ - bufsiz = rpcproc_bufsiz(clnt, task->tk_proc) + RPC_SLACK_SPACE; + bufsiz = rpcproc_bufsiz(clnt, task->tk_msg.rpc_proc) + RPC_SLACK_SPACE; if ((task->tk_buffer = rpc_malloc(task, bufsiz)) != NULL) return; - printk("RPC: buffer allocation failed for task %p\n", task); + printk(KERN_INFO "RPC: buffer allocation failed for task %p\n", task); - if (!signalled()) { + if (RPC_IS_ASYNC(task) || !(task->tk_client->cl_intr && signalled())) { xprt_release(task); task->tk_action = call_reserve; rpc_delay(task, HZ>>4); @@ -460,10 +474,10 @@ call_encode(struct rpc_task *task) dprintk("RPC: %4d call_encode (status %d)\n", task->tk_pid, task->tk_status); - task->tk_action = call_transmit; + task->tk_action = call_bind; /* Default buffer setup */ - bufsiz = rpcproc_bufsiz(clnt, task->tk_proc)+RPC_SLACK_SPACE; + bufsiz = rpcproc_bufsiz(clnt, task->tk_msg.rpc_proc)+RPC_SLACK_SPACE; req->rq_svec[0].iov_base = task->tk_buffer; req->rq_svec[0].iov_len = bufsiz; req->rq_slen = 0; @@ -474,23 +488,16 @@ call_encode(struct rpc_task *task) req->rq_rnr = 1; req->rq_damaged = 0; - if (task->tk_proc > clnt->cl_maxproc) { - printk(KERN_WARNING "%s (vers %d): bad procedure number %d\n", - clnt->cl_protname, clnt->cl_vers, task->tk_proc); - rpc_exit(task, -EIO); - return; - } - /* Zero buffer so we have automatic zero-padding of opaque & string */ memset(task->tk_buffer, 0, bufsiz); /* Encode header and provided arguments */ - encode = rpcproc_encode(clnt, task->tk_proc); + encode = rpcproc_encode(clnt, task->tk_msg.rpc_proc); if (!(p = call_header(task))) { - printk("RPC: call_header failed, exit EIO\n"); + printk(KERN_INFO "RPC: call_header failed, exit EIO\n"); rpc_exit(task, -EIO); } else - if (encode && (status = encode(req, p, task->tk_argp)) < 0) { + if (encode && (status = encode(req, p, task->tk_msg.rpc_argp)) < 0) { printk(KERN_WARNING "%s: can't encode arguments: %d\n", clnt->cl_protname, -status); rpc_exit(task, status); @@ -498,38 +505,59 @@ call_encode(struct rpc_task *task) } /* - * 4. Transmit the RPC request + * 4. Get the server port number if not yet set */ static void -call_transmit(struct rpc_task *task) +call_bind(struct rpc_task *task) { - dprintk("RPC: %4d call_transmit (status %d)\n", - task->tk_pid, task->tk_status); + struct rpc_clnt *clnt = task->tk_client; + struct rpc_xprt *xprt = clnt->cl_xprt; - task->tk_action = call_receive; - task->tk_status = 0; - xprt_transmit(task); + task->tk_action = (xprt->connected) ? call_transmit : call_reconnect; + + if (!clnt->cl_port) { + task->tk_action = call_reconnect; + task->tk_timeout = clnt->cl_timeout.to_maxval; + rpc_getport(task, clnt); + } } /* - * 5. Wait for the RPC reply + * 4a. Reconnect to the RPC server (TCP case) */ static void -call_receive(struct rpc_task *task) +call_reconnect(struct rpc_task *task) { - dprintk("RPC: %4d call_receive (status %d)\n", - task->tk_pid, task->tk_status); + struct rpc_clnt *clnt = task->tk_client; - task->tk_action = call_status; + dprintk("RPC: %4d call_reconnect status %d\n", + task->tk_pid, task->tk_status); - /* Need to ensure cleanups are performed by xprt_receive_status() */ - xprt_receive(task); + task->tk_action = call_transmit; + if (task->tk_status < 0 || !clnt->cl_xprt->stream) + return; + clnt->cl_stats->netreconn++; + xprt_reconnect(task); +} - /* If we have no decode function, this means we're performing - * a void call (a la lockd message passing). */ - if (!rpcproc_decode(task->tk_client, task->tk_proc)) { - task->tk_action = NULL; +/* + * 5. Transmit the RPC request, and wait for reply + */ +static void +call_transmit(struct rpc_task *task) +{ + struct rpc_clnt *clnt = task->tk_client; + + dprintk("RPC: %4d call_transmit (status %d)\n", + task->tk_pid, task->tk_status); + + task->tk_action = call_status; + if (task->tk_status < 0) return; + xprt_transmit(task); + if (!rpcproc_decode(clnt, task->tk_msg.rpc_proc)) { + task->tk_action = NULL; + rpc_wake_up_task(task); } } @@ -558,34 +586,30 @@ call_status(struct rpc_task *task) case -ETIMEDOUT: task->tk_action = call_timeout; break; - case -EAGAIN: - if (!req) - task->tk_action = call_reserve; - else if (!task->tk_buffer) - task->tk_action = call_allocate; - else if (req->rq_damaged) { - task->tk_action = call_encode; - clnt->cl_stats->rpcretrans++; - } else { - task->tk_action = call_transmit; - clnt->cl_stats->rpcretrans++; - } - break; case -ECONNREFUSED: case -ENOTCONN: + req->rq_bytes_sent = 0; if (clnt->cl_autobind || !clnt->cl_port) { clnt->cl_port = 0; task->tk_action = call_bind; - } else if (xprt->stream) + break; + } + if (xprt->stream) { task->tk_action = call_reconnect; - else { - rpc_delay(task, 5*HZ); /* Hope it all wears off */ - if (req->rq_damaged) - task->tk_action = call_encode; - else - task->tk_action = call_transmit; - clnt->cl_stats->rpcretrans++; + break; } + /* + * Sleep and dream of an open connection + */ + task->tk_timeout = 5 * HZ; + rpc_sleep_on(&xprt->sending, task, NULL, NULL); + case -ENOMEM: + case -EAGAIN: + if (req->rq_damaged) + task->tk_action = call_encode; + else + task->tk_action = call_transmit; + clnt->cl_stats->rpcretrans++; break; default: if (clnt->cl_chatty) @@ -614,15 +638,13 @@ call_timeout(struct rpc_task *task) task->tk_pid); goto minor_timeout; } - to->to_initval <<= 1; - if (to->to_initval > to->to_maxval) - to->to_initval = to->to_maxval; + to->to_retries = clnt->cl_timeout.to_retries; } dprintk("RPC: %4d call_timeout (major timeo)\n", task->tk_pid); if (clnt->cl_softrtry) { if (clnt->cl_chatty && !task->tk_exit) - printk("%s: server %s not responding, timed out\n", + printk(KERN_NOTICE "%s: server %s not responding, timed out\n", clnt->cl_protname, clnt->cl_server); rpc_exit(task, -EIO); return; @@ -630,24 +652,26 @@ call_timeout(struct rpc_task *task) if (clnt->cl_chatty && !(task->tk_flags & RPC_CALL_MAJORSEEN)) { task->tk_flags |= RPC_CALL_MAJORSEEN; if (req) - printk("%s: server %s not responding, still trying\n", + printk(KERN_NOTICE "%s: server %s not responding, still trying\n", clnt->cl_protname, clnt->cl_server); else - printk("%s: task %d can't get a request slot\n", + printk(KERN_NOTICE "%s: task %d can't get a request slot\n", clnt->cl_protname, task->tk_pid); } if (clnt->cl_autobind) clnt->cl_port = 0; minor_timeout: - if (!clnt->cl_port) { + if (!req) + task->tk_action = call_reserve; + else if (req->rq_damaged) { + task->tk_action = call_encode; + clnt->cl_stats->rpcretrans++; + } else if (!clnt->cl_port) { task->tk_action = call_bind; + clnt->cl_stats->rpcretrans++; } else if (clnt->cl_xprt->stream && !clnt->cl_xprt->connected) { task->tk_action = call_reconnect; - } else if (!req) { - task->tk_action = call_reserve; - } else if (req->rq_damaged) { - task->tk_action = call_encode; clnt->cl_stats->rpcretrans++; } else { task->tk_action = call_transmit; @@ -657,21 +681,6 @@ minor_timeout: } /* - * 6b. Reconnect to the RPC server (TCP case) - */ -static void -call_reconnect(struct rpc_task *task) -{ - struct rpc_clnt *clnt = task->tk_client; - dprintk("RPC: %4d call_reconnect status %d\n", - task->tk_pid, task->tk_status); - task->tk_action = call_reserve; - task->tk_status = 0; - clnt->cl_stats->netreconn++; - xprt_reconnect(task); -} - -/* * 7. Decode the RPC reply */ static void @@ -679,20 +688,20 @@ call_decode(struct rpc_task *task) { struct rpc_clnt *clnt = task->tk_client; struct rpc_rqst *req = task->tk_rqstp; - kxdrproc_t decode = rpcproc_decode(clnt, task->tk_proc); + kxdrproc_t decode = rpcproc_decode(clnt, task->tk_msg.rpc_proc); u32 *p; dprintk("RPC: %4d call_decode (status %d)\n", task->tk_pid, task->tk_status); if (clnt->cl_chatty && (task->tk_flags & RPC_CALL_MAJORSEEN)) { - printk("%s: server %s OK\n", + printk(KERN_NOTICE "%s: server %s OK\n", clnt->cl_protname, clnt->cl_server); task->tk_flags &= ~RPC_CALL_MAJORSEEN; } if (task->tk_status < 12) { - printk("%s: too small RPC reply size (%d bytes)\n", + printk(KERN_WARNING "%s: too small RPC reply size (%d bytes)\n", clnt->cl_protname, task->tk_status); rpc_exit(task, -EIO); return; @@ -708,10 +717,11 @@ call_decode(struct rpc_task *task) */ if (task->tk_client->cl_prog == 100003 && (ntohl(*p) == NFSERR_ACCES || ntohl(*p) == NFSERR_PERM)) { - if (RPC_IS_SETUID(task) && (task->tk_suid_retry)--) { + if (RPC_IS_SETUID(task) && task->tk_suid_retry) { dprintk("RPC: %4d retry squashed uid\n", task->tk_pid); task->tk_flags ^= RPC_CALL_REALUID; task->tk_action = call_encode; + task->tk_suid_retry--; return; } } @@ -719,7 +729,7 @@ call_decode(struct rpc_task *task) task->tk_action = NULL; if (decode) - task->tk_status = decode(req, p, task->tk_resp); + task->tk_status = decode(req, p, task->tk_msg.rpc_resp); dprintk("RPC: %4d call_decode result %d\n", task->tk_pid, task->tk_status); } @@ -751,7 +761,7 @@ call_refreshresult(struct rpc_task *task) if (task->tk_status < 0) rpc_exit(task, -EACCES); else - task->tk_action = call_bind; + task->tk_action = call_reserve; } /* @@ -772,7 +782,7 @@ call_header(struct rpc_task *task) *p++ = htonl(RPC_VERSION); /* RPC version */ *p++ = htonl(clnt->cl_prog); /* program number */ *p++ = htonl(clnt->cl_vers); /* program version */ - *p++ = htonl(task->tk_proc); /* procedure */ + *p++ = htonl(task->tk_msg.rpc_proc); /* procedure */ return rpcauth_marshcred(task, p); } @@ -787,20 +797,21 @@ call_verify(struct rpc_task *task) p += 1; /* skip XID */ if ((n = ntohl(*p++)) != RPC_REPLY) { - printk("call_verify: not an RPC reply: %x\n", n); + printk(KERN_WARNING "call_verify: not an RPC reply: %x\n", n); goto garbage; } if ((n = ntohl(*p++)) != RPC_MSG_ACCEPTED) { int error = -EACCES; if ((n = ntohl(*p++)) != RPC_AUTH_ERROR) { - printk("call_verify: RPC call rejected: %x\n", n); + printk(KERN_WARNING "call_verify: RPC call rejected: %x\n", n); } else switch ((n = ntohl(*p++))) { case RPC_AUTH_REJECTEDCRED: case RPC_AUTH_REJECTEDVERF: - if (!task->tk_cred_retry--) + if (!task->tk_cred_retry) break; + task->tk_cred_retry--; dprintk("RPC: %4d call_verify: retry stale creds\n", task->tk_pid); rpcauth_invalcred(task); @@ -809,17 +820,18 @@ call_verify(struct rpc_task *task) case RPC_AUTH_BADCRED: case RPC_AUTH_BADVERF: /* possibly garbled cred/verf? */ - if (!task->tk_garb_retry--) + if (!task->tk_garb_retry) break; + task->tk_garb_retry--; dprintk("RPC: %4d call_verify: retry garbled creds\n", task->tk_pid); task->tk_action = call_encode; return NULL; case RPC_AUTH_TOOWEAK: - printk("call_verify: server requires stronger " + printk(KERN_NOTICE "call_verify: server requires stronger " "authentication.\n"); default: - printk("call_verify: unknown auth error: %x\n", n); + printk(KERN_WARNING "call_verify: unknown auth error: %x\n", n); error = -EIO; } dprintk("RPC: %4d call_verify: call rejected %d\n", @@ -828,7 +840,7 @@ call_verify(struct rpc_task *task) return NULL; } if (!(p = rpcauth_checkverf(task, p))) { - printk("call_verify: auth check failed\n"); + printk(KERN_WARNING "call_verify: auth check failed\n"); goto garbage; /* bad verifier, retry */ } switch ((n = ntohl(*p++))) { @@ -837,19 +849,20 @@ call_verify(struct rpc_task *task) case RPC_GARBAGE_ARGS: break; /* retry */ default: - printk("call_verify: server accept status: %x\n", n); + printk(KERN_WARNING "call_verify: server accept status: %x\n", n); /* Also retry */ } garbage: dprintk("RPC: %4d call_verify: server saw garbage\n", task->tk_pid); task->tk_client->cl_stats->rpcgarbage++; - if (task->tk_garb_retry--) { - printk("RPC: garbage, retrying %4d\n", task->tk_pid); + if (task->tk_garb_retry) { + task->tk_garb_retry--; + printk(KERN_WARNING "RPC: garbage, retrying %4d\n", task->tk_pid); task->tk_action = call_encode; return NULL; } - printk("RPC: garbage, exit EIO\n"); + printk(KERN_WARNING "RPC: garbage, exit EIO\n"); rpc_exit(task, -EIO); return NULL; } diff --git a/net/sunrpc/pmap_clnt.c b/net/sunrpc/pmap_clnt.c index 2bbe9d50a..6afb28e88 100644 --- a/net/sunrpc/pmap_clnt.c +++ b/net/sunrpc/pmap_clnt.c @@ -41,6 +41,7 @@ rpc_getport(struct rpc_task *task, struct rpc_clnt *clnt) { struct rpc_portmap *map = &clnt->cl_pmap; struct sockaddr_in *sap = &clnt->cl_xprt->addr; + struct rpc_message msg = { PMAP_GETPORT, map, &clnt->cl_port, NULL }; struct rpc_clnt *pmap_clnt; struct rpc_task *child; @@ -66,7 +67,7 @@ rpc_getport(struct rpc_task *task, struct rpc_clnt *clnt) goto bailout; /* Setup the call info struct */ - rpc_call_setup(child, PMAP_GETPORT, map, &clnt->cl_port, 0); + rpc_call_setup(child, &msg, 0); /* ... and run the child task */ rpc_run_child(task, child, pmap_getport_done); diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index ffd4c18ad..bfbfc1580 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -69,6 +69,16 @@ static pid_t rpciod_pid = 0; static int rpc_inhibit = 0; /* + * Spinlock for wait queues. Access to the latter also has to be + * interrupt-safe in order to allow timers to wake up sleeping tasks. + */ +spinlock_t rpc_queue_lock = SPIN_LOCK_UNLOCKED; +/* + * Spinlock for other critical sections of code. + */ +spinlock_t rpc_sched_lock = SPIN_LOCK_UNLOCKED; + +/* * This is the last-ditch buffer for NFS swap requests */ static u32 swap_buffer[PAGE_SIZE >> 2]; @@ -87,14 +97,52 @@ static __inline__ void rpc_unlock_swapbuf(void) } /* - * Spinlock for wait queues. Access to the latter also has to be - * interrupt-safe in order to allow timers to wake up sleeping tasks. + * Set up a timer for the current task. */ -spinlock_t rpc_queue_lock = SPIN_LOCK_UNLOCKED; +static inline void +__rpc_add_timer(struct rpc_task *task, rpc_action timer) +{ + if (!task->tk_timeout) + return; + + dprintk("RPC: %4d setting alarm for %lu ms\n", + task->tk_pid, task->tk_timeout * 1000 / HZ); + + if (timer_pending(&task->tk_timer)) { + printk(KERN_ERR "RPC: Bug! Overwriting active timer\n"); + del_timer(&task->tk_timer); + } + if (!timer) + timer = __rpc_default_timer; + init_timer(&task->tk_timer); + task->tk_timer.expires = jiffies + task->tk_timeout; + task->tk_timer.data = (unsigned long) task; + task->tk_timer.function = (void (*)(unsigned long)) timer; + add_timer(&task->tk_timer); +} + /* - * Spinlock for other critical sections of code. + * Set up a timer for an already sleeping task. */ -spinlock_t rpc_sched_lock = SPIN_LOCK_UNLOCKED; +void rpc_add_timer(struct rpc_task *task, rpc_action timer) +{ + spin_lock_bh(&rpc_queue_lock); + if (!(RPC_IS_RUNNING(task) || task->tk_wakeup)) + __rpc_add_timer(task, timer); + spin_unlock_bh(&rpc_queue_lock); +} + +/* + * Delete any timer for the current task. + */ +static inline void +__rpc_del_timer(struct rpc_task *task) +{ + dprintk("RPC: %4d deleting timer\n", task->tk_pid); + if (timer_pending(&task->tk_timer)) + del_timer(&task->tk_timer); + task->tk_timeout = 0; +} /* * Add new request to wait queue. @@ -104,16 +152,15 @@ spinlock_t rpc_sched_lock = SPIN_LOCK_UNLOCKED; * improve overall performance. * Everyone else gets appended to the queue to ensure proper FIFO behavior. */ -static int +static inline int __rpc_add_wait_queue(struct rpc_wait_queue *queue, struct rpc_task *task) { - if (task->tk_rpcwait) { - if (task->tk_rpcwait != queue) - { - printk(KERN_WARNING "RPC: doubly enqueued task!\n"); - return -EWOULDBLOCK; - } + if (task->tk_rpcwait == queue) return 0; + + if (task->tk_rpcwait) { + printk(KERN_WARNING "RPC: doubly enqueued task!\n"); + return -EWOULDBLOCK; } if (RPC_IS_SWAPPER(task)) rpc_insert_list(&queue->task, task); @@ -130,7 +177,7 @@ __rpc_add_wait_queue(struct rpc_wait_queue *queue, struct rpc_task *task) int rpc_add_wait_queue(struct rpc_wait_queue *q, struct rpc_task *task) { - int result; + int result; spin_lock_bh(&rpc_queue_lock); result = __rpc_add_wait_queue(q, task); @@ -142,13 +189,14 @@ rpc_add_wait_queue(struct rpc_wait_queue *q, struct rpc_task *task) * Remove request from queue. * Note: must be called with spin lock held. */ -static void +static inline void __rpc_remove_wait_queue(struct rpc_task *task) { - struct rpc_wait_queue *queue; + struct rpc_wait_queue *queue = task->tk_rpcwait; - if (!(queue = task->tk_rpcwait)) + if (!queue) return; + rpc_remove_list(&queue->task, task); task->tk_rpcwait = NULL; @@ -159,51 +207,14 @@ __rpc_remove_wait_queue(struct rpc_task *task) void rpc_remove_wait_queue(struct rpc_task *task) { + if (!task->tk_rpcwait) + return; spin_lock_bh(&rpc_queue_lock); __rpc_remove_wait_queue(task); spin_unlock_bh(&rpc_queue_lock); } /* - * Set up a timer for the current task. - */ -inline void -rpc_add_timer(struct rpc_task *task, rpc_action timer) -{ - unsigned long expires = jiffies + task->tk_timeout; - - dprintk("RPC: %4d setting alarm for %lu ms\n", - task->tk_pid, task->tk_timeout * 1000 / HZ); - if (!timer) - timer = __rpc_default_timer; - if (time_before(expires, jiffies)) { - printk(KERN_ERR "RPC: bad timeout value %ld - setting to 10 sec!\n", - task->tk_timeout); - expires = jiffies + 10 * HZ; - } - task->tk_timer.expires = expires; - task->tk_timer.data = (unsigned long) task; - task->tk_timer.function = (void (*)(unsigned long)) timer; - task->tk_timer.prev = NULL; - task->tk_timer.next = NULL; - add_timer(&task->tk_timer); -} - -/* - * Delete any timer for the current task. - * Must be called with interrupts off. - */ -inline void -rpc_del_timer(struct rpc_task *task) -{ - if (task->tk_timeout) { - dprintk("RPC: %4d deleting timer\n", task->tk_pid); - del_timer(&task->tk_timer); - task->tk_timeout = 0; - } -} - -/* * Make an RPC task runnable. * * Note: If the task is ASYNC, this must be called with @@ -218,31 +229,44 @@ rpc_make_runnable(struct rpc_task *task) } task->tk_flags |= RPC_TASK_RUNNING; if (RPC_IS_ASYNC(task)) { - int status; - status = __rpc_add_wait_queue(&schedq, task); - if (status) - { - printk(KERN_WARNING "RPC: failed to add task to queue: error: %d!\n", status); - task->tk_status = status; + if (RPC_IS_SLEEPING(task)) { + int status; + status = __rpc_add_wait_queue(&schedq, task); + if (status < 0) { + printk(KERN_WARNING "RPC: failed to add task to queue: error: %d!\n", status); + task->tk_status = status; + } else + task->tk_sleeping = 0; } wake_up(&rpciod_idle); } else { + task->tk_sleeping = 0; wake_up(&task->tk_wait); } } +/* + * Place a newly initialized task on the schedq. + */ +static inline void +rpc_schedule_run(struct rpc_task *task) +{ + /* Don't run a child twice! */ + if (RPC_IS_ACTIVATED(task)) + return; + task->tk_active = 1; + task->tk_sleeping = 1; + rpc_make_runnable(task); +} /* * For other people who may need to wake the I/O daemon * but should (for now) know nothing about its innards */ - void rpciod_wake_up(void) { if(rpciod_pid==0) - { printk(KERN_ERR "rpciod: wot no daemon?\n"); - } wake_up(&rpciod_idle); } @@ -261,19 +285,25 @@ __rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task, dprintk("RPC: %4d sleep_on(queue \"%s\" time %ld)\n", task->tk_pid, rpc_qname(q), jiffies); + if (!RPC_IS_ASYNC(task) && !RPC_IS_ACTIVATED(task)) { + printk(KERN_ERR "RPC: Inactive synchronous task put to sleep!\n"); + return; + } + + /* Mark the task as being activated if so needed */ + if (!RPC_IS_ACTIVATED(task)) { + task->tk_active = 1; + task->tk_sleeping = 1; + } + status = __rpc_add_wait_queue(q, task); - if (status) - { + if (status) { printk(KERN_WARNING "RPC: failed to add task to queue: error: %d!\n", status); task->tk_status = status; - task->tk_flags |= RPC_TASK_RUNNING; - } - else - { - task->tk_callback = action; - if (task->tk_timeout) - rpc_add_timer(task, timer); + } else { task->tk_flags &= ~RPC_TASK_RUNNING; + task->tk_callback = action; + __rpc_add_timer(task, timer); } return; @@ -291,6 +321,19 @@ rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task, spin_unlock_bh(&rpc_queue_lock); } +void +rpc_sleep_locked(struct rpc_wait_queue *q, struct rpc_task *task, + rpc_action action, rpc_action timer) +{ + /* + * Protect the queue operations. + */ + spin_lock_bh(&rpc_queue_lock); + __rpc_sleep_on(q, task, action, timer); + rpc_lock_task(task); + spin_unlock_bh(&rpc_queue_lock); +} + /* * Wake up a single task -- must be invoked with spin lock held. * @@ -307,16 +350,33 @@ __rpc_wake_up(struct rpc_task *task) if (task->tk_magic != 0xf00baa) { printk(KERN_ERR "RPC: attempt to wake up non-existing task!\n"); rpc_debug = ~0; + rpc_show_tasks(); return; } #endif - rpc_del_timer(task); + /* Has the task been executed yet? If not, we cannot wake it up! */ + if (!RPC_IS_ACTIVATED(task)) { + printk(KERN_ERR "RPC: Inactive task (%p) being woken up!\n", task); + return; + } + if (RPC_IS_RUNNING(task)) + return; + + __rpc_del_timer(task); + + /* If the task has been locked, then set tk_wakeup so that + * rpc_unlock_task() wakes us up... */ + if (task->tk_lock) { + task->tk_wakeup = 1; + return; + } else + task->tk_wakeup = 0; + if (task->tk_rpcwait != &schedq) __rpc_remove_wait_queue(task); - if (!RPC_IS_RUNNING(task)) { - task->tk_flags |= RPC_TASK_CALLBACK; - rpc_make_runnable(task); - } + task->tk_flags |= RPC_TASK_CALLBACK; + rpc_make_runnable(task); + dprintk("RPC: __rpc_wake_up done\n"); } @@ -338,6 +398,8 @@ __rpc_default_timer(struct rpc_task *task) void rpc_wake_up_task(struct rpc_task *task) { + if (RPC_IS_RUNNING(task)) + return; spin_lock_bh(&rpc_queue_lock); __rpc_wake_up(task); spin_unlock_bh(&rpc_queue_lock); @@ -389,6 +451,30 @@ rpc_wake_up_status(struct rpc_wait_queue *queue, int status) } /* + * Lock down a sleeping task to prevent it from waking up + * and disappearing from beneath us. + * + * This function should always be called with the + * rpc_queue_lock held. + */ +int +rpc_lock_task(struct rpc_task *task) +{ + if (!RPC_IS_RUNNING(task)) + return ++task->tk_lock; + return 0; +} + +void +rpc_unlock_task(struct rpc_task *task) +{ + spin_lock_bh(&rpc_queue_lock); + if (task->tk_lock && !--task->tk_lock && task->tk_wakeup) + __rpc_wake_up(task); + spin_unlock_bh(&rpc_queue_lock); +} + +/* * Run a task at a later time */ static void __rpc_atrun(struct rpc_task *); @@ -426,7 +512,7 @@ __rpc_execute(struct rpc_task *task) /* * Execute any pending callback. */ - if (task->tk_flags & RPC_TASK_CALLBACK) { + if (RPC_DO_CALLBACK(task)) { /* Define a callback save pointer */ void (*save_callback)(struct rpc_task *); @@ -446,101 +532,89 @@ __rpc_execute(struct rpc_task *task) } /* - * No handler for next step means exit. - */ - if (!task->tk_action) - break; - - /* * Perform the next FSM step. * tk_action may be NULL when the task has been killed * by someone else. */ - if (RPC_IS_RUNNING(task) && task->tk_action) + if (RPC_IS_RUNNING(task)) { + if (!task->tk_action) + break; task->tk_action(task); + } /* * Check whether task is sleeping. - * Note that if the task may go to sleep in tk_action, + * Note that if the task goes to sleep in tk_action, * and the RPC reply arrives before we get here, it will * have state RUNNING, but will still be on schedq. + * 27/9/99: The above has been attempted fixed by + * introduction of task->tk_sleeping. */ spin_lock_bh(&rpc_queue_lock); - if (RPC_IS_RUNNING(task)) { - if (task->tk_rpcwait == &schedq) - __rpc_remove_wait_queue(task); - } else while (!RPC_IS_RUNNING(task)) { + if (!RPC_IS_RUNNING(task)) { + task->tk_sleeping = 1; if (RPC_IS_ASYNC(task)) { spin_unlock_bh(&rpc_queue_lock); return 0; } + } else + task->tk_sleeping = 0; + spin_unlock_bh(&rpc_queue_lock); + while (RPC_IS_SLEEPING(task)) { /* sync task: sleep here */ dprintk("RPC: %4d sync task going to sleep\n", task->tk_pid); if (current->pid == rpciod_pid) printk(KERN_ERR "RPC: rpciod waiting on sync task!\n"); - spin_unlock_bh(&rpc_queue_lock); - __wait_event(task->tk_wait, RPC_IS_RUNNING(task)); - spin_lock_bh(&rpc_queue_lock); + __wait_event(task->tk_wait, !RPC_IS_SLEEPING(task)); + dprintk("RPC: %4d sync task resuming\n", task->tk_pid); /* - * When the task received a signal, remove from - * any queues etc, and make runnable again. + * When a sync task receives a signal, it exits with + * -ERESTARTSYS. In order to catch any callbacks that + * clean up after sleeping on some queue, we don't + * break the loop here, but go around once more. */ - if (signalled()) - __rpc_wake_up(task); - - dprintk("RPC: %4d sync task resuming\n", - task->tk_pid); - } - spin_unlock_bh(&rpc_queue_lock); - - /* - * When a sync task receives a signal, it exits with - * -ERESTARTSYS. In order to catch any callbacks that - * clean up after sleeping on some queue, we don't - * break the loop here, but go around once more. - */ - if (!RPC_IS_ASYNC(task) && signalled()) { - dprintk("RPC: %4d got signal\n", task->tk_pid); - rpc_exit(task, -ERESTARTSYS); + if (task->tk_client->cl_intr && signalled()) { + dprintk("RPC: %4d got signal\n", task->tk_pid); + task->tk_flags |= RPC_TASK_KILLED; + rpc_exit(task, -ERESTARTSYS); + rpc_wake_up_task(task); + } } } dprintk("RPC: %4d exit() = %d\n", task->tk_pid, task->tk_status); - if (task->tk_exit) { - status = task->tk_status; + status = task->tk_status; + if (task->tk_exit) task->tk_exit(task); - } return status; } /* * User-visible entry point to the scheduler. - * The recursion protection is for debugging. It should go away once - * the code has stabilized. + * + * This may be called recursively if e.g. an async NFS task updates + * the attributes and finds that dirty pages must be flushed. */ -void +int rpc_execute(struct rpc_task *task) { - static int executing = 0; - int incr = RPC_IS_ASYNC(task)? 1 : 0; - - if (incr) { - if (rpc_inhibit) { - printk(KERN_INFO "RPC: execution inhibited!\n"); - return; - } - if (executing) - printk(KERN_WARNING "RPC: %d tasks executed\n", executing); + if (rpc_inhibit) { + printk(KERN_INFO "RPC: execution inhibited!\n"); + return -EIO; } + task->tk_flags |= RPC_TASK_RUNNING; + if (task->tk_active) { + printk(KERN_ERR "RPC: active task was run twice!\n"); + return -EWOULDBLOCK; + } + task->tk_active = 1; - executing += incr; - __rpc_execute(task); - executing -= incr; + return __rpc_execute(task); } /* @@ -551,28 +625,33 @@ __rpc_schedule(void) { struct rpc_task *task; int count = 0; - int need_resched = current->need_resched; dprintk("RPC: rpc_schedule enter\n"); while (1) { + /* Ensure equal rights for tcp tasks... */ + rpciod_tcp_dispatcher(); + spin_lock_bh(&rpc_queue_lock); if (!(task = schedq.task)) { spin_unlock_bh(&rpc_queue_lock); break; } - rpc_del_timer(task); + if (task->tk_lock) { + spin_unlock_bh(&rpc_queue_lock); + printk(KERN_ERR "RPC: Locked task was scheduled !!!!\n"); + rpc_debug = ~0; + rpc_show_tasks(); + break; + } __rpc_remove_wait_queue(task); - task->tk_flags |= RPC_TASK_RUNNING; spin_unlock_bh(&rpc_queue_lock); __rpc_execute(task); - if (++count >= 200) { + if (++count >= 200 || current->need_resched) { count = 0; - need_resched = 1; - } - if (need_resched) schedule(); + } } dprintk("RPC: rpc_schedule leave\n"); } @@ -646,8 +725,9 @@ rpc_init_task(struct rpc_task *task, struct rpc_clnt *clnt, rpc_action callback, int flags) { memset(task, 0, sizeof(*task)); + init_timer(&task->tk_timer); task->tk_client = clnt; - task->tk_flags = RPC_TASK_RUNNING | flags; + task->tk_flags = flags; task->tk_exit = callback; init_waitqueue_head(&task->tk_wait); if (current->uid != current->fsuid || current->gid != current->fsgid) @@ -717,6 +797,15 @@ rpc_release_task(struct rpc_task *task) dprintk("RPC: %4d release task\n", task->tk_pid); +#ifdef RPC_DEBUG + if (task->tk_magic != 0xf00baa) { + printk(KERN_ERR "RPC: attempt to release a non-existing task!\n"); + rpc_debug = ~0; + rpc_show_tasks(); + return; + } +#endif + /* Remove from global task list */ spin_lock(&rpc_sched_lock); prev = task->tk_prev_task; @@ -734,18 +823,20 @@ rpc_release_task(struct rpc_task *task) spin_lock_bh(&rpc_queue_lock); /* Delete any running timer */ - rpc_del_timer(task); + __rpc_del_timer(task); /* Remove from any wait queue we're still on */ __rpc_remove_wait_queue(task); + task->tk_active = 0; + spin_unlock_bh(&rpc_queue_lock); /* Release resources */ if (task->tk_rqstp) xprt_release(task); - if (task->tk_cred) - rpcauth_releasecred(task); + if (task->tk_msg.rpc_cred) + rpcauth_unbindcred(task); if (task->tk_buffer) { rpc_free(task->tk_buffer); task->tk_buffer = NULL; @@ -824,7 +915,7 @@ rpc_run_child(struct rpc_task *task, struct rpc_task *child, rpc_action func) spin_lock_bh(&rpc_queue_lock); /* N.B. Is it possible for the child to have already finished? */ __rpc_sleep_on(&childq, task, func, NULL); - rpc_make_runnable(child); + rpc_schedule_run(child); spin_unlock_bh(&rpc_queue_lock); } @@ -903,8 +994,6 @@ rpciod(void *ptr) schedule(); rounds = 0; } - dprintk("RPC: rpciod running checking dispatch\n"); - rpciod_tcp_dispatcher(); if (!rpciod_task_pending()) { dprintk("RPC: rpciod back to sleep\n"); @@ -1032,11 +1121,9 @@ out: } #ifdef RPC_DEBUG -#include <linux/nfs_fs.h> void rpc_show_tasks(void) { struct rpc_task *t = all_tasks, *next; - struct nfs_wreq *wreq; spin_lock(&rpc_sched_lock); t = all_tasks; @@ -1049,22 +1136,11 @@ void rpc_show_tasks(void) for (; t; t = next) { next = t->tk_next_task; printk("%05d %04d %04x %06d %8p %6d %8p %08ld %8s %8p %8p\n", - t->tk_pid, t->tk_proc, t->tk_flags, t->tk_status, + t->tk_pid, t->tk_msg.rpc_proc, t->tk_flags, t->tk_status, t->tk_client, t->tk_client->cl_prog, t->tk_rqstp, t->tk_timeout, t->tk_rpcwait ? rpc_qname(t->tk_rpcwait) : " <NULL> ", t->tk_action, t->tk_exit); - - if (!(t->tk_flags & RPC_TASK_NFSWRITE)) - continue; - /* NFS write requests */ - wreq = (struct nfs_wreq *) t->tk_calldata; - printk(" NFS: flgs=%08x, pid=%d, pg=%p, off=(%d, %d)\n", - wreq->wb_flags, wreq->wb_pid, wreq->wb_page, - wreq->wb_offset, wreq->wb_bytes); - printk(" name=%s/%s\n", - wreq->wb_file->f_dentry->d_parent->d_name.name, - wreq->wb_file->f_dentry->d_name.name); } spin_unlock(&rpc_sched_lock); } diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c index 9a1861041..92559fa65 100644 --- a/net/sunrpc/sunrpc_syms.c +++ b/net/sunrpc/sunrpc_syms.c @@ -35,13 +35,16 @@ EXPORT_SYMBOL(rpc_new_child); EXPORT_SYMBOL(rpc_run_child); EXPORT_SYMBOL(rpciod_down); EXPORT_SYMBOL(rpciod_up); +EXPORT_SYMBOL(rpc_new_task); +EXPORT_SYMBOL(rpc_wake_up_status); /* RPC client functions */ EXPORT_SYMBOL(rpc_create_client); EXPORT_SYMBOL(rpc_destroy_client); EXPORT_SYMBOL(rpc_shutdown_client); EXPORT_SYMBOL(rpc_killall_tasks); -EXPORT_SYMBOL(rpc_do_call); +EXPORT_SYMBOL(rpc_call_sync); +EXPORT_SYMBOL(rpc_call_async); EXPORT_SYMBOL(rpc_call_setup); EXPORT_SYMBOL(rpc_clnt_sigmask); EXPORT_SYMBOL(rpc_clnt_sigunmask); @@ -60,6 +63,7 @@ EXPORT_SYMBOL(rpcauth_init_credcache); EXPORT_SYMBOL(rpcauth_free_credcache); EXPORT_SYMBOL(rpcauth_insert_credcache); EXPORT_SYMBOL(rpcauth_lookupcred); +EXPORT_SYMBOL(rpcauth_bindcred); EXPORT_SYMBOL(rpcauth_matchcred); EXPORT_SYMBOL(rpcauth_releasecred); diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 48dd5623d..06d682223 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -68,7 +68,14 @@ /* Following value should be > 32k + RPC overhead */ #define XPRT_MIN_WRITE_SPACE 35000 +extern spinlock_t rpc_queue_lock; + +/* + * Local variables + */ + /* Spinlock for critical sections in the code. */ +spinlock_t xprt_sock_lock = SPIN_LOCK_UNLOCKED; spinlock_t xprt_lock = SPIN_LOCK_UNLOCKED; #ifdef RPC_DEBUG @@ -86,14 +93,12 @@ spinlock_t xprt_lock = SPIN_LOCK_UNLOCKED; */ static void xprt_request_init(struct rpc_task *, struct rpc_xprt *); static void do_xprt_transmit(struct rpc_task *); -static void xprt_transmit_status(struct rpc_task *task); -static void xprt_transmit_timeout(struct rpc_task *task); -static void xprt_receive_status(struct rpc_task *task); static void xprt_reserve_status(struct rpc_task *task); static void xprt_disconnect(struct rpc_xprt *); -static void xprt_reconn_timeout(struct rpc_task *task); -static struct socket *xprt_create_socket(int, struct sockaddr_in *, - struct rpc_timeout *); +static void xprt_reconn_status(struct rpc_task *task); +static struct socket *xprt_create_socket(int, struct rpc_timeout *); +static int xprt_bind_socket(struct rpc_xprt *, struct socket *); +static void xprt_remove_pending(struct rpc_xprt *); #ifdef RPC_DEBUG_DATA /* @@ -140,7 +145,7 @@ xprt_from_sock(struct sock *sk) */ extern inline void -xprt_move_iov(struct msghdr *msg, struct iovec *niv, int amount) +xprt_move_iov(struct msghdr *msg, struct iovec *niv, unsigned amount) { struct iovec *iv=msg->msg_iov; int i; @@ -148,7 +153,7 @@ xprt_move_iov(struct msghdr *msg, struct iovec *niv, int amount) /* * Eat any sent iovecs */ - while(iv->iov_len <= amount) { + while (iv->iov_len <= amount) { amount -= iv->iov_len; iv++; msg->msg_iovlen--; @@ -184,14 +189,17 @@ xprt_sendmsg(struct rpc_xprt *xprt, struct rpc_rqst *req) int slen = req->rq_slen - req->rq_bytes_sent; struct iovec niv[MAX_IOVEC]; - if (slen == 0) + if (slen <= 0) return 0; + if (!sock) + return -ENOTCONN; + xprt_pktdump("packet data:", req->rq_svec->iov_base, req->rq_svec->iov_len); - msg.msg_flags = MSG_DONTWAIT; + msg.msg_flags = MSG_DONTWAIT|MSG_NOSIGNAL; msg.msg_iov = req->rq_svec; msg.msg_iovlen = req->rq_snr; msg.msg_name = (struct sockaddr *) &xprt->addr; @@ -238,23 +246,30 @@ xprt_sendmsg(struct rpc_xprt *xprt, struct rpc_rqst *req) /* * Read data from socket */ -static inline int -xprt_recvmsg(struct rpc_xprt *xprt, struct iovec *iov, int nr, int len) +static int +xprt_recvmsg(struct rpc_xprt *xprt, struct iovec *iov, int nr, unsigned len, unsigned shift) { struct socket *sock = xprt->sock; - struct sockaddr_in sin; struct msghdr msg; mm_segment_t oldfs; + struct iovec niv[MAX_IOVEC]; int result; - msg.msg_flags = MSG_DONTWAIT; + if (!sock) + return -ENOTCONN; + + msg.msg_flags = MSG_DONTWAIT|MSG_NOSIGNAL; msg.msg_iov = iov; msg.msg_iovlen = nr; - msg.msg_name = &sin; - msg.msg_namelen = sizeof(sin); + msg.msg_name = NULL; + msg.msg_namelen = 0; msg.msg_control = NULL; msg.msg_controllen = 0; + /* Adjust the iovec if we've already filled it */ + if (shift) + xprt_move_iov(&msg, niv, shift); + oldfs = get_fs(); set_fs(get_ds()); result = sock_recvmsg(sock, &msg, len, MSG_DONTWAIT); set_fs(oldfs); @@ -309,21 +324,30 @@ xprt_adjust_cwnd(struct rpc_xprt *xprt, int result) int xprt_adjust_timeout(struct rpc_timeout *to) { - if (to->to_exponential) - to->to_current <<= 1; - else - to->to_current += to->to_increment; - if (to->to_maxval && to->to_current >= to->to_maxval) { - to->to_current = to->to_maxval; - to->to_retries = 0; + if (to->to_retries > 0) { + if (to->to_exponential) + to->to_current <<= 1; + else + to->to_current += to->to_increment; + if (to->to_maxval && to->to_current >= to->to_maxval) + to->to_current = to->to_maxval; + } else { + if (to->to_exponential) + to->to_initval <<= 1; + else + to->to_initval += to->to_increment; + if (to->to_maxval && to->to_initval >= to->to_maxval) + to->to_initval = to->to_maxval; + to->to_current = to->to_initval; } + if (!to->to_current) { printk(KERN_WARNING "xprt_adjust_timeout: to_current = 0!\n"); to->to_current = 5 * HZ; } pprintk("RPC: %lu %s\n", jiffies, to->to_retries? "retrans" : "timeout"); - return (to->to_retries)--; + return to->to_retries-- > 0; } /* @@ -332,22 +356,29 @@ xprt_adjust_timeout(struct rpc_timeout *to) static void xprt_close(struct rpc_xprt *xprt) { + struct socket *sock = xprt->sock; struct sock *sk = xprt->inet; - xprt_disconnect(xprt); + if (!sk) + return; + + xprt->inet = NULL; + xprt->sock = NULL; sk->user_data = NULL; sk->data_ready = xprt->old_data_ready; sk->state_change = xprt->old_state_change; sk->write_space = xprt->old_write_space; + + xprt_disconnect(xprt); sk->no_check = 0; - sock_release(xprt->sock); + sock_release(sock); /* * TCP doesnt require the rpciod now - other things may * but rpciod handles that not us. */ - if(xprt->stream && !xprt->connecting) + if(xprt->stream) rpciod_down(); } @@ -360,14 +391,10 @@ xprt_disconnect(struct rpc_xprt *xprt) dprintk("RPC: disconnected transport %p\n", xprt); xprt->connected = 0; xprt->tcp_offset = 0; - xprt->tcp_more = 0; - xprt->tcp_total = 0; - xprt->tcp_reclen = 0; xprt->tcp_copied = 0; - xprt->tcp_rqstp = NULL; - xprt->rx_pending_flag = 0; + xprt->tcp_more = 0; + xprt_remove_pending(xprt); rpc_wake_up_status(&xprt->pending, -ENOTCONN); - rpc_wake_up_status(&xprt->sending, -ENOTCONN); } /* @@ -377,85 +404,87 @@ void xprt_reconnect(struct rpc_task *task) { struct rpc_xprt *xprt = task->tk_xprt; - struct socket *sock; - struct sock *inet; + struct socket *sock = xprt->sock; + struct sock *inet = xprt->inet; int status; dprintk("RPC: %4d xprt_reconnect %p connected %d\n", task->tk_pid, xprt, xprt->connected); - task->tk_status = 0; - if (xprt->shutdown) return; if (!xprt->stream) return; - spin_lock_bh(&xprt_lock); - if (xprt->connected) { - spin_unlock_bh(&xprt_lock); + if (!xprt->addr.sin_port) { + task->tk_status = -EIO; return; } + + spin_lock(&xprt_lock); if (xprt->connecting) { - task->tk_timeout = xprt->timeout.to_maxval; + task->tk_timeout = 0; rpc_sleep_on(&xprt->reconn, task, NULL, NULL); - spin_unlock_bh(&xprt_lock); + spin_unlock(&xprt_lock); return; } xprt->connecting = 1; - spin_unlock_bh(&xprt_lock); + spin_unlock(&xprt_lock); - /* Create an unconnected socket */ - if (!(sock = xprt_create_socket(xprt->prot, NULL, &xprt->timeout))) { - xprt->connecting = 0; - goto defer; + status = -ENOTCONN; + if (!inet) { + /* Create an unconnected socket */ + if (!(sock = xprt_create_socket(xprt->prot, &xprt->timeout))) + goto defer; + xprt_bind_socket(xprt, sock); + inet = sock->sk; } - inet = sock->sk; - inet->data_ready = xprt->inet->data_ready; - inet->state_change = xprt->inet->state_change; - inet->write_space = xprt->inet->write_space; - inet->user_data = xprt; - - dprintk("RPC: %4d closing old socket\n", task->tk_pid); - xprt_close(xprt); - - /* Reset to new socket */ - xprt->sock = sock; - xprt->inet = inet; + xprt_disconnect(xprt); /* Now connect it asynchronously. */ dprintk("RPC: %4d connecting new socket\n", task->tk_pid); status = sock->ops->connect(sock, (struct sockaddr *) &xprt->addr, sizeof(xprt->addr), O_NONBLOCK); - xprt->connecting = 0; if (status < 0) { - if (status != -EINPROGRESS && status != -EALREADY) { + switch (status) { + case -EALREADY: + case -EINPROGRESS: + status = 0; + break; + case -EISCONN: + case -EPIPE: + status = 0; + xprt_close(xprt); + goto defer; + default: printk("RPC: TCP connect error %d!\n", -status); + xprt_close(xprt); goto defer; } dprintk("RPC: %4d connect status %d connected %d\n", task->tk_pid, status, xprt->connected); - task->tk_timeout = 60 * HZ; - spin_lock_bh(&xprt_lock); + spin_lock_bh(&xprt_sock_lock); if (!xprt->connected) { - rpc_sleep_on(&xprt->reconn, task, - NULL, xprt_reconn_timeout); - spin_unlock_bh(&xprt_lock); + task->tk_timeout = xprt->timeout.to_maxval; + rpc_sleep_on(&xprt->reconn, task, xprt_reconn_status, NULL); + spin_unlock_bh(&xprt_sock_lock); return; } - spin_unlock_bh(&xprt_lock); + spin_unlock_bh(&xprt_sock_lock); } - - defer: - spin_lock_bh(&xprt_lock); - if (!xprt->connected) - rpc_wake_up_next(&xprt->reconn); - spin_unlock_bh(&xprt_lock); + spin_lock(&xprt_lock); + xprt->connecting = 0; + if (status < 0) { + rpc_delay(task, 5*HZ); + task->tk_status = -ENOTCONN; + } + rpc_wake_up(&xprt->reconn); + spin_unlock(&xprt_lock); } /* @@ -463,29 +492,21 @@ defer: * process of reconnecting, and leave the rest to the upper layers. */ static void -xprt_reconn_timeout(struct rpc_task *task) +xprt_reconn_status(struct rpc_task *task) { - spin_lock_bh(&xprt_lock); + struct rpc_xprt *xprt = task->tk_xprt; + dprintk("RPC: %4d xprt_reconn_timeout %d\n", task->tk_pid, task->tk_status); - task->tk_status = -ENOTCONN; - if (task->tk_xprt->connecting) - task->tk_xprt->connecting = 0; - if (!task->tk_xprt->connected) - task->tk_status = -ENOTCONN; - else - task->tk_status = -ETIMEDOUT; - task->tk_timeout = 0; - rpc_wake_up_task(task); - spin_unlock_bh(&xprt_lock); + + spin_lock(&xprt_lock); + xprt->connecting = 0; + rpc_wake_up(&xprt->reconn); + spin_unlock(&xprt_lock); } -extern spinlock_t rpc_queue_lock; /* - * Look up the RPC request corresponding to a reply. - * - * RED-PEN: Niiice... Guys, when will we learn finally that locking - * in this manner is NOOP? --ANK + * Look up the RPC request corresponding to a reply, and then lock it. */ static inline struct rpc_rqst * xprt_lookup_rqst(struct rpc_xprt *xprt, u32 xid) @@ -511,6 +532,8 @@ xprt_lookup_rqst(struct rpc_xprt *xprt, u32 xid) out_bad: req = NULL; out: + if (req && !rpc_lock_task(req->rq_task)) + req = NULL; spin_unlock_bh(&rpc_queue_lock); return req; } @@ -524,9 +547,6 @@ xprt_complete_rqst(struct rpc_xprt *xprt, struct rpc_rqst *req, int copied) { struct rpc_task *task = req->rq_task; - req->rq_rlen = copied; - req->rq_gotit = 1; - /* Adjust congestion window */ xprt_adjust_cwnd(xprt, copied); @@ -549,12 +569,11 @@ xprt_complete_rqst(struct rpc_xprt *xprt, struct rpc_rqst *req, int copied) } #endif - /* ... and wake up the process. */ dprintk("RPC: %4d has input (%d bytes)\n", task->tk_pid, copied); task->tk_status = copied; - if (!RPC_IS_RUNNING(task)) - rpc_wake_up_task(task); + /* ... and wake up the process. */ + rpc_wake_up_task(task); return; } @@ -612,6 +631,7 @@ static int csum_partial_copy_to_page_cache(struct iovec *iov, static inline void udp_data_ready(struct sock *sk, int len) { + struct rpc_task *task; struct rpc_xprt *xprt; struct rpc_rqst *rovr; struct sk_buff *skb; @@ -626,7 +646,10 @@ udp_data_ready(struct sock *sk, int len) dprintk("RPC: udp_data_ready client %p\n", xprt); if ((skb = skb_recv_datagram(sk, 0, 1, &err)) == NULL) - goto out_err; + return; + + if (xprt->shutdown) + goto dropit; repsize = skb->len - sizeof(struct udphdr); if (repsize < 4) { @@ -634,14 +657,15 @@ udp_data_ready(struct sock *sk, int len) goto dropit; } - /* Look up the request corresponding to the given XID */ - if (!(rovr = xprt_lookup_rqst(xprt, - *(u32 *) (skb->h.raw + sizeof(struct udphdr))))) + /* Look up and lock the request corresponding to the given XID */ + rovr = xprt_lookup_rqst(xprt, *(u32 *) (skb->h.raw + sizeof(struct udphdr))); + if (!rovr) goto dropit; + task = rovr->rq_task; - dprintk("RPC: %4d received reply\n", rovr->rq_task->tk_pid); + dprintk("RPC: %4d received reply\n", task->tk_pid); xprt_pktdump("packet data:", - (u32 *) (skb->h.raw + sizeof(struct udphdr)), repsize); + (u32 *) (skb->h.raw+sizeof(struct udphdr)), repsize); if ((copied = rovr->rq_rlen) > repsize) copied = repsize; @@ -649,213 +673,287 @@ udp_data_ready(struct sock *sk, int len) rovr->rq_damaged = 1; /* Suck it into the iovec, verify checksum if not done by hw. */ if (csum_partial_copy_to_page_cache(rovr->rq_rvec, skb, copied)) - goto dropit; + goto out_unlock; /* Something worked... */ dst_confirm(skb->dst); xprt_complete_rqst(xprt, rovr, copied); -dropit: + out_unlock: + rpc_unlock_task(task); + + dropit: skb_free_datagram(sk, skb); - return; -out_err: - return; } /* - * TCP record receive routine - * This is not the most efficient code since we call recvfrom twice-- - * first receiving the record marker and XID, then the data. - * - * The optimal solution would be a RPC support in the TCP layer, which - * would gather all data up to the next record marker and then pass us - * the list of all TCP segments ready to be copied. + * TCP read fragment marker */ static inline int -tcp_input_record(struct rpc_xprt *xprt) +tcp_read_fraghdr(struct rpc_xprt *xprt) { - struct rpc_rqst *req; - struct iovec *iov; struct iovec riov; - u32 offset; - int result, maxcpy, reclen, avail, want; + int want, result; - dprintk("RPC: tcp_input_record\n"); + if (xprt->tcp_offset >= xprt->tcp_reclen + sizeof(xprt->tcp_recm)) { + xprt->tcp_offset = 0; + xprt->tcp_reclen = 0; + } + if (xprt->tcp_offset >= sizeof(xprt->tcp_recm)) + goto done; - offset = xprt->tcp_offset; - result = -EAGAIN; - if (offset < 4 || (!xprt->tcp_more && offset < 8)) { - want = (xprt->tcp_more? 4 : 8) - offset; - dprintk("RPC: reading header (%d bytes)\n", want); - riov.iov_base = xprt->tcp_recm.data + offset; + want = sizeof(xprt->tcp_recm) - xprt->tcp_offset; + dprintk("RPC: reading header (%d bytes)\n", want); + do { + riov.iov_base = ((u8*) &xprt->tcp_recm) + xprt->tcp_offset; riov.iov_len = want; - result = xprt_recvmsg(xprt, &riov, 1, want); + result = xprt_recvmsg(xprt, &riov, 1, want, 0); if (result < 0) - goto done; - offset += result; - if (result < want) { - result = -EAGAIN; - goto done; - } + return result; + xprt->tcp_offset += result; + want -= result; + } while (want); - /* Get the record length and mask out the more_fragments bit */ - reclen = ntohl(xprt->tcp_reclen); - dprintk("RPC: reclen %08x\n", reclen); - xprt->tcp_more = (reclen & 0x80000000)? 0 : 1; - reclen &= 0x7fffffff; - xprt->tcp_total += reclen; - xprt->tcp_reclen = reclen; - - dprintk("RPC: got xid %08x reclen %d morefrags %d\n", - xprt->tcp_xid, xprt->tcp_reclen, xprt->tcp_more); - if (!xprt->tcp_copied - && (req = xprt_lookup_rqst(xprt, xprt->tcp_xid))) { - iov = xprt->tcp_iovec; - memcpy(iov, req->rq_rvec, req->rq_rnr * sizeof(iov[0])); -#if 0 -*(u32 *)iov->iov_base = req->rq_xid; -#endif - iov->iov_base += 4; - iov->iov_len -= 4; - xprt->tcp_copied = 4; - xprt->tcp_rqstp = req; - } - } else { - reclen = xprt->tcp_reclen; - } + /* Is this another fragment in the last message */ + if (!xprt->tcp_more) + xprt->tcp_copied = 0; /* No, so we're reading a new message */ + + /* Get the record length and mask out the last fragment bit */ + xprt->tcp_reclen = ntohl(xprt->tcp_recm); + xprt->tcp_more = (xprt->tcp_reclen & 0x80000000) ? 0 : 1; + xprt->tcp_reclen &= 0x7fffffff; + + dprintk("RPC: New record reclen %d morefrags %d\n", + xprt->tcp_reclen, xprt->tcp_more); + done: + return xprt->tcp_reclen + sizeof(xprt->tcp_recm) - xprt->tcp_offset; +} + +/* + * TCP read xid + */ +static inline int +tcp_read_xid(struct rpc_xprt *xprt, int avail) +{ + struct iovec riov; + int want, result; + + if (xprt->tcp_copied >= sizeof(xprt->tcp_xid) || !avail) + goto done; + want = MIN(sizeof(xprt->tcp_xid) - xprt->tcp_copied, avail); + do { + dprintk("RPC: reading xid (%d bytes)\n", want); + riov.iov_base = ((u8*) &xprt->tcp_xid) + xprt->tcp_copied; + riov.iov_len = want; + result = xprt_recvmsg(xprt, &riov, 1, want, 0); + if (result < 0) + return result; + xprt->tcp_copied += result; + xprt->tcp_offset += result; + want -= result; + avail -= result; + } while (want); + done: + return avail; +} - avail = reclen - (offset - 4); - if ((req = xprt->tcp_rqstp) && req->rq_xid == xprt->tcp_xid - && req->rq_task->tk_rpcwait == &xprt->pending) { - want = MIN(req->rq_rlen - xprt->tcp_copied, avail); +/* + * TCP read and complete request + */ +static inline int +tcp_read_request(struct rpc_xprt *xprt, struct rpc_rqst *req, int avail) +{ + int want, result; + if (req->rq_rlen <= xprt->tcp_copied || !avail) + goto done; + want = MIN(req->rq_rlen - xprt->tcp_copied, avail); + do { dprintk("RPC: %4d TCP receiving %d bytes\n", - req->rq_task->tk_pid, want); - /* Request must be re-encoded before retransmit */ - req->rq_damaged = 1; - result = xprt_recvmsg(xprt, xprt->tcp_iovec, req->rq_rnr, want); + req->rq_task->tk_pid, want); + + result = xprt_recvmsg(xprt, req->rq_rvec, req->rq_rnr, want, xprt->tcp_copied); if (result < 0) - goto done; + return result; xprt->tcp_copied += result; - offset += result; + xprt->tcp_offset += result; avail -= result; - if (result < want) { - result = -EAGAIN; - goto done; - } + want -= result; + } while (want); - maxcpy = MIN(req->rq_rlen, xprt->tcp_total); - if (xprt->tcp_copied == maxcpy && !xprt->tcp_more) { - dprintk("RPC: %4d received reply complete\n", - req->rq_task->tk_pid); - xprt_complete_rqst(xprt, req, xprt->tcp_total); - xprt->tcp_copied = 0; - xprt->tcp_rqstp = NULL; - } - } + done: + if (req->rq_rlen > xprt->tcp_copied && xprt->tcp_more) + return avail; + dprintk("RPC: %4d received reply complete\n", req->rq_task->tk_pid); + xprt_complete_rqst(xprt, req, xprt->tcp_copied); - /* Skip over any trailing bytes on short reads */ - while (avail > 0) { - static u8 dummy[64]; + return avail; +} +/* + * TCP discard extra bytes from a short read + */ +static inline int +tcp_read_discard(struct rpc_xprt *xprt, int avail) +{ + struct iovec riov; + static u8 dummy[64]; + int want, result = 0; + + while (avail) { want = MIN(avail, sizeof(dummy)); riov.iov_base = dummy; riov.iov_len = want; dprintk("RPC: TCP skipping %d bytes\n", want); - result = xprt_recvmsg(xprt, &riov, 1, want); + result = xprt_recvmsg(xprt, &riov, 1, want, 0); if (result < 0) - goto done; - offset += result; + return result; + xprt->tcp_offset += result; avail -= result; - if (result < want) { - result = -EAGAIN; - goto done; + } + return avail; +} + +/* + * TCP record receive routine + * This is not the most efficient code since we call recvfrom thrice-- + * first receiving the record marker, then the XID, then the data. + * + * The optimal solution would be a RPC support in the TCP layer, which + * would gather all data up to the next record marker and then pass us + * the list of all TCP segments ready to be copied. + */ +static int +tcp_input_record(struct rpc_xprt *xprt) +{ + struct rpc_rqst *req = NULL; + struct rpc_task *task = NULL; + int avail, result; + + dprintk("RPC: tcp_input_record\n"); + + if (xprt->shutdown) + return -EIO; + if (!xprt->connected) + return -ENOTCONN; + + /* Read in a new fragment marker if necessary */ + /* Can we ever really expect to get completely empty fragments? */ + if ((result = tcp_read_fraghdr(xprt)) <= 0) + return result; + avail = result; + + /* Read in the xid if necessary */ + if ((result = tcp_read_xid(xprt, avail)) <= 0) + return result; + avail = result; + + /* Find and lock the request corresponding to this xid */ + req = xprt_lookup_rqst(xprt, xprt->tcp_xid); + if (req) { + task = req->rq_task; + if (xprt->tcp_copied == sizeof(xprt->tcp_xid) || req->rq_damaged) { + req->rq_damaged = 1; + /* Read in the request data */ + result = tcp_read_request(xprt, req, avail); } + rpc_unlock_task(task); + if (result < 0) + return result; + avail = result; } - if (!xprt->tcp_more) - xprt->tcp_total = 0; - offset = 0; -done: - dprintk("RPC: tcp_input_record done (off %d total %d copied %d)\n", - offset, xprt->tcp_total, xprt->tcp_copied); - xprt->tcp_offset = offset; + /* Skip over any trailing bytes on short reads */ + if ((result = tcp_read_discard(xprt, avail)) < 0) + return result; + + dprintk("RPC: tcp_input_record done (off %d reclen %d copied %d)\n", + xprt->tcp_offset, xprt->tcp_reclen, xprt->tcp_copied); + result = xprt->tcp_reclen; return result; } /* * TCP task queue stuff */ - -static struct rpc_xprt *rpc_xprt_pending = NULL; /* Chain by rx_pending of rpc_xprt's */ +LIST_HEAD(rpc_xprt_pending); /* List of xprts having pending tcp requests */ + +static inline +void tcp_rpciod_queue(void) +{ + rpciod_wake_up(); +} + +static inline +void xprt_append_pending(struct rpc_xprt *xprt) +{ + if (!list_empty(&xprt->rx_pending)) + return; + spin_lock_bh(&rpc_queue_lock); + if (list_empty(&xprt->rx_pending)) { + list_add(&xprt->rx_pending, rpc_xprt_pending.prev); + dprintk("RPC: xprt queue %p\n", xprt); + tcp_rpciod_queue(); + } + spin_unlock_bh(&rpc_queue_lock); +} + +static +void xprt_remove_pending(struct rpc_xprt *xprt) +{ + spin_lock_bh(&rpc_queue_lock); + if (!list_empty(&xprt->rx_pending)) { + list_del(&xprt->rx_pending); + INIT_LIST_HEAD(&xprt->rx_pending); + } + spin_unlock_bh(&rpc_queue_lock); +} + +static inline +struct rpc_xprt *xprt_remove_pending_next(void) +{ + struct rpc_xprt *xprt = NULL; + + spin_lock_bh(&rpc_queue_lock); + if (!list_empty(&rpc_xprt_pending)) { + xprt = list_entry(rpc_xprt_pending.next, struct rpc_xprt, rx_pending); + list_del(&xprt->rx_pending); + INIT_LIST_HEAD(&xprt->rx_pending); + } + spin_unlock_bh(&rpc_queue_lock); + return xprt; +} /* * This is protected from tcp_data_ready and the stack as its run * inside of the RPC I/O daemon */ -static void -do_rpciod_tcp_dispatcher(void) +void +__rpciod_tcp_dispatcher(void) { struct rpc_xprt *xprt; - int result = 0; + int safe_retry = 0, result; dprintk("rpciod_tcp_dispatcher: Queue Running\n"); /* * Empty each pending socket */ - - while(1) { - int safe_retry=0; - - if ((xprt = rpc_xprt_pending) == NULL) { - break; - } - xprt->rx_pending_flag = 0; - rpc_xprt_pending=xprt->rx_pending; - xprt->rx_pending = NULL; - + while ((xprt = xprt_remove_pending_next()) != NULL) { dprintk("rpciod_tcp_dispatcher: Processing %p\n", xprt); - do - { - if (safe_retry++ > 50) - break; + do { result = tcp_input_record(xprt); - } - while (result >= 0); - - switch (result) { - case -EAGAIN: - case -ENOTCONN: - case -EPIPE: - continue; - default: - printk(KERN_WARNING "RPC: unexpected error %d from tcp_input_record\n", - result); + } while (result >= 0); + + if (safe_retry++ > 200) { + schedule(); + safe_retry = 0; } } } -void rpciod_tcp_dispatcher(void) -{ - /* mama... start_bh_atomic was here... - Calls to sock->ops _are_ _impossible_ with disabled bh. Period. --ANK - */ - do_rpciod_tcp_dispatcher(); -} - -int xprt_tcp_pending(void) -{ - return rpc_xprt_pending != NULL; -} - -extern inline void tcp_rpciod_queue(void) -{ - rpciod_wake_up(); -} - /* * data_ready callback for TCP. We can't just jump into the * tcp recvmsg functions inside of the network receive bh or @@ -874,24 +972,15 @@ static void tcp_data_ready(struct sock *sk, int len) return; } + if (xprt->shutdown) + return; + + xprt_append_pending(xprt); + dprintk("RPC: tcp_data_ready client %p\n", xprt); dprintk("RPC: state %x conn %d dead %d zapped %d\n", sk->state, xprt->connected, sk->dead, sk->zapped); - /* - * If we are not waiting for the RPC bh run then - * we are now - */ - if (!xprt->rx_pending_flag) { - dprintk("RPC: xprt queue %p\n", rpc_xprt_pending); - - xprt->rx_pending=rpc_xprt_pending; - rpc_xprt_pending=xprt; - xprt->rx_pending_flag=1; - } else - dprintk("RPC: xprt queued already %p\n", xprt); - tcp_rpciod_queue(); - } @@ -907,26 +996,20 @@ tcp_state_change(struct sock *sk) sk->state, xprt->connected, sk->dead, sk->zapped); - switch(sk->state) { + spin_lock_bh(&xprt_sock_lock); + switch (sk->state) { case TCP_ESTABLISHED: - if (xprt->connected) - break; xprt->connected = 1; - xprt->connecting = 0; + if (xprt->snd_task && xprt->snd_task->tk_rpcwait == &xprt->sending) + rpc_wake_up_task(xprt->snd_task); rpc_wake_up(&xprt->reconn); - rpc_wake_up_next(&xprt->sending); - tcp_rpciod_queue(); - break; - case TCP_CLOSE: - if (xprt->connecting) - break; - xprt_disconnect(xprt); - rpc_wake_up_status(&xprt->reconn, -ENOTCONN); break; default: + xprt->connected = 0; + rpc_wake_up_status(&xprt->pending, -ENOTCONN); break; } - + spin_unlock_bh(&xprt_sock_lock); } /* @@ -940,20 +1023,23 @@ tcp_write_space(struct sock *sk) if (!(xprt = xprt_from_sock(sk))) return; + if (xprt->shutdown) + return; /* Wait until we have enough socket memory */ if (sock_wspace(sk) < min(sk->sndbuf,XPRT_MIN_WRITE_SPACE)) return; + spin_lock_bh(&xprt_sock_lock); if (xprt->write_space) - return; + goto out_unlock; xprt->write_space = 1; - if (!xprt->snd_task) - rpc_wake_up_next(&xprt->sending); - else if (!RPC_IS_RUNNING(xprt->snd_task)) + if (xprt->snd_task && xprt->snd_task->tk_rpcwait == &xprt->sending) rpc_wake_up_task(xprt->snd_task); + out_unlock: + spin_unlock_bh(&xprt_sock_lock); } static void @@ -963,20 +1049,24 @@ udp_write_space(struct sock *sk) if (!(xprt = xprt_from_sock(sk))) return; + if (xprt->shutdown) + return; /* Wait until we have enough socket memory */ if (sock_wspace(sk) < min(sk->sndbuf,XPRT_MIN_WRITE_SPACE)) return; + spin_lock_bh(&xprt_sock_lock); if (xprt->write_space) - return; + goto out_unlock; xprt->write_space = 1; - if (!xprt->snd_task) - rpc_wake_up_next(&xprt->sending); - else if (!RPC_IS_RUNNING(xprt->snd_task)) + + if (xprt->snd_task && xprt->snd_task->tk_rpcwait == &xprt->sending) rpc_wake_up_task(xprt->snd_task); + out_unlock: + spin_unlock_bh(&xprt_sock_lock); } /* @@ -987,9 +1077,8 @@ xprt_timer(struct rpc_task *task) { struct rpc_rqst *req = task->tk_rqstp; - if (req) { + if (req) xprt_adjust_cwnd(task->tk_xprt, -ETIMEDOUT); - } dprintk("RPC: %4d xprt_timer (%s request)\n", task->tk_pid, req ? "pending" : "backlogged"); @@ -1010,12 +1099,13 @@ xprt_down_transmit(struct rpc_task *task) struct rpc_xprt *xprt = task->tk_rqstp->rq_xprt; struct rpc_rqst *req = task->tk_rqstp; - spin_lock_bh(&xprt_lock); + spin_lock(&xprt_lock); if (xprt->snd_task && xprt->snd_task != task) { dprintk("RPC: %4d TCP write queue full (task %d)\n", task->tk_pid, xprt->snd_task->tk_pid); - task->tk_timeout = req->rq_timeout.to_current; - rpc_sleep_on(&xprt->sending, task, xprt_transmit, NULL); + task->tk_timeout = 0; + task->tk_status = -EAGAIN; + rpc_sleep_on(&xprt->sending, task, NULL, NULL); } else if (!xprt->snd_task) { xprt->snd_task = task; #ifdef RPC_PROFILE @@ -1023,23 +1113,23 @@ xprt_down_transmit(struct rpc_task *task) #endif req->rq_bytes_sent = 0; } - spin_unlock_bh(&xprt_lock); + spin_unlock(&xprt_lock); return xprt->snd_task == task; } /* * Releases the socket for use by other requests. */ -static void +static inline void xprt_up_transmit(struct rpc_task *task) { struct rpc_xprt *xprt = task->tk_rqstp->rq_xprt; if (xprt->snd_task && xprt->snd_task == task) { - spin_lock_bh(&xprt_lock); + spin_lock(&xprt_lock); xprt->snd_task = NULL; rpc_wake_up_next(&xprt->sending); - spin_unlock_bh(&xprt_lock); + spin_unlock(&xprt_lock); } } @@ -1050,7 +1140,6 @@ xprt_up_transmit(struct rpc_task *task) void xprt_transmit(struct rpc_task *task) { - struct rpc_timeout *timeo; struct rpc_rqst *req = task->tk_rqstp; struct rpc_xprt *xprt = req->rq_xprt; @@ -1060,26 +1149,21 @@ xprt_transmit(struct rpc_task *task) if (xprt->shutdown) task->tk_status = -EIO; + if (!xprt->connected) + task->tk_status = -ENOTCONN; + if (task->tk_status < 0) return; - /* Reset timeout parameters */ - timeo = &req->rq_timeout; - if (timeo->to_retries < 0) { - dprintk("RPC: %4d xprt_transmit reset timeo\n", - task->tk_pid); - timeo->to_retries = xprt->timeout.to_retries; - timeo->to_current = timeo->to_initval; - } + if (task->tk_rpcwait) + rpc_remove_wait_queue(task); /* set up everything as needed. */ /* Write the record marker */ if (xprt->stream) { - u32 marker; - - marker = htonl(0x80000000|(req->rq_slen-4)); - *((u32 *) req->rq_svec[0].iov_base) = marker; + u32 *marker = req->rq_svec[0].iov_base; + *marker = htonl(0x80000000|(req->rq_slen-sizeof(*marker))); } if (!xprt_down_transmit(task)) @@ -1095,24 +1179,14 @@ do_xprt_transmit(struct rpc_task *task) struct rpc_xprt *xprt = req->rq_xprt; int status, retry = 0; - if (xprt->shutdown) { - task->tk_status = -EIO; - goto out_release; - } /* For fast networks/servers we have to put the request on * the pending list now: + * Note that we don't want the task timing out during the + * call to xprt_sendmsg(), so we initially disable the timeout, + * and then reset it later... */ - req->rq_gotit = 0; - status = rpc_add_wait_queue(&xprt->pending, task); - if (!status) - task->tk_callback = NULL; - - if (status) { - printk(KERN_WARNING "RPC: failed to add task to queue: error: %d!\n", status); - task->tk_status = status; - goto out_release; - } + xprt_receive(task); /* Continue transmitting the packet/record. We must be careful * to cope with writespace callbacks arriving _after_ we have @@ -1129,80 +1203,67 @@ do_xprt_transmit(struct rpc_task *task) req->rq_bytes_sent += status; if (req->rq_bytes_sent >= req->rq_slen) - goto out_release; - } - - if (status < req->rq_slen) - status = -EAGAIN; - - if (status >= 0 || !xprt->stream) { - dprintk("RPC: %4d xmit complete\n", task->tk_pid); - goto out_release; + goto out_receive; + } else { + if (status >= req->rq_slen) + goto out_receive; + status = -ENOMEM; + break; } dprintk("RPC: %4d xmit incomplete (%d left of %d)\n", task->tk_pid, req->rq_slen - req->rq_bytes_sent, req->rq_slen); + status = -EAGAIN; if (retry++ > 50) break; } + rpc_unlock_task(task); - task->tk_status = (status == -ENOMEM) ? -EAGAIN : status; + task->tk_status = status; - /* We don't care if we got a reply, so don't protect - * against bh. */ - if (task->tk_rpcwait == &xprt->pending) - rpc_remove_wait_queue(task); + /* Note: at this point, task->tk_sleeping has not yet been set, + * hence there is no danger of the waking up task being put on + * schedq, and being picked up by a parallel run of rpciod(). + */ + rpc_wake_up_task(task); + if (!RPC_IS_RUNNING(task)) + goto out_release; - /* Protect against (udp|tcp)_write_space */ - spin_lock_bh(&xprt_lock); - if (status == -ENOMEM || status == -EAGAIN) { + switch (status) { + case -ENOMEM: + /* Protect against (udp|tcp)_write_space */ task->tk_timeout = req->rq_timeout.to_current; + spin_lock_bh(&xprt_sock_lock); if (!xprt->write_space) - rpc_sleep_on(&xprt->sending, task, xprt_transmit_status, - xprt_transmit_timeout); - spin_unlock_bh(&xprt_lock); + rpc_sleep_on(&xprt->sending, task, NULL, NULL); + spin_unlock_bh(&xprt_sock_lock); return; - } - spin_unlock_bh(&xprt_lock); - -out_release: - xprt_up_transmit(task); -} - -/* - * This callback is invoked when the sending task is forced to sleep - * because the TCP write buffers are full - */ -static void -xprt_transmit_status(struct rpc_task *task) -{ - struct rpc_xprt *xprt = task->tk_client->cl_xprt; - - dprintk("RPC: %4d transmit_status %d\n", task->tk_pid, task->tk_status); - if (xprt->snd_task == task) { - task->tk_status = 0; - do_xprt_transmit(task); + case -EAGAIN: + /* Keep holding the socket if it is blocked */ + rpc_delay(task, HZ>>4); return; + case -ECONNREFUSED: + case -ENOTCONN: + if (!xprt->stream) + return; + default: + goto out_release; } -} -/* - * RPC transmit timeout handler. - */ -static void -xprt_transmit_timeout(struct rpc_task *task) -{ - dprintk("RPC: %4d transmit_timeout %d\n", task->tk_pid, task->tk_status); - task->tk_status = -ETIMEDOUT; - task->tk_timeout = 0; - rpc_wake_up_task(task); + out_receive: + dprintk("RPC: %4d xmit complete\n", task->tk_pid); + /* Set the task's receive timeout value */ + task->tk_timeout = req->rq_timeout.to_current; + rpc_add_timer(task, xprt_timer); + rpc_unlock_task(task); + out_release: xprt_up_transmit(task); } /* - * Wait for the reply to our call. + * Queue the task for a reply to our call. * When the callback is invoked, the congestion window should have * been updated already. */ @@ -1214,42 +1275,8 @@ xprt_receive(struct rpc_task *task) dprintk("RPC: %4d xprt_receive\n", task->tk_pid); - /* - * Wait until rq_gotit goes non-null, or timeout elapsed. - */ - task->tk_timeout = req->rq_timeout.to_current; - - spin_lock_bh(&xprt_lock); - if (task->tk_rpcwait) - rpc_remove_wait_queue(task); - - if (task->tk_status < 0 || xprt->shutdown) { - spin_unlock_bh(&xprt_lock); - goto out; - } - - if (!req->rq_gotit) { - rpc_sleep_on(&xprt->pending, task, - xprt_receive_status, xprt_timer); - spin_unlock_bh(&xprt_lock); - return; - } - spin_unlock_bh(&xprt_lock); - - dprintk("RPC: %4d xprt_receive returns %d\n", - task->tk_pid, task->tk_status); - out: - xprt_receive_status(task); -} - -static void -xprt_receive_status(struct rpc_task *task) -{ - struct rpc_xprt *xprt = task->tk_xprt; - - if (xprt->tcp_rqstp == task->tk_rqstp) - xprt->tcp_rqstp = NULL; - + task->tk_timeout = 0; + rpc_sleep_locked(&xprt->pending, task, NULL, NULL); } /* @@ -1335,7 +1362,6 @@ xprt_request_init(struct rpc_task *task, struct rpc_xprt *xprt) dprintk("RPC: %4d reserved req %p xid %08x\n", task->tk_pid, req, xid); task->tk_status = 0; - req->rq_gotit = 0; req->rq_timeout = xprt->timeout; req->rq_task = task; req->rq_xprt = xprt; @@ -1353,6 +1379,7 @@ xprt_release(struct rpc_task *task) struct rpc_xprt *xprt = task->tk_xprt; struct rpc_rqst *req; + xprt_up_transmit(task); if (!(req = task->tk_rqstp)) return; task->tk_rqstp = NULL; @@ -1363,16 +1390,16 @@ xprt_release(struct rpc_task *task) spin_lock(&xprt_lock); req->rq_next = xprt->free; xprt->free = req; - spin_unlock(&xprt_lock); /* remove slot from queue of pending */ - spin_lock_bh(&xprt_lock); if (task->tk_rpcwait) { printk("RPC: task of released request still queued!\n"); - rpc_del_timer(task); +#ifdef RPC_DEBUG + printk("RPC: (task is on %s)\n", rpc_qname(task->tk_rpcwait)); +#endif rpc_remove_wait_queue(task); } - spin_unlock_bh(&xprt_lock); + spin_unlock(&xprt_lock); /* Decrease congestion value. */ xprt->cong -= RPC_CWNDSCALE; @@ -1389,7 +1416,7 @@ xprt_default_timeout(struct rpc_timeout *to, int proto) if (proto == IPPROTO_UDP) xprt_set_timeout(to, 5, 5 * HZ); else - xprt_set_timeout(to, 5, 15 * HZ); + xprt_set_timeout(to, 5, 60 * HZ); } /* @@ -1416,52 +1443,33 @@ xprt_setup(struct socket *sock, int proto, { struct rpc_xprt *xprt; struct rpc_rqst *req; - struct sock *inet; int i; dprintk("RPC: setting up %s transport...\n", proto == IPPROTO_UDP? "UDP" : "TCP"); - inet = sock->sk; - if ((xprt = kmalloc(sizeof(struct rpc_xprt), GFP_KERNEL)) == NULL) return NULL; memset(xprt, 0, sizeof(*xprt)); /* Nnnngh! */ - xprt->file = NULL; - xprt->sock = sock; - xprt->inet = inet; xprt->addr = *ap; xprt->prot = proto; xprt->stream = (proto == IPPROTO_TCP)? 1 : 0; - xprt->congtime = jiffies; - init_waitqueue_head(&xprt->cong_wait); - inet->user_data = xprt; - xprt->old_data_ready = inet->data_ready; - xprt->old_state_change = inet->state_change; - xprt->old_write_space = inet->write_space; - if (proto == IPPROTO_UDP) { - inet->data_ready = udp_data_ready; - inet->write_space = udp_write_space; - inet->no_check = UDP_CSUM_NORCV; - xprt->cwnd = RPC_INITCWND; - } else { - inet->data_ready = tcp_data_ready; - inet->state_change = tcp_state_change; - inet->write_space = tcp_write_space; + if (xprt->stream) { xprt->cwnd = RPC_MAXCWND; xprt->nocong = 1; - } - xprt->connected = 1; + } else + xprt->cwnd = RPC_INITCWND; + xprt->congtime = jiffies; + init_waitqueue_head(&xprt->cong_wait); /* Set timeout parameters */ if (to) { xprt->timeout = *to; xprt->timeout.to_current = to->to_initval; xprt->timeout.to_resrvval = to->to_maxval << 1; - } else { + } else xprt_default_timeout(&xprt->timeout, xprt->prot); - } xprt->pending = RPC_INIT_WAITQ("xprt_pending"); xprt->sending = RPC_INIT_WAITQ("xprt_sending"); @@ -1474,13 +1482,11 @@ xprt_setup(struct socket *sock, int proto, req->rq_next = NULL; xprt->free = xprt->slot; + INIT_LIST_HEAD(&xprt->rx_pending); + dprintk("RPC: created transport %p\n", xprt); - /* - * TCP requires the rpc I/O daemon is present - */ - if(proto==IPPROTO_TCP) - rpciod_up(); + xprt_bind_socket(xprt, sock); return xprt; } @@ -1508,17 +1514,52 @@ xprt_bindresvport(struct socket *sock) return err; } +static int +xprt_bind_socket(struct rpc_xprt *xprt, struct socket *sock) +{ + struct sock *sk = sock->sk; + + if (xprt->inet) + return -EBUSY; + + sk->user_data = xprt; + xprt->old_data_ready = sk->data_ready; + xprt->old_state_change = sk->state_change; + xprt->old_write_space = sk->write_space; + if (xprt->prot == IPPROTO_UDP) { + sk->data_ready = udp_data_ready; + sk->write_space = udp_write_space; + sk->no_check = UDP_CSUM_NORCV; + xprt->connected = 1; + } else { + sk->data_ready = tcp_data_ready; + sk->state_change = tcp_state_change; + sk->write_space = tcp_write_space; + xprt->connected = 0; + } + + /* Reset to new socket */ + xprt->sock = sock; + xprt->inet = sk; + /* + * TCP requires the rpc I/O daemon is present + */ + if(xprt->stream) + rpciod_up(); + + return 0; +} + /* * Create a client socket given the protocol and peer address. */ static struct socket * -xprt_create_socket(int proto, struct sockaddr_in *sap, struct rpc_timeout *to) +xprt_create_socket(int proto, struct rpc_timeout *to) { struct socket *sock; int type, err; - dprintk("RPC: xprt_create_socket(%08x, %s %d)\n", - sap? ntohl(sap->sin_addr.s_addr) : 0, + dprintk("RPC: xprt_create_socket(%s %d)\n", (proto == IPPROTO_UDP)? "udp" : "tcp", proto); type = (proto == IPPROTO_UDP)? SOCK_DGRAM : SOCK_STREAM; @@ -1532,15 +1573,6 @@ xprt_create_socket(int proto, struct sockaddr_in *sap, struct rpc_timeout *to) if (!current->fsuid && xprt_bindresvport(sock) < 0) goto failed; - if (type == SOCK_STREAM && sap) { - err = sock->ops->connect(sock, (struct sockaddr *) sap, - sizeof(*sap), 0); - if (err < 0) { - printk("RPC: TCP connect failed (%d).\n", -err); - goto failed; - } - } - return sock; failed: @@ -1559,7 +1591,7 @@ xprt_create_proto(int proto, struct sockaddr_in *sap, struct rpc_timeout *to) dprintk("RPC: xprt_create_proto called\n"); - if (!(sock = xprt_create_socket(proto, sap, to))) + if (!(sock = xprt_create_socket(proto, to))) return NULL; if (!(xprt = xprt_setup(sock, proto, sap, to))) @@ -1587,8 +1619,6 @@ xprt_shutdown(struct rpc_xprt *xprt) */ int xprt_clear_backlog(struct rpc_xprt *xprt) { - if (!xprt) - return 0; if (RPCXPRT_CONGESTED(xprt)) return 0; rpc_wake_up_next(&xprt->backlog); @@ -1603,6 +1633,7 @@ int xprt_destroy(struct rpc_xprt *xprt) { dprintk("RPC: destroying transport %p\n", xprt); + xprt_shutdown(xprt); xprt_close(xprt); kfree(xprt); |