Merge ../linux-2.6-watchdog-mm
[pandora-kernel.git] / net / sunrpc / svcsock.c
index b39e7e2..ff1f8bf 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/netdevice.h>
 #include <linux/skbuff.h>
 #include <linux/file.h>
+#include <linux/freezer.h>
 #include <net/sock.h>
 #include <net/checksum.h>
 #include <net/ip.h>
@@ -84,6 +85,35 @@ static struct cache_deferred_req *svc_defer(struct cache_req *req);
  */
 static int svc_conn_age_period = 6*60;
 
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+static struct lock_class_key svc_key[2];
+static struct lock_class_key svc_slock_key[2];
+
+static inline void svc_reclassify_socket(struct socket *sock)
+{
+       struct sock *sk = sock->sk;
+       BUG_ON(sk->sk_lock.owner != NULL);
+       switch (sk->sk_family) {
+       case AF_INET:
+               sock_lock_init_class_and_name(sk, "slock-AF_INET-NFSD",
+                   &svc_slock_key[0], "sk_lock-AF_INET-NFSD", &svc_key[0]);
+               break;
+
+       case AF_INET6:
+               sock_lock_init_class_and_name(sk, "slock-AF_INET6-NFSD",
+                   &svc_slock_key[1], "sk_lock-AF_INET6-NFSD", &svc_key[1]);
+               break;
+
+       default:
+               BUG();
+       }
+}
+#else
+static inline void svc_reclassify_socket(struct socket *sock)
+{
+}
+#endif
+
 /*
  * Queue up an idle server thread.  Must have pool->sp_lock held.
  * Note: this is really a stack rather than a queue, so that we only
@@ -192,13 +222,13 @@ svc_sock_enqueue(struct svc_sock *svsk)
        svsk->sk_pool = pool;
 
        set_bit(SOCK_NOSPACE, &svsk->sk_sock->flags);
-       if (((atomic_read(&svsk->sk_reserved) + serv->sv_bufsz)*2
+       if (((atomic_read(&svsk->sk_reserved) + serv->sv_max_mesg)*2
             > svc_sock_wspace(svsk))
            && !test_bit(SK_CLOSE, &svsk->sk_flags)
            && !test_bit(SK_CONN, &svsk->sk_flags)) {
                /* Don't enqueue while not enough space for reply */
                dprintk("svc: socket %p  no space, %d*2 > %ld, not enqueued\n",
-                       svsk->sk_sk, atomic_read(&svsk->sk_reserved)+serv->sv_bufsz,
+                       svsk->sk_sk, atomic_read(&svsk->sk_reserved)+serv->sv_max_mesg,
                        svc_sock_wspace(svsk));
                svsk->sk_pool = NULL;
                clear_bit(SK_BUSY, &svsk->sk_flags);
@@ -220,7 +250,7 @@ svc_sock_enqueue(struct svc_sock *svsk)
                                rqstp, rqstp->rq_sock);
                rqstp->rq_sock = svsk;
                atomic_inc(&svsk->sk_inuse);
-               rqstp->rq_reserved = serv->sv_bufsz;
+               rqstp->rq_reserved = serv->sv_max_mesg;
                atomic_add(rqstp->rq_reserved, &svsk->sk_reserved);
                BUG_ON(svsk->sk_pool != pool);
                wake_up(&rqstp->rq_wait);
