nfsd: track last inode only in use_wgather case
[safe/jmp/linux-2.6] / net / netrom / af_netrom.c
index 053fa26..3be0e01 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
 #include <linux/skbuff.h>
+#include <net/net_namespace.h>
 #include <net/sock.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -72,6 +73,20 @@ static const struct proto_ops nr_proto_ops;
  * separate class since they always nest.
  */
 static struct lock_class_key nr_netdev_xmit_lock_key;
+static struct lock_class_key nr_netdev_addr_lock_key;
+
+static void nr_set_lockdep_one(struct net_device *dev,
+                              struct netdev_queue *txq,
+                              void *_unused)
+{
+       lockdep_set_class(&txq->_xmit_lock, &nr_netdev_xmit_lock_key);
+}
+
+static void nr_set_lockdep_key(struct net_device *dev)
+{
+       lockdep_set_class(&dev->addr_list_lock, &nr_netdev_addr_lock_key);
+       netdev_for_each_tx_queue(dev, nr_set_lockdep_one, NULL);
+}
 
 /*
  *     Socket removal during an interrupt is now safe.
@@ -105,6 +120,9 @@ static int nr_device_event(struct notifier_block *this, unsigned long event, voi
 {
        struct net_device *dev = (struct net_device *)ptr;
 
+       if (!net_eq(dev_net(dev), &init_net))
+               return NOTIFY_DONE;
+
        if (event != NETDEV_DOWN)
                return NOTIFY_DONE;
 
@@ -408,15 +426,19 @@ static struct proto nr_proto = {
        .obj_size = sizeof(struct nr_sock),
 };
 
-static int nr_create(struct socket *sock, int protocol)
+static int nr_create(struct net *net, struct socket *sock, int protocol)
 {
        struct sock *sk;
        struct nr_sock *nr;
 
+       if (net != &init_net)
+               return -EAFNOSUPPORT;
+
        if (sock->type != SOCK_SEQPACKET || protocol != 0)
                return -ESOCKTNOSUPPORT;
 
-       if ((sk = sk_alloc(PF_NETROM, GFP_ATOMIC, &nr_proto, 1)) == NULL)
+       sk = sk_alloc(net, PF_NETROM, GFP_ATOMIC, &nr_proto);
+       if (sk  == NULL)
                return -ENOMEM;
 
        nr = nr_sk(sk);
@@ -458,7 +480,8 @@ static struct sock *nr_make_new(struct sock *osk)
        if (osk->sk_type != SOCK_SEQPACKET)
                return NULL;
 
-       if ((sk = sk_alloc(PF_NETROM, GFP_ATOMIC, osk->sk_prot, 1)) == NULL)
+       sk = sk_alloc(sock_net(osk), PF_NETROM, GFP_ATOMIC, osk->sk_prot);
+       if (sk == NULL)
                return NULL;
 
        nr = nr_sk(sk);
@@ -466,13 +489,11 @@ static struct sock *nr_make_new(struct sock *osk)
        sock_init_data(NULL, sk);
 
        sk->sk_type     = osk->sk_type;
-       sk->sk_socket   = osk->sk_socket;
        sk->sk_priority = osk->sk_priority;
        sk->sk_protocol = osk->sk_protocol;
        sk->sk_rcvbuf   = osk->sk_rcvbuf;
        sk->sk_sndbuf   = osk->sk_sndbuf;
        sk->sk_state    = TCP_ESTABLISHED;
-       sk->sk_sleep    = osk->sk_sleep;
        sock_copy_flags(sk, osk);
 
        skb_queue_head_init(&nr->ack_queue);
@@ -504,6 +525,7 @@ static int nr_release(struct socket *sock)
        if (sk == NULL) return 0;
 
        sock_hold(sk);
+       sock_orphan(sk);
        lock_sock(sk);
        nr = nr_sk(sk);
 
@@ -527,13 +549,10 @@ static int nr_release(struct socket *sock)
                sk->sk_state    = TCP_CLOSE;
                sk->sk_shutdown |= SEND_SHUTDOWN;
                sk->sk_state_change(sk);
-               sock_orphan(sk);
                sock_set_flag(sk, SOCK_DESTROY);
-               sk->sk_socket   = NULL;
                break;
 
        default:
-               sk->sk_socket = NULL;
                break;
        }
 
@@ -590,7 +609,7 @@ static int nr_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
        } else {
                source = &addr->fsa_ax25.sax25_call;
 
-               user = ax25_findbyuid(current->euid);
+               user = ax25_findbyuid(current_euid());
                if (user) {
                        nr->user_addr   = user->call;
                        ax25_uid_put(user);
@@ -625,54 +644,54 @@ static int nr_connect(struct socket *sock, struct sockaddr *uaddr,
        ax25_address *source = NULL;
        ax25_uid_assoc *user;
        struct net_device *dev;
+       int err = 0;
 
        lock_sock(sk);
        if (sk->sk_state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) {
                sock->state = SS_CONNECTED;
-               release_sock(sk);
-               return 0;       /* Connect completed during a ERESTARTSYS event */
+               goto out_release;       /* Connect completed during a ERESTARTSYS event */
        }
 
        if (sk->sk_state == TCP_CLOSE && sock->state == SS_CONNECTING) {
                sock->state = SS_UNCONNECTED;
-               release_sock(sk);
-               return -ECONNREFUSED;
+               err = -ECONNREFUSED;
+               goto out_release;
        }
 
        if (sk->sk_state == TCP_ESTABLISHED) {
-               release_sock(sk);
-               return -EISCONN;        /* No reconnect on a seqpacket socket */
+               err = -EISCONN; /* No reconnect on a seqpacket socket */
+               goto out_release;
        }
 
        sk->sk_state   = TCP_CLOSE;
        sock->state = SS_UNCONNECTED;
 
        if (addr_len != sizeof(struct sockaddr_ax25) && addr_len != sizeof(struct full_sockaddr_ax25)) {
-               release_sock(sk);
-               return -EINVAL;
+               err = -EINVAL;
+               goto out_release;
        }
        if (addr->sax25_family != AF_NETROM) {
-               release_sock(sk);
-               return -EINVAL;
+               err = -EINVAL;
+               goto out_release;
        }
        if (sock_flag(sk, SOCK_ZAPPED)) {       /* Must bind first - autobinding in this may or may not work */
                sock_reset_flag(sk, SOCK_ZAPPED);
 
                if ((dev = nr_dev_first()) == NULL) {
-                       release_sock(sk);
-                       return -ENETUNREACH;
+                       err = -ENETUNREACH;
+                       goto out_release;
                }
                source = (ax25_address *)dev->dev_addr;
 
-               user = ax25_findbyuid(current->euid);
+               user = ax25_findbyuid(current_euid());
                if (user) {
                        nr->user_addr   = user->call;
                        ax25_uid_put(user);
                } else {
                        if (ax25_uid_policy && !capable(CAP_NET_ADMIN)) {
                                dev_put(dev);
-                               release_sock(sk);
-                               return -EPERM;
+                               err = -EPERM;
+                               goto out_release;
                        }
                        nr->user_addr   = *source;
                }
@@ -707,8 +726,8 @@ static int nr_connect(struct socket *sock, struct sockaddr *uaddr,
 
        /* Now the loop */
        if (sk->sk_state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) {
-               release_sock(sk);
-               return -EINPROGRESS;
+               err = -EINPROGRESS;
+               goto out_release;
        }
 
        /*
@@ -716,46 +735,46 @@ static int nr_connect(struct socket *sock, struct sockaddr *uaddr,
         * closed.
         */
        if (sk->sk_state == TCP_SYN_SENT) {
-               struct task_struct *tsk = current;
-               DECLARE_WAITQUEUE(wait, tsk);
+               DEFINE_WAIT(wait);
 
-               add_wait_queue(sk->sk_sleep, &wait);
                for (;;) {
-                       set_current_state(TASK_INTERRUPTIBLE);
+                       prepare_to_wait(sk->sk_sleep, &wait,
+                                       TASK_INTERRUPTIBLE);
                        if (sk->sk_state != TCP_SYN_SENT)
                                break;
-                       release_sock(sk);
-                       if (!signal_pending(tsk)) {
+                       if (!signal_pending(current)) {
+                               release_sock(sk);
                                schedule();
                                lock_sock(sk);
                                continue;
                        }
-                       current->state = TASK_RUNNING;
-                       remove_wait_queue(sk->sk_sleep, &wait);
-                       return -ERESTARTSYS;
+                       err = -ERESTARTSYS;
+                       break;
                }
-               current->state = TASK_RUNNING;
-               remove_wait_queue(sk->sk_sleep, &wait);
+               finish_wait(sk->sk_sleep, &wait);
+               if (err)
+                       goto out_release;
        }
 
        if (sk->sk_state != TCP_ESTABLISHED) {
                sock->state = SS_UNCONNECTED;
-               release_sock(sk);
-               return sock_error(sk);  /* Always set at this point */
+               err = sock_error(sk);   /* Always set at this point */
+               goto out_release;
        }
 
        sock->state = SS_CONNECTED;
+
+out_release:
        release_sock(sk);
 
-       return 0;
+       return err;
 }
 
 static int nr_accept(struct socket *sock, struct socket *newsock, int flags)
 {
-       struct task_struct *tsk = current;
-       DECLARE_WAITQUEUE(wait, tsk);
        struct sk_buff *skb;
        struct sock *newsk;
+       DEFINE_WAIT(wait);
        struct sock *sk;
        int err = 0;
 
@@ -765,54 +784,51 @@ static int nr_accept(struct socket *sock, struct socket *newsock, int flags)
        lock_sock(sk);
        if (sk->sk_type != SOCK_SEQPACKET) {
                err = -EOPNOTSUPP;
-               goto out;
+               goto out_release;
        }
 
        if (sk->sk_state != TCP_LISTEN) {
                err = -EINVAL;
-               goto out;
+               goto out_release;
        }
 
        /*
         *      The write queue this time is holding sockets ready to use
         *      hooked into the SABM we saved
         */
-       add_wait_queue(sk->sk_sleep, &wait);
        for (;;) {
+               prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
                skb = skb_dequeue(&sk->sk_receive_queue);
                if (skb)
                        break;
 
-               current->state = TASK_INTERRUPTIBLE;
-               release_sock(sk);
                if (flags & O_NONBLOCK) {
-                       current->state = TASK_RUNNING;
-                       remove_wait_queue(sk->sk_sleep, &wait);
-                       return -EWOULDBLOCK;
+                       err = -EWOULDBLOCK;
+                       break;
                }
-               if (!signal_pending(tsk)) {
+               if (!signal_pending(current)) {
+                       release_sock(sk);
                        schedule();
                        lock_sock(sk);
                        continue;
                }
-               current->state = TASK_RUNNING;
-               remove_wait_queue(sk->sk_sleep, &wait);
-               return -ERESTARTSYS;
+               err = -ERESTARTSYS;
+               break;
        }
-       current->state = TASK_RUNNING;
-       remove_wait_queue(sk->sk_sleep, &wait);
+       finish_wait(sk->sk_sleep, &wait);
+       if (err)
+               goto out_release;
 
        newsk = skb->sk;
-       newsk->sk_socket = newsock;
-       newsk->sk_sleep = &newsock->wait;
+       sock_graft(newsk, newsock);
 
        /* Now attach up the new socket */
        kfree_skb(skb);
        sk_acceptq_removed(sk);
-       newsock->sk = newsk;
 
-out:
+out_release:
        release_sock(sk);
+
        return err;
 }
 
@@ -1066,7 +1082,13 @@ static int nr_sendmsg(struct kiocb *iocb, struct socket *sock,
 
        SOCK_DEBUG(sk, "NET/ROM: sendto: Addresses built.\n");
 
-       /* Build a packet */
+       /* Build a packet - the conventional user limit is 236 bytes. We can
+          do ludicrously large NetROM frames but must not overflow */
+       if (len > 65536) {
+               err = -EMSGSIZE;
+               goto out;
+       }
+
        SOCK_DEBUG(sk, "NET/ROM: sendto: building packet.\n");
        size = len + NR_NETWORK_LEN + NR_TRANSPORT_LEN;
 
@@ -1160,7 +1182,8 @@ static int nr_recvmsg(struct kiocb *iocb, struct socket *sock,
 
        if (sax != NULL) {
                sax->sax25_family = AF_NETROM;
-               memcpy(sax->sax25_call.ax25_call, skb->data + 7, AX25_ADDR_LEN);
+               skb_copy_from_linear_data_offset(skb, 7, sax->sax25_call.ax25_call,
+                             AX25_ADDR_LEN);
        }
 
        msg->msg_namelen = sizeof(*sax);
@@ -1328,7 +1351,7 @@ static int nr_info_show(struct seq_file *seq, void *v)
        return 0;
 }
 
-static struct seq_operations nr_info_seqops = {
+static const struct seq_operations nr_info_seqops = {
        .start = nr_info_start,
        .next = nr_info_next,
        .stop = nr_info_stop,
@@ -1415,7 +1438,7 @@ static int __init nr_proto_init(void)
                struct net_device *dev;
 
                sprintf(name, "nr%d", i);
-               dev = alloc_netdev(sizeof(struct nr_private), name, nr_setup);
+               dev = alloc_netdev(0, name, nr_setup);
                if (!dev) {
                        printk(KERN_ERR "NET/ROM: nr_proto_init - unable to allocate device structure\n");
                        goto fail;
@@ -1427,7 +1450,7 @@ static int __init nr_proto_init(void)
                        free_netdev(dev);
                        goto fail;
                }
-               lockdep_set_class(&dev->_xmit_lock, &nr_netdev_xmit_lock_key);
+               nr_set_lockdep_key(dev);
                dev_nr[i] = dev;
        }
 
@@ -1447,9 +1470,9 @@ static int __init nr_proto_init(void)
 
        nr_loopback_init();
 
-       proc_net_fops_create("nr", S_IRUGO, &nr_info_fops);
-       proc_net_fops_create("nr_neigh", S_IRUGO, &nr_neigh_fops);
-       proc_net_fops_create("nr_nodes", S_IRUGO, &nr_nodes_fops);
+       proc_net_fops_create(&init_net, "nr", S_IRUGO, &nr_info_fops);
+       proc_net_fops_create(&init_net, "nr_neigh", S_IRUGO, &nr_neigh_fops);
+       proc_net_fops_create(&init_net, "nr_nodes", S_IRUGO, &nr_nodes_fops);
 out:
        return rc;
 fail:
@@ -1477,9 +1500,9 @@ static void __exit nr_exit(void)
 {
        int i;
 
-       proc_net_remove("nr");
-       proc_net_remove("nr_neigh");
-       proc_net_remove("nr_nodes");
+       proc_net_remove(&init_net, "nr");
+       proc_net_remove(&init_net, "nr_neigh");
+       proc_net_remove(&init_net, "nr_nodes");
        nr_loopback_clear();
 
        nr_rt_free();