@@ -299,9 +329,15 @@ void svc_reserve(struct svc_rqst *rqstp, int space)
 static inline void
 svc_sock_put(struct svc_sock *svsk)
 {
-       if (atomic_dec_and_test(&svsk->sk_inuse) && test_bit(SK_DEAD, &svsk->sk_flags)) {
+       if (atomic_dec_and_test(&svsk->sk_inuse) &&
+                       test_bit(SK_DEAD, &svsk->sk_flags)) {
                dprintk("svc: releasing dead socket\n");
-               sock_release(svsk->sk_sock);
+               if (svsk->sk_sock->file)
+                       sockfd_put(svsk->sk_sock);
+               else
+                       sock_release(svsk->sk_sock);
+               if (svsk->sk_info_authunix != NULL)
+                       svcauth_unix_info_release(svsk->sk_info_authunix);
                kfree(svsk);
        }
 }
@@ -639,8 +675,8 @@ svc_udp_recvfrom(struct svc_rqst *rqstp)
             * which will access the socket.
             */
            svc_sock_setbufsize(svsk->sk_sock,
-                               (serv->sv_nrthreads+3) * serv->sv_bufsz,
-                               (serv->sv_nrthreads+3) * serv->sv_bufsz);
+                               (serv->sv_nrthreads+3) * serv->sv_max_mesg,
+                               (serv->sv_nrthreads+3) * serv->sv_max_mesg);
 
        if ((rqstp->rq_deferred = svc_deferred_dequeue(svsk))) {
                svc_sock_received(svsk);
@@ -749,8 +785,8 @@ svc_udp_init(struct svc_sock *svsk)
         * svc_udp_recvfrom will re-adjust if necessary
         */
        svc_sock_setbufsize(svsk->sk_sock,
-                           3 * svsk->sk_server->sv_bufsz,
-                           3 * svsk->sk_server->sv_bufsz);
+                           3 * svsk->sk_server->sv_max_mesg,
+                           3 * svsk->sk_server->sv_max_mesg);
 
        set_bit(SK_DATA, &svsk->sk_flags); /* might have come in before data_ready set up */
        set_bit(SK_CHNGBUF, &svsk->sk_flags);
@@ -973,7 +1009,7 @@ svc_tcp_recvfrom(struct svc_rqst *rqstp)
                return 0;
        }
 
-       if (test_bit(SK_CONN, &svsk->sk_flags)) {
+       if (svsk->sk_sk->sk_state == TCP_LISTEN) {
                svc_tcp_accept(svsk);
                svc_sock_received(svsk);
                return 0;
@@ -993,8 +1029,8 @@ svc_tcp_recvfrom(struct svc_rqst *rqstp)
                 * as soon a a complete request arrives.
                 */
                svc_sock_setbufsize(svsk->sk_sock,
-                                   (serv->sv_nrthreads+3) * serv->sv_bufsz,
-                                   3 * serv->sv_bufsz);
+                                   (serv->sv_nrthreads+3) * serv->sv_max_mesg,
+                                   3 * serv->sv_max_mesg);
 
        clear_bit(SK_DATA, &svsk->sk_flags);
 
@@ -1026,15 +1062,19 @@ svc_tcp_recvfrom(struct svc_rqst *rqstp)
                         *  bit set in the fragment length header.
                         *  But apparently no known nfs clients send fragmented
                         *  records. */
-                       printk(KERN_NOTICE "RPC: bad TCP reclen 0x%08lx (non-terminal)\n",
-                              (unsigned long) svsk->sk_reclen);
+                       if (net_ratelimit())
+                               printk(KERN_NOTICE "RPC: bad TCP reclen 0x%08lx"
+                                      " (non-terminal)\n",
+                                      (unsigned long) svsk->sk_reclen);
                        goto err_delete;
                }
                svsk->sk_reclen &= 0x7fffffff;
                dprintk("svc: TCP record, %d bytes\n", svsk->sk_reclen);
-               if (svsk->sk_reclen > serv->sv_bufsz) {
-                       printk(KERN_NOTICE "RPC: bad TCP reclen 0x%08lx (large)\n",
-                              (unsigned long) svsk->sk_reclen);
+               if (svsk->sk_reclen > serv->sv_max_mesg) {
+                       if (net_ratelimit())
+                               printk(KERN_NOTICE "RPC: bad TCP reclen 0x%08lx"
+                                      " (large)\n",
+                                      (unsigned long) svsk->sk_reclen);
                        goto err_delete;
                }
        }
@@ -1171,8 +1211,8 @@ svc_tcp_init(struct svc_sock *svsk)
                 * svc_tcp_recvfrom will re-adjust if necessary
                 */
                svc_sock_setbufsize(svsk->sk_sock,
-                                   3 * svsk->sk_server->sv_bufsz,
-                                   3 * svsk->sk_server->sv_bufsz);
+                                   3 * svsk->sk_server->sv_max_mesg,
+                                   3 * svsk->sk_server->sv_max_mesg);
 
                set_bit(SK_CHNGBUF, &svsk->sk_flags);
                set_bit(SK_DATA, &svsk->sk_flags);
@@ -1234,7 +1274,7 @@ svc_recv(struct svc_rqst *rqstp, long timeout)
 
 
        /* now allocate needed pages.  If we get a failure, sleep briefly */
-       pages = 2 + (serv->sv_bufsz + PAGE_SIZE -1) / PAGE_SIZE;
+       pages = (serv->sv_max_mesg + PAGE_SIZE) / PAGE_SIZE;
        for (i=0; i < pages ; i++)
                while (rqstp->rq_pages[i] == NULL) {
                        struct page *p = alloc_page(GFP_KERNEL);
@@ -1242,6 +1282,8 @@ svc_recv(struct svc_rqst *rqstp, long timeout)
                                schedule_timeout_uninterruptible(msecs_to_jiffies(500));
                        rqstp->rq_pages[i] = p;
                }
+       rqstp->rq_pages[i++] = NULL; /* this might be seen in nfs_read_actor */
+       BUG_ON(pages >= RPCSVC_MAXPAGES);
 
        /* Make arg->head point to first page and arg->pages point to rest */
        arg = &rqstp->rq_arg;
@@ -1263,7 +1305,7 @@ svc_recv(struct svc_rqst *rqstp, long timeout)
        if ((svsk = svc_sock_dequeue(pool)) != NULL) {
                rqstp->rq_sock = svsk;
                atomic_inc(&svsk->sk_inuse);
-               rqstp->rq_reserved = serv->sv_bufsz;    
+               rqstp->rq_reserved = serv->sv_max_mesg;
                atomic_add(rqstp->rq_reserved, &svsk->sk_reserved);
        } else {
                /* No data pending. Go to sleep */
@@ -1550,6 +1592,8 @@ svc_create_socket(struct svc_serv *serv, int protocol, struct sockaddr_in *sin)
        if ((error = sock_create_kern(PF_INET, type, protocol, &sock)) < 0)
                return error;
 
+       svc_reclassify_socket(sock);
+
        if (type == SOCK_STREAM)
                sock->sk->sk_reuse = 1; /* allow address reuse */
        error = kernel_bind(sock, (struct sockaddr *) sin,
@@ -1604,20 +1648,13 @@ svc_delete_socket(struct svc_sock *svsk)
                if (test_bit(SK_TEMP, &svsk->sk_flags))
                        serv->sv_tmpcnt--;
 
-       if (!atomic_read(&svsk->sk_inuse)) {
-               spin_unlock_bh(&serv->sv_lock);
-               if (svsk->sk_sock->file)
-                       sockfd_put(svsk->sk_sock);
-               else
-                       sock_release(svsk->sk_sock);
-               if (svsk->sk_info_authunix != NULL)
-                       svcauth_unix_info_release(svsk->sk_info_authunix);
-               kfree(svsk);
-       } else {
-               spin_unlock_bh(&serv->sv_lock);
-               dprintk(KERN_NOTICE "svc: server socket destroy delayed\n");
-               /* svsk->sk_server = NULL; */
-       }
+       /* This atomic_inc should be needed - svc_delete_socket
+        * should have the semantic of dropping a reference.
+        * But it doesn't yet....
+        */
+       atomic_inc(&svsk->sk_inuse);
+       spin_unlock_bh(&serv->sv_lock);
+       svc_sock_put(svsk);
 }
 
 /*