Merge branch 'devel'
authorTrond Myklebust <Trond.Myklebust@netapp.com>
Thu, 24 Apr 2008 18:01:02 +0000 (14:01 -0400)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Thu, 24 Apr 2008 18:01:02 +0000 (14:01 -0400)
1  2 
fs/Kconfig
fs/nfs/dir.c
fs/nfs/file.c
fs/nfs/inode.c
fs/nfs/super.c
net/sunrpc/auth_gss/auth_gss.c
net/sunrpc/clnt.c
net/sunrpc/rpcb_clnt.c
net/sunrpc/xprtsock.c

diff --combined fs/Kconfig
index 8b18a875867751cc9a95bdf85a9f6f9935b6b68d,4115deb567e185c43546823ab419e7c348e40af5..48ca1e1316d94022b422ff721ab617160df157d9
@@@ -444,32 -444,6 +444,32 @@@ config OCFS2_F
          For more information on OCFS2, see the file
          <file:Documentation/filesystems/ocfs2.txt>.
  
 +config OCFS2_FS_O2CB
 +      tristate "O2CB Kernelspace Clustering"
 +      depends on OCFS2_FS
 +      default y
 +      help
 +        OCFS2 includes a simple kernelspace clustering package, the OCFS2
 +        Cluster Base.  It only requires a very small userspace component
 +        to configure it. This comes with the standard ocfs2-tools package.
 +        O2CB is limited to maintaining a cluster for OCFS2 file systems.
 +        It cannot manage any other cluster applications.
 +
 +        It is always safe to say Y here, as the clustering method is
 +        run-time selectable.
 +
 +config OCFS2_FS_USERSPACE_CLUSTER
 +      tristate "OCFS2 Userspace Clustering"
 +      depends on OCFS2_FS && DLM
 +      default y
 +      help
 +        This option will allow OCFS2 to use userspace clustering services
 +        in conjunction with the DLM in fs/dlm.  If you are using a
 +        userspace cluster manager, say Y here.
 +
 +        It is safe to say Y, as the clustering method is run-time
 +        selectable.
 +
  config OCFS2_DEBUG_MASKLOG
        bool "OCFS2 logging support"
        depends on OCFS2_FS
@@@ -689,7 -663,6 +689,7 @@@ config ZISOF
  
  config UDF_FS
        tristate "UDF file system support"
 +      select CRC_ITU_T
        help
          This is the new file system used on some CD-ROMs and DVDs. Say Y if
          you intend to mount DVD discs or CDRW's written in packet mode, or
@@@ -1664,30 -1637,6 +1664,6 @@@ config NFS_V
  
          If unsure, say N.
  
- config NFS_DIRECTIO
-       bool "Allow direct I/O on NFS files"
-       depends on NFS_FS
-       help
-         This option enables applications to perform uncached I/O on files
-         in NFS file systems using the O_DIRECT open() flag.  When O_DIRECT
-         is set for a file, its data is not cached in the system's page
-         cache.  Data is moved to and from user-level application buffers
-         directly.  Unlike local disk-based file systems, NFS O_DIRECT has
-         no alignment restrictions.
-         Unless your program is designed to use O_DIRECT properly, you are
-         much better off allowing the NFS client to manage data caching for
-         you.  Misusing O_DIRECT can cause poor server performance or network
-         storms.  This kernel build option defaults OFF to avoid exposing
-         system administrators unwittingly to a potentially hazardous
-         feature.
-         For more details on NFS O_DIRECT, see fs/nfs/direct.c.
-         If unsure, say N.  This reduces the size of the NFS client, and
-         causes open() to return EINVAL if a file residing in NFS is
-         opened with the O_DIRECT flag.
  config NFSD
        tristate "NFS server support"
        depends on INET
@@@ -1771,10 -1720,10 +1747,10 @@@ config ROOT_NF
          If you want your Linux box to mount its whole root file system (the
          one containing the directory /) from some other computer over the
          net via NFS (presumably because your box doesn't have a hard disk),
 -        say Y. Read <file:Documentation/nfsroot.txt> for details. It is
 -        likely that in this case, you also want to say Y to "Kernel level IP
 -        autoconfiguration" so that your box can discover its network address
 -        at boot time.
 +        say Y. Read <file:Documentation/filesystems/nfsroot.txt> for
 +        details. It is likely that in this case, you also want to say Y to
 +        "Kernel level IP autoconfiguration" so that your box can discover
 +        its network address at boot time.
  
          Most people say N here.
  
@@@ -1808,15 -1757,33 +1784,33 @@@ config SUNRPC_XPRT_RDM
        tristate
        depends on SUNRPC && INFINIBAND && EXPERIMENTAL
        default SUNRPC && INFINIBAND
+       help
+         This option enables an RPC client transport capability that
+         allows the NFS client to mount servers via an RDMA-enabled
+         transport.
+         To compile RPC client RDMA transport support as a module,
+         choose M here: the module will be called xprtrdma.
+         If unsure, say N.
  
  config SUNRPC_BIND34
        bool "Support for rpcbind versions 3 & 4 (EXPERIMENTAL)"
        depends on SUNRPC && EXPERIMENTAL
+       default n
        help
-         Provides kernel support for querying rpcbind servers via versions 3
-         and 4 of the rpcbind protocol.  The kernel automatically falls back
-         to version 2 if a remote rpcbind service does not support versions
-         3 or 4.
+         RPC requests over IPv6 networks require support for larger
+         addresses when performing an RPC bind.  Sun added support for
+         IPv6 addressing by creating two new versions of the rpcbind
+         protocol (RFC 1833).
+         This option enables support in the kernel RPC client for
+         querying rpcbind servers via versions 3 and 4 of the rpcbind
+         protocol.  The kernel automatically falls back to version 2
+         if a remote rpcbind service does not support versions 3 or 4.
+         By themselves, these new versions do not provide support for
+         RPC over IPv6, but the new protocol versions are necessary to
+         support it.
  
          If unsure, say N to get traditional behavior (version 2 rpcbind
          requests only).
@@@ -1830,12 -1797,13 +1824,13 @@@ config RPCSEC_GSS_KRB
        select CRYPTO_DES
        select CRYPTO_CBC
        help
-         Provides for secure RPC calls by means of a gss-api
-         mechanism based on Kerberos V5. This is required for
-         NFSv4.
+         Choose Y here to enable Secure RPC using the Kerberos version 5
+         GSS-API mechanism (RFC 1964).
  
-         Note: Requires an auxiliary userspace daemon which may be found on
-               http://www.citi.umich.edu/projects/nfsv4/
+         Secure RPC calls with Kerberos require an auxiliary user-space
+         daemon which may be found in the Linux nfs-utils package
+         available from http://linux-nfs.org/.  In addition, user-space
+         Kerberos support should be installed.
  
          If unsure, say N.
  
@@@ -1849,11 -1817,12 +1844,12 @@@ config RPCSEC_GSS_SPKM
        select CRYPTO_CAST5
        select CRYPTO_CBC
        help
-         Provides for secure RPC calls by means of a gss-api
-         mechanism based on the SPKM3 public-key mechanism.
+         Choose Y here to enable Secure RPC using the SPKM3 public key
+         GSS-API mechansim (RFC 2025).
  
-         Note: Requires an auxiliary userspace daemon which may be found on
-               http://www.citi.umich.edu/projects/nfsv4/
+         Secure RPC calls with SPKM3 require an auxiliary userspace
+         daemon which may be found in the Linux nfs-utils package
+         available from http://linux-nfs.org/.
  
          If unsure, say N.
  
diff --combined fs/nfs/dir.c
index d9e30ac2798dc1d79ac46ad1a9b6b385252d4ab3,d583654a0b397fef8b63b4e883284db153dc3625..f288b3ecab4afad46334d311ac301f7a2e1e1fa4
@@@ -967,8 -967,7 +967,8 @@@ static int is_atomic_open(struct inode 
        if (nd->flags & LOOKUP_DIRECTORY)
                return 0;
        /* Are we trying to write to a read only partition? */
 -      if (IS_RDONLY(dir) && (nd->intent.open.flags & (O_CREAT|O_TRUNC|FMODE_WRITE)))
 +      if (__mnt_is_readonly(nd->path.mnt) &&
 +          (nd->intent.open.flags & (O_CREAT|O_TRUNC|FMODE_WRITE)))
                return 0;
        return 1;
  }
@@@ -1967,7 -1966,7 +1967,7 @@@ force_lookup
        if (!NFS_PROTO(inode)->access)
                goto out_notsup;
  
-       cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0);
+       cred = rpc_lookup_cred();
        if (!IS_ERR(cred)) {
                res = nfs_do_access(inode, cred, mask);
                put_rpccred(cred);
diff --combined fs/nfs/file.c
index 5d2e9d9a4e28a390c15fd10a0c856baf2fe89058,742cb745cb47df5e111c99f95434354c66ca4348..3536b01164f9ca036aa102ee5211d670273f26df
@@@ -64,11 -64,7 +64,11 @@@ const struct file_operations nfs_file_o
        .write          = do_sync_write,
        .aio_read       = nfs_file_read,
        .aio_write      = nfs_file_write,
 +#ifdef CONFIG_MMU
        .mmap           = nfs_file_mmap,
 +#else
 +      .mmap           = generic_file_mmap,
 +#endif
        .open           = nfs_file_open,
        .flush          = nfs_file_flush,
        .release        = nfs_file_release,
@@@ -238,10 -234,8 +238,8 @@@ nfs_file_read(struct kiocb *iocb, cons
        ssize_t result;
        size_t count = iov_length(iov, nr_segs);
  
- #ifdef CONFIG_NFS_DIRECTIO
        if (iocb->ki_filp->f_flags & O_DIRECT)
                return nfs_file_direct_read(iocb, iov, nr_segs, pos);
- #endif
  
        dfprintk(VFS, "nfs: read(%s/%s, %lu@%lu)\n",
                dentry->d_parent->d_name.name, dentry->d_name.name,
@@@ -387,9 -381,7 +385,7 @@@ const struct address_space_operations n
        .write_end = nfs_write_end,
        .invalidatepage = nfs_invalidate_page,
        .releasepage = nfs_release_page,
- #ifdef CONFIG_NFS_DIRECTIO
        .direct_IO = nfs_direct_IO,
- #endif
        .launder_page = nfs_launder_page,
  };
  
@@@ -447,10 -439,8 +443,8 @@@ static ssize_t nfs_file_write(struct ki
        ssize_t result;
        size_t count = iov_length(iov, nr_segs);
  
- #ifdef CONFIG_NFS_DIRECTIO
        if (iocb->ki_filp->f_flags & O_DIRECT)
                return nfs_file_direct_write(iocb, iov, nr_segs, pos);
- #endif
  
        dfprintk(VFS, "nfs: write(%s/%s(%ld), %lu@%Ld)\n",
                dentry->d_parent->d_name.name, dentry->d_name.name,
@@@ -576,17 -566,9 +570,9 @@@ static int do_setlk(struct file *filp, 
  
        lock_kernel();
        /* Use local locking if mounted with "-onolock" */
-       if (!(NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM)) {
+       if (!(NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM))
                status = NFS_PROTO(inode)->lock(filp, cmd, fl);
-               /* If we were signalled we still need to ensure that
-                * we clean up any state on the server. We therefore
-                * record the lock call as having succeeded in order to
-                * ensure that locks_remove_posix() cleans it out when
-                * the process exits.
-                */
-               if (status == -EINTR || status == -ERESTARTSYS)
-                       do_vfs_lock(filp, fl);
-       } else
+       else
                status = do_vfs_lock(filp, fl);
        unlock_kernel();
        if (status < 0)
diff --combined fs/nfs/inode.c
index 6f88d7c77ac98e1b4bdb5a8f0b347227c271d5ac,15f787355d2753ab8bb4739a946f82467b7b2cf9..5cb3345eb6940a7532457f447d7ea77d89b86113
@@@ -506,7 -506,6 +506,7 @@@ static struct nfs_open_context *alloc_n
                ctx->cred = get_rpccred(cred);
                ctx->state = NULL;
                ctx->lockowner = current->files;
 +              ctx->flags = 0;
                ctx->error = 0;
                ctx->dir_cookie = 0;
                atomic_set(&ctx->count, 1);
@@@ -523,8 -522,12 +523,12 @@@ struct nfs_open_context *get_nfs_open_c
  
  static void __put_nfs_open_context(struct nfs_open_context *ctx, int wait)
  {
-       struct inode *inode = ctx->path.dentry->d_inode;
+       struct inode *inode;
  
+       if (ctx == NULL)
+               return;
+       inode = ctx->path.dentry->d_inode;
        if (!atomic_dec_and_lock(&ctx->count, &inode->i_lock))
                return;
        list_del(&ctx->list);
@@@ -610,7 -613,7 +614,7 @@@ int nfs_open(struct inode *inode, struc
        struct nfs_open_context *ctx;
        struct rpc_cred *cred;
  
-       cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0);
+       cred = rpc_lookup_cred();
        if (IS_ERR(cred))
                return PTR_ERR(cred);
        ctx = alloc_nfs_open_context(filp->f_path.mnt, filp->f_path.dentry, cred);
@@@ -1218,6 -1221,36 +1222,36 @@@ static void nfs_destroy_inodecache(void
        kmem_cache_destroy(nfs_inode_cachep);
  }
  
+ struct workqueue_struct *nfsiod_workqueue;
+ /*
+  * start up the nfsiod workqueue
+  */
+ static int nfsiod_start(void)
+ {
+       struct workqueue_struct *wq;
+       dprintk("RPC:       creating workqueue nfsiod\n");
+       wq = create_singlethread_workqueue("nfsiod");
+       if (wq == NULL)
+               return -ENOMEM;
+       nfsiod_workqueue = wq;
+       return 0;
+ }
+ /*
+  * Destroy the nfsiod workqueue
+  */
+ static void nfsiod_stop(void)
+ {
+       struct workqueue_struct *wq;
+       wq = nfsiod_workqueue;
+       if (wq == NULL)
+               return;
+       nfsiod_workqueue = NULL;
+       destroy_workqueue(wq);
+ }
  /*
   * Initialize NFS
   */
@@@ -1225,6 -1258,10 +1259,10 @@@ static int __init init_nfs_fs(void
  {
        int err;
  
+       err = nfsiod_start();
+       if (err)
+               goto out6;
        err = nfs_fs_proc_init();
        if (err)
                goto out5;
@@@ -1271,6 -1308,8 +1309,8 @@@ out3
  out4:
        nfs_fs_proc_exit();
  out5:
+       nfsiod_stop();
+ out6:
        return err;
  }
  
@@@ -1286,6 -1325,7 +1326,7 @@@ static void __exit exit_nfs_fs(void
  #endif
        unregister_nfs_fs();
        nfs_fs_proc_exit();
+       nfsiod_stop();
  }
  
  /* Not quite true; I just maintain it */
diff --combined fs/nfs/super.c
index f9219024f31aca9fd56962050823d4e46bdbbb37,88a0ecd84c6539126cc2f96083f51dff84baa2f1..20a1cb1810fef50c9a4ce67f5ec9a5f1312e25ba
@@@ -441,10 -441,52 +441,52 @@@ static const char *nfs_pseudoflavour_to
        return sec_flavours[i].str;
  }
  
+ static void nfs_show_mountd_options(struct seq_file *m, struct nfs_server *nfss,
+                                   int showdefaults)
+ {
+       struct sockaddr *sap = (struct sockaddr *)&nfss->mountd_address;
+       switch (sap->sa_family) {
+       case AF_INET: {
+               struct sockaddr_in *sin = (struct sockaddr_in *)sap;
+               seq_printf(m, ",mountaddr=" NIPQUAD_FMT,
+                               NIPQUAD(sin->sin_addr.s_addr));
+               break;
+       }
+       case AF_INET6: {
+               struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
+               seq_printf(m, ",mountaddr=" NIP6_FMT,
+                               NIP6(sin6->sin6_addr));
+               break;
+       }
+       default:
+               if (showdefaults)
+                       seq_printf(m, ",mountaddr=unspecified");
+       }
+       if (nfss->mountd_version || showdefaults)
+               seq_printf(m, ",mountvers=%u", nfss->mountd_version);
+       if (nfss->mountd_port || showdefaults)
+               seq_printf(m, ",mountport=%u", nfss->mountd_port);
+       switch (nfss->mountd_protocol) {
+       case IPPROTO_UDP:
+               seq_printf(m, ",mountproto=udp");
+               break;
+       case IPPROTO_TCP:
+               seq_printf(m, ",mountproto=tcp");
+               break;
+       default:
+               if (showdefaults)
+                       seq_printf(m, ",mountproto=auto");
+       }
+ }
  /*
   * Describe the mount options in force on this server representation
   */
- static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, int showdefaults)
+ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss,
+                                  int showdefaults)
  {
        static const struct proc_nfs_info {
                int flag;
                const char *nostr;
        } nfs_info[] = {
                { NFS_MOUNT_SOFT, ",soft", ",hard" },
+               { NFS_MOUNT_INTR, ",intr", ",nointr" },
+               { NFS_MOUNT_POSIX, ",posix", "" },
                { NFS_MOUNT_NOCTO, ",nocto", "" },
                { NFS_MOUNT_NOAC, ",noac", "" },
                { NFS_MOUNT_NONLM, ",nolock", "" },
        };
        const struct proc_nfs_info *nfs_infop;
        struct nfs_client *clp = nfss->nfs_client;
-       seq_printf(m, ",vers=%d", clp->rpc_ops->version);
-       seq_printf(m, ",rsize=%d", nfss->rsize);
-       seq_printf(m, ",wsize=%d", nfss->wsize);
+       u32 version = clp->rpc_ops->version;
+       seq_printf(m, ",vers=%u", version);
+       seq_printf(m, ",rsize=%u", nfss->rsize);
+       seq_printf(m, ",wsize=%u", nfss->wsize);
+       if (nfss->bsize != 0)
+               seq_printf(m, ",bsize=%u", nfss->bsize);
+       seq_printf(m, ",namlen=%u", nfss->namelen);
        if (nfss->acregmin != 3*HZ || showdefaults)
-               seq_printf(m, ",acregmin=%d", nfss->acregmin/HZ);
+               seq_printf(m, ",acregmin=%u", nfss->acregmin/HZ);
        if (nfss->acregmax != 60*HZ || showdefaults)
-               seq_printf(m, ",acregmax=%d", nfss->acregmax/HZ);
+               seq_printf(m, ",acregmax=%u", nfss->acregmax/HZ);
        if (nfss->acdirmin != 30*HZ || showdefaults)
-               seq_printf(m, ",acdirmin=%d", nfss->acdirmin/HZ);
+               seq_printf(m, ",acdirmin=%u", nfss->acdirmin/HZ);
        if (nfss->acdirmax != 60*HZ || showdefaults)
-               seq_printf(m, ",acdirmax=%d", nfss->acdirmax/HZ);
+               seq_printf(m, ",acdirmax=%u", nfss->acdirmax/HZ);
        for (nfs_infop = nfs_info; nfs_infop->flag; nfs_infop++) {
                if (nfss->flags & nfs_infop->flag)
                        seq_puts(m, nfs_infop->str);
        }
        seq_printf(m, ",proto=%s",
                   rpc_peeraddr2str(nfss->client, RPC_DISPLAY_PROTO));
+       if (version == 4) {
+               if (nfss->port != NFS_PORT)
+                       seq_printf(m, ",port=%u", nfss->port);
+       } else
+               if (nfss->port)
+                       seq_printf(m, ",port=%u", nfss->port);
        seq_printf(m, ",timeo=%lu", 10U * nfss->client->cl_timeout->to_initval / HZ);
        seq_printf(m, ",retrans=%u", nfss->client->cl_timeout->to_retries);
        seq_printf(m, ",sec=%s", nfs_pseudoflavour_to_name(nfss->client->cl_auth->au_flavor));
+       if (version != 4)
+               nfs_show_mountd_options(m, nfss, showdefaults);
+ #ifdef CONFIG_NFS_V4
+       if (clp->rpc_ops->version == 4)
+               seq_printf(m, ",clientaddr=%s", clp->cl_ipaddr);
+ #endif
  }
  
  /*
@@@ -529,10 -592,10 +592,10 @@@ static int nfs_show_stats(struct seq_fi
  
        seq_printf(m, "\n\tcaps:\t");
        seq_printf(m, "caps=0x%x", nfss->caps);
-       seq_printf(m, ",wtmult=%d", nfss->wtmult);
-       seq_printf(m, ",dtsize=%d", nfss->dtsize);
-       seq_printf(m, ",bsize=%d", nfss->bsize);
-       seq_printf(m, ",namelen=%d", nfss->namelen);
+       seq_printf(m, ",wtmult=%u", nfss->wtmult);
+       seq_printf(m, ",dtsize=%u", nfss->dtsize);
+       seq_printf(m, ",bsize=%u", nfss->bsize);
+       seq_printf(m, ",namlen=%u", nfss->namelen);
  
  #ifdef CONFIG_NFS_V4
        if (nfss->nfs_client->rpc_ops->version == 4) {
        /*
         * Display security flavor in effect for this mount
         */
-       seq_printf(m, "\n\tsec:\tflavor=%d", auth->au_ops->au_flavor);
+       seq_printf(m, "\n\tsec:\tflavor=%u", auth->au_ops->au_flavor);
        if (auth->au_flavor)
-               seq_printf(m, ",pseudoflavor=%d", auth->au_flavor);
+               seq_printf(m, ",pseudoflavor=%u", auth->au_flavor);
  
        /*
         * Display superblock I/O counters
@@@ -589,6 -652,8 +652,6 @@@ static void nfs_umount_begin(struct vfs
        struct nfs_server *server = NFS_SB(vfsmnt->mnt_sb);
        struct rpc_clnt *rpc;
  
 -      shrink_submounts(vfsmnt, &nfs_automount_list);
 -
        if (!(flags & MNT_FORCE))
                return;
        /* -EIO all pending I/O */
@@@ -630,7 -695,7 +693,7 @@@ static int nfs_verify_server_address(st
        switch (addr->sa_family) {
        case AF_INET: {
                struct sockaddr_in *sa = (struct sockaddr_in *)addr;
 -              return sa->sin_addr.s_addr != INADDR_ANY;
 +              return sa->sin_addr.s_addr != htonl(INADDR_ANY);
        }
        case AF_INET6: {
                struct in6_addr *sa = &((struct sockaddr_in6 *)addr)->sin6_addr;
@@@ -683,7 -748,6 +746,6 @@@ static int nfs_parse_mount_options(cha
                                   struct nfs_parsed_mount_data *mnt)
  {
        char *p, *string, *secdata;
-       unsigned short port = 0;
        int rc;
  
        if (!raw) {
                                return 0;
                        if (option < 0 || option > 65535)
                                return 0;
-                       port = option;
+                       mnt->nfs_server.port = option;
                        break;
                case Opt_rsize:
                        if (match_int(args, &mnt->rsize))
                }
        }
  
-       nfs_set_port((struct sockaddr *)&mnt->nfs_server.address, port);
+       nfs_set_port((struct sockaddr *)&mnt->nfs_server.address,
+                               mnt->nfs_server.port);
  
        return 1;
  
@@@ -1169,7 -1234,9 +1232,9 @@@ static int nfs_validate_mount_data(voi
        args->acregmax          = 60;
        args->acdirmin          = 30;
        args->acdirmax          = 60;
+       args->mount_server.port = 0;    /* autobind unless user sets port */
        args->mount_server.protocol = XPRT_TRANSPORT_UDP;
+       args->nfs_server.port   = 0;    /* autobind unless user sets port */
        args->nfs_server.protocol = XPRT_TRANSPORT_TCP;
  
        switch (data->version) {
                args->flags             = data->flags;
                args->rsize             = data->rsize;
                args->wsize             = data->wsize;
-               args->flags             = data->flags;
                args->timeo             = data->timeo;
                args->retrans           = data->retrans;
                args->acregmin          = data->acregmin;
                args->namlen            = data->namlen;
                args->bsize             = data->bsize;
                args->auth_flavors[0]   = data->pseudoflavor;
+               if (!args->nfs_server.hostname)
+                       goto out_nomem;
  
                /*
                 * The legacy version 6 binary mount data from userspace has a
                len = c - dev_name;
                /* N.B. caller will free nfs_server.hostname in all cases */
                args->nfs_server.hostname = kstrndup(dev_name, len, GFP_KERNEL);
+               if (!args->nfs_server.hostname)
+                       goto out_nomem;
  
                c++;
                if (strlen(c) > NFS_MAXPATHLEN)
@@@ -1319,6 -1389,10 +1387,10 @@@ out_v3_not_compiled
        return -EPROTONOSUPPORT;
  #endif /* !CONFIG_NFS_V3 */
  
+ out_nomem:
+       dfprintk(MOUNT, "NFS: not enough memory to handle mount options\n");
+       return -ENOMEM;
  out_no_address:
        dfprintk(MOUNT, "NFS: mount program didn't pass remote address\n");
        return -EINVAL;
@@@ -1705,28 -1779,6 +1777,6 @@@ static void nfs4_fill_super(struct supe
        nfs_initialise_sb(sb);
  }
  
- /*
-  * If the user didn't specify a port, set the port number to
-  * the NFS version 4 default port.
-  */
- static void nfs4_default_port(struct sockaddr *sap)
- {
-       switch (sap->sa_family) {
-       case AF_INET: {
-               struct sockaddr_in *ap = (struct sockaddr_in *)sap;
-               if (ap->sin_port == 0)
-                       ap->sin_port = htons(NFS_PORT);
-               break;
-       }
-       case AF_INET6: {
-               struct sockaddr_in6 *ap = (struct sockaddr_in6 *)sap;
-               if (ap->sin6_port == 0)
-                       ap->sin6_port = htons(NFS_PORT);
-               break;
-       }
-       }
- }
  /*
   * Validate NFSv4 mount options
   */
@@@ -1751,6 -1803,7 +1801,7 @@@ static int nfs4_validate_mount_data(voi
        args->acregmax          = 60;
        args->acdirmin          = 30;
        args->acdirmax          = 60;
+       args->nfs_server.port   = NFS_PORT; /* 2049 unless user set port= */
        args->nfs_server.protocol = XPRT_TRANSPORT_TCP;
  
        switch (data->version) {
                                                &args->nfs_server.address))
                        goto out_no_address;
  
-               nfs4_default_port((struct sockaddr *)
-                                 &args->nfs_server.address);
                switch (data->auth_flavourlen) {
                case 0:
                        args->auth_flavors[0] = RPC_AUTH_UNIX;
                                                &args->nfs_server.address))
                        return -EINVAL;
  
-               nfs4_default_port((struct sockaddr *)
-                                 &args->nfs_server.address);
                switch (args->auth_flavor_len) {
                case 0:
                        args->auth_flavors[0] = RPC_AUTH_UNIX;
                        return -ENAMETOOLONG;
                /* N.B. caller will free nfs_server.hostname in all cases */
                args->nfs_server.hostname = kstrndup(dev_name, len, GFP_KERNEL);
+               if (!args->nfs_server.hostname)
+                       goto out_nomem;
  
                c++;                    /* step over the ':' */
                len = strlen(c);
                if (len > NFS4_MAXPATHLEN)
                        return -ENAMETOOLONG;
                args->nfs_server.export_path = kstrndup(c, len, GFP_KERNEL);
+               if (!args->nfs_server.export_path)
+                       goto out_nomem;
  
                dprintk("NFS: MNTPATH: '%s'\n", args->nfs_server.export_path);
  
@@@ -1879,6 -1930,10 +1928,10 @@@ out_inval_auth
                 data->auth_flavourlen);
        return -EINVAL;
  
+ out_nomem:
+       dfprintk(MOUNT, "NFS4: not enough memory to handle mount options\n");
+       return -ENOMEM;
  out_no_address:
        dfprintk(MOUNT, "NFS4: mount program didn't pass remote address\n");
        return -EINVAL;
index 5828e5c060ca6f0fd7f8db305774261cd8d3e76e,621c07f322c4b3c0d8aaba2ffa14efe11be3d7ad..cc12d5f5d5da57e61db43d1d11bf6e2498432970
@@@ -114,27 -114,14 +114,14 @@@ static voi
  gss_cred_set_ctx(struct rpc_cred *cred, struct gss_cl_ctx *ctx)
  {
        struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base);
-       struct gss_cl_ctx *old;
  
-       old = gss_cred->gc_ctx;
+       if (!test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags))
+               return;
+       gss_get_ctx(ctx);
        rcu_assign_pointer(gss_cred->gc_ctx, ctx);
        set_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
+       smp_mb__before_clear_bit();
        clear_bit(RPCAUTH_CRED_NEW, &cred->cr_flags);
-       if (old)
-               gss_put_ctx(old);
- }
- static int
- gss_cred_is_uptodate_ctx(struct rpc_cred *cred)
- {
-       struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base);
-       int res = 0;
-       rcu_read_lock();
-       if (test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) && gss_cred->gc_ctx)
-               res = 1;
-       rcu_read_unlock();
-       return res;
  }
  
  static const void *
@@@ -266,6 -253,7 +253,7 @@@ gss_release_msg(struct gss_upcall_msg *
        BUG_ON(!list_empty(&gss_msg->list));
        if (gss_msg->ctx != NULL)
                gss_put_ctx(gss_msg->ctx);
+       rpc_destroy_wait_queue(&gss_msg->rpc_waitqueue);
        kfree(gss_msg);
  }
  
@@@ -339,7 -327,7 +327,7 @@@ gss_upcall_callback(struct rpc_task *ta
  
        spin_lock(&inode->i_lock);
        if (gss_msg->ctx)
-               gss_cred_set_ctx(task->tk_msg.rpc_cred, gss_get_ctx(gss_msg->ctx));
+               gss_cred_set_ctx(task->tk_msg.rpc_cred, gss_msg->ctx);
        else
                task->tk_status = gss_msg->msg.errno;
        gss_cred->gc_upcall = NULL;
@@@ -370,9 -358,16 +358,16 @@@ gss_alloc_msg(struct gss_auth *gss_auth
  static struct gss_upcall_msg *
  gss_setup_upcall(struct rpc_clnt *clnt, struct gss_auth *gss_auth, struct rpc_cred *cred)
  {
+       struct gss_cred *gss_cred = container_of(cred,
+                       struct gss_cred, gc_base);
        struct gss_upcall_msg *gss_new, *gss_msg;
+       uid_t uid = cred->cr_uid;
  
-       gss_new = gss_alloc_msg(gss_auth, cred->cr_uid);
+       /* Special case: rpc.gssd assumes that uid == 0 implies machine creds */
+       if (gss_cred->gc_machine_cred != 0)
+               uid = 0;
+       gss_new = gss_alloc_msg(gss_auth, uid);
        if (gss_new == NULL)
                return ERR_PTR(-ENOMEM);
        gss_msg = gss_add_msg(gss_auth, gss_new);
@@@ -408,13 -403,17 +403,17 @@@ gss_refresh_upcall(struct rpc_task *tas
        }
        spin_lock(&inode->i_lock);
        if (gss_cred->gc_upcall != NULL)
-               rpc_sleep_on(&gss_cred->gc_upcall->rpc_waitqueue, task, NULL, NULL);
-       else if (gss_msg->ctx == NULL && gss_msg->msg.errno >= 0) {
+               rpc_sleep_on(&gss_cred->gc_upcall->rpc_waitqueue, task, NULL);
+       else if (gss_msg->ctx != NULL) {
+               gss_cred_set_ctx(task->tk_msg.rpc_cred, gss_msg->ctx);
+               gss_cred->gc_upcall = NULL;
+               rpc_wake_up_status(&gss_msg->rpc_waitqueue, gss_msg->msg.errno);
+       } else if (gss_msg->msg.errno >= 0) {
                task->tk_timeout = 0;
                gss_cred->gc_upcall = gss_msg;
                /* gss_upcall_callback will release the reference to gss_upcall_msg */
                atomic_inc(&gss_msg->count);
-               rpc_sleep_on(&gss_msg->rpc_waitqueue, task, gss_upcall_callback, NULL);
+               rpc_sleep_on(&gss_msg->rpc_waitqueue, task, gss_upcall_callback);
        } else
                err = gss_msg->msg.errno;
        spin_unlock(&inode->i_lock);
@@@ -454,7 -453,7 +453,7 @@@ gss_create_upcall(struct gss_auth *gss_
                schedule();
        }
        if (gss_msg->ctx)
-               gss_cred_set_ctx(cred, gss_get_ctx(gss_msg->ctx));
+               gss_cred_set_ctx(cred, gss_msg->ctx);
        else
                err = gss_msg->msg.errno;
        spin_unlock(&inode->i_lock);
@@@ -625,7 -624,7 +624,7 @@@ gss_create(struct rpc_clnt *clnt, rpc_a
        gss_auth->mech = gss_mech_get_by_pseudoflavor(flavor);
        if (!gss_auth->mech) {
                printk(KERN_WARNING "%s: Pseudoflavor %d not found!\n",
 -                              __FUNCTION__, flavor);
 +                              __func__, flavor);
                goto err_free;
        }
        gss_auth->service = gss_pseudoflavor_to_service(gss_auth->mech, flavor);
@@@ -709,7 -708,7 +708,7 @@@ gss_destroying_context(struct rpc_cred 
        struct rpc_task *task;
  
        if (gss_cred->gc_ctx == NULL ||
-                       gss_cred->gc_ctx->gc_proc == RPC_GSS_PROC_DESTROY)
+           test_and_clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) == 0)
                return 0;
  
        gss_cred->gc_ctx->gc_proc = RPC_GSS_PROC_DESTROY;
         * by the RPC call or by the put_rpccred() below */
        get_rpccred(cred);
  
-       task = rpc_call_null(gss_auth->client, cred, RPC_TASK_ASYNC);
+       task = rpc_call_null(gss_auth->client, cred, RPC_TASK_ASYNC|RPC_TASK_SOFT);
        if (!IS_ERR(task))
                rpc_put_task(task);
  
@@@ -817,6 -816,7 +816,7 @@@ gss_create_cred(struct rpc_auth *auth, 
         */
        cred->gc_base.cr_flags = 1UL << RPCAUTH_CRED_NEW;
        cred->gc_service = gss_auth->service;
+       cred->gc_machine_cred = acred->machine_cred;
        kref_get(&gss_auth->kref);
        return &cred->gc_base;
  
@@@ -843,17 -843,16 +843,16 @@@ gss_match(struct auth_cred *acred, stru
  {
        struct gss_cred *gss_cred = container_of(rc, struct gss_cred, gc_base);
  
-       /*
-        * If the searchflags have set RPCAUTH_LOOKUP_NEW, then
-        * we don't really care if the credential has expired or not,
-        * since the caller should be prepared to reinitialise it.
-        */
-       if ((flags & RPCAUTH_LOOKUP_NEW) && test_bit(RPCAUTH_CRED_NEW, &rc->cr_flags))
+       if (test_bit(RPCAUTH_CRED_NEW, &rc->cr_flags))
                goto out;
        /* Don't match with creds that have expired. */
-       if (gss_cred->gc_ctx && time_after(jiffies, gss_cred->gc_ctx->gc_expiry))
+       if (time_after(jiffies, gss_cred->gc_ctx->gc_expiry))
+               return 0;
+       if (!test_bit(RPCAUTH_CRED_UPTODATE, &rc->cr_flags))
                return 0;
  out:
+       if (acred->machine_cred != gss_cred->gc_machine_cred)
+               return 0;
        return (rc->cr_uid == acred->uid);
  }
  
@@@ -917,16 -916,48 +916,48 @@@ out_put_ctx
        return NULL;
  }
  
+ static int gss_renew_cred(struct rpc_task *task)
+ {
+       struct rpc_cred *oldcred = task->tk_msg.rpc_cred;
+       struct gss_cred *gss_cred = container_of(oldcred,
+                                                struct gss_cred,
+                                                gc_base);
+       struct rpc_auth *auth = oldcred->cr_auth;
+       struct auth_cred acred = {
+               .uid = oldcred->cr_uid,
+               .machine_cred = gss_cred->gc_machine_cred,
+       };
+       struct rpc_cred *new;
+       new = gss_lookup_cred(auth, &acred, RPCAUTH_LOOKUP_NEW);
+       if (IS_ERR(new))
+               return PTR_ERR(new);
+       task->tk_msg.rpc_cred = new;
+       put_rpccred(oldcred);
+       return 0;
+ }
  /*
  * Refresh credentials. XXX - finish
  */
  static int
  gss_refresh(struct rpc_task *task)
  {
+       struct rpc_cred *cred = task->tk_msg.rpc_cred;
+       int ret = 0;
+       if (!test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags) &&
+                       !test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags)) {
+               ret = gss_renew_cred(task);
+               if (ret < 0)
+                       goto out;
+               cred = task->tk_msg.rpc_cred;
+       }
  
-       if (!gss_cred_is_uptodate_ctx(task->tk_msg.rpc_cred))
-               return gss_refresh_upcall(task);
-       return 0;
+       if (test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags))
+               ret = gss_refresh_upcall(task);
+ out:
+       return ret;
  }
  
  /* Dummy refresh routine: used only when destroying the context */
@@@ -1286,9 -1317,7 +1317,7 @@@ out
  static const struct rpc_authops authgss_ops = {
        .owner          = THIS_MODULE,
        .au_flavor      = RPC_AUTH_GSS,
- #ifdef RPC_DEBUG
        .au_name        = "RPCSEC_GSS",
- #endif
        .create         = gss_create,
        .destroy        = gss_destroy,
        .lookup_cred    = gss_lookup_cred,
@@@ -1299,6 -1328,7 +1328,7 @@@ static const struct rpc_credops gss_cre
        .cr_name        = "AUTH_GSS",
        .crdestroy      = gss_destroy_cred,
        .cr_init        = gss_cred_init,
+       .crbind         = rpcauth_generic_bind_cred,
        .crmatch        = gss_match,
        .crmarshal      = gss_marshal,
        .crrefresh      = gss_refresh,
  static const struct rpc_credops gss_nullops = {
        .cr_name        = "AUTH_GSS",
        .crdestroy      = gss_destroy_cred,
+       .crbind         = rpcauth_generic_bind_cred,
        .crmatch        = gss_match,
        .crmarshal      = gss_marshal,
        .crrefresh      = gss_refresh_null,
diff --combined net/sunrpc/clnt.c
index 7b96ff38002feaef24b575cdf5f35516fe38d4dd,c6efb982057b9c2e71c449b108333e5224f8414a..8945307556ec32c1a02da6f505748cb5f813b490
@@@ -43,7 -43,7 +43,7 @@@
  
  #define dprint_status(t)                                      \
        dprintk("RPC: %5u %s (status %d)\n", t->tk_pid,         \
 -                      __FUNCTION__, t->tk_status)
 +                      __func__, t->tk_status)
  
  /*
   * All RPC clients are linked into this list
@@@ -261,6 -261,10 +261,6 @@@ struct rpc_clnt *rpc_create(struct rpc_
        };
        char servername[48];
  
 -      xprt = xprt_create_transport(&xprtargs);
 -      if (IS_ERR(xprt))
 -              return (struct rpc_clnt *)xprt;
 -
        /*
         * If the caller chooses not to specify a hostname, whip
         * up a string representation of the passed-in address.
@@@ -368,7 -372,7 +368,7 @@@ out_no_path
  out_no_stats:
        kfree(new);
  out_no_clnt:
 -      dprintk("RPC:       %s: returned error %d\n", __FUNCTION__, err);
 +      dprintk("RPC:       %s: returned error %d\n", __func__, err);
        return ERR_PTR(err);
  }
  EXPORT_SYMBOL_GPL(rpc_clone_client);
@@@ -544,7 -548,7 +544,7 @@@ EXPORT_SYMBOL_GPL(rpc_run_task)
   * @msg: RPC call parameters
   * @flags: RPC call flags
   */
- int rpc_call_sync(struct rpc_clnt *clnt, struct rpc_message *msg, int flags)
+ int rpc_call_sync(struct rpc_clnt *clnt, const struct rpc_message *msg, int flags)
  {
        struct rpc_task *task;
        struct rpc_task_setup task_setup_data = {
@@@ -575,7 -579,7 +575,7 @@@ EXPORT_SYMBOL_GPL(rpc_call_sync)
   * @data: user call data
   */
  int
- rpc_call_async(struct rpc_clnt *clnt, struct rpc_message *msg, int flags,
+ rpc_call_async(struct rpc_clnt *clnt, const struct rpc_message *msg, int flags,
               const struct rpc_call_ops *tk_ops, void *data)
  {
        struct rpc_task *task;
@@@ -752,7 -756,7 +752,7 @@@ call_reserveresult(struct rpc_task *tas
                }
  
                printk(KERN_ERR "%s: status=%d, but no request slot, exiting\n",
 -                              __FUNCTION__, status);
 +                              __func__, status);
                rpc_exit(task, -EIO);
                return;
        }
         */
        if (task->tk_rqstp) {
                printk(KERN_ERR "%s: status=%d, request allocated anyway\n",
 -                              __FUNCTION__, status);
 +                              __func__, status);
                xprt_release(task);
        }
  
                break;
        default:
                printk(KERN_ERR "%s: unrecognized error %d, exiting\n",
 -                              __FUNCTION__, status);
 +                              __func__, status);
                break;
        }
        rpc_exit(task, status);
@@@ -1062,7 -1066,7 +1062,7 @@@ call_transmit(struct rpc_task *task
        if (task->tk_msg.rpc_proc->p_decode != NULL)
                return;
        task->tk_action = rpc_exit_task;
-       rpc_wake_up_task(task);
+       rpc_wake_up_queued_task(&task->tk_xprt->pending, task);
  }
  
  /*
@@@ -1116,7 -1120,8 +1116,8 @@@ call_status(struct rpc_task *task
        case -ETIMEDOUT:
                task->tk_action = call_timeout;
                if (task->tk_client->cl_discrtry)
-                       xprt_force_disconnect(task->tk_xprt);
+                       xprt_conditional_disconnect(task->tk_xprt,
+                                       req->rq_connect_cookie);
                break;
        case -ECONNREFUSED:
        case -ENOTCONN:
@@@ -1168,6 -1173,11 +1169,11 @@@ call_timeout(struct rpc_task *task
                        clnt->cl_protname, clnt->cl_server);
        }
        rpc_force_rebind(clnt);
+       /*
+        * Did our request time out due to an RPCSEC_GSS out-of-sequence
+        * event? RFC2203 requires the server to drop all such requests.
+        */
+       rpcauth_invalcred(task);
  
  retry:
        clnt->cl_stats->rpcretrans++;
@@@ -1195,18 -1205,6 +1201,6 @@@ call_decode(struct rpc_task *task
                task->tk_flags &= ~RPC_CALL_MAJORSEEN;
        }
  
-       if (task->tk_status < 12) {
-               if (!RPC_IS_SOFT(task)) {
-                       task->tk_action = call_bind;
-                       clnt->cl_stats->rpcretrans++;
-                       goto out_retry;
-               }
-               dprintk("RPC:       %s: too small RPC reply size (%d bytes)\n",
-                               clnt->cl_protname, task->tk_status);
-               task->tk_action = call_timeout;
-               goto out_retry;
-       }
        /*
         * Ensure that we see all writes made by xprt_complete_rqst()
         * before it changed req->rq_received.
        WARN_ON(memcmp(&req->rq_rcv_buf, &req->rq_private_buf,
                                sizeof(req->rq_rcv_buf)) != 0);
  
+       if (req->rq_rcv_buf.len < 12) {
+               if (!RPC_IS_SOFT(task)) {
+                       task->tk_action = call_bind;
+                       clnt->cl_stats->rpcretrans++;
+                       goto out_retry;
+               }
+               dprintk("RPC:       %s: too small RPC reply size (%d bytes)\n",
+                               clnt->cl_protname, task->tk_status);
+               task->tk_action = call_timeout;
+               goto out_retry;
+       }
        /* Verify the RPC header */
        p = call_verify(task);
        if (IS_ERR(p)) {
                        task->tk_status);
        return;
  out_retry:
-       req->rq_received = req->rq_private_buf.len = 0;
        task->tk_status = 0;
-       if (task->tk_client->cl_discrtry)
-               xprt_force_disconnect(task->tk_xprt);
+       /* Note: call_verify() may have freed the RPC slot */
+       if (task->tk_rqstp == req) {
+               req->rq_received = req->rq_rcv_buf.len = 0;
+               if (task->tk_client->cl_discrtry)
+                       xprt_conditional_disconnect(task->tk_xprt,
+                                       req->rq_connect_cookie);
+       }
  }
  
  /*
@@@ -1323,7 -1337,7 +1333,7 @@@ call_verify(struct rpc_task *task
                 *   undefined results
                 */
                dprintk("RPC: %5u %s: XDR representation not a multiple of"
 -                     " 4 bytes: 0x%x\n", task->tk_pid, __FUNCTION__,
 +                     " 4 bytes: 0x%x\n", task->tk_pid, __func__,
                       task->tk_rqstp->rq_rcv_buf.len);
                goto out_eio;
        }
  
        if ((n = ntohl(*p++)) != RPC_REPLY) {
                dprintk("RPC: %5u %s: not an RPC reply: %x\n",
 -                              task->tk_pid, __FUNCTION__, n);
 +                              task->tk_pid, __func__, n);
                goto out_garbage;
        }
        if ((n = ntohl(*p++)) != RPC_MSG_ACCEPTED) {
                        case RPC_MISMATCH:
                                dprintk("RPC: %5u %s: RPC call version "
                                                "mismatch!\n",
 -                                              task->tk_pid, __FUNCTION__);
 +                                              task->tk_pid, __func__);
                                error = -EPROTONOSUPPORT;
                                goto out_err;
                        default:
                                dprintk("RPC: %5u %s: RPC call rejected, "
                                                "unknown error: %x\n",
 -                                              task->tk_pid, __FUNCTION__, n);
 +                                              task->tk_pid, __func__, n);
                                goto out_eio;
                }
                if (--len < 0)
                                break;
                        task->tk_cred_retry--;
                        dprintk("RPC: %5u %s: retry stale creds\n",
 -                                      task->tk_pid, __FUNCTION__);
 +                                      task->tk_pid, __func__);
                        rpcauth_invalcred(task);
                        /* Ensure we obtain a new XID! */
                        xprt_release(task);
                                break;
                        task->tk_garb_retry--;
                        dprintk("RPC: %5u %s: retry garbled creds\n",
 -                                      task->tk_pid, __FUNCTION__);
 +                                      task->tk_pid, __func__);
                        task->tk_action = call_bind;
                        goto out_retry;
                case RPC_AUTH_TOOWEAK:
                        break;
                default:
                        dprintk("RPC: %5u %s: unknown auth error: %x\n",
 -                                      task->tk_pid, __FUNCTION__, n);
 +                                      task->tk_pid, __func__, n);
                        error = -EIO;
                }
                dprintk("RPC: %5u %s: call rejected %d\n",
 -                              task->tk_pid, __FUNCTION__, n);
 +                              task->tk_pid, __func__, n);
                goto out_err;
        }
        if (!(p = rpcauth_checkverf(task, p))) {
                dprintk("RPC: %5u %s: auth check failed\n",
 -                              task->tk_pid, __FUNCTION__);
 +                              task->tk_pid, __func__);
                goto out_garbage;               /* bad verifier, retry */
        }
        len = p - (__be32 *)iov->iov_base - 1;
                return p;
        case RPC_PROG_UNAVAIL:
                dprintk("RPC: %5u %s: program %u is unsupported by server %s\n",
 -                              task->tk_pid, __FUNCTION__,
 +                              task->tk_pid, __func__,
                                (unsigned int)task->tk_client->cl_prog,
                                task->tk_client->cl_server);
                error = -EPFNOSUPPORT;
                goto out_err;
        case RPC_PROG_MISMATCH:
                dprintk("RPC: %5u %s: program %u, version %u unsupported by "
 -                              "server %s\n", task->tk_pid, __FUNCTION__,
 +                              "server %s\n", task->tk_pid, __func__,
                                (unsigned int)task->tk_client->cl_prog,
                                (unsigned int)task->tk_client->cl_vers,
                                task->tk_client->cl_server);
        case RPC_PROC_UNAVAIL:
                dprintk("RPC: %5u %s: proc %p unsupported by program %u, "
                                "version %u on server %s\n",
 -                              task->tk_pid, __FUNCTION__,
 +                              task->tk_pid, __func__,
                                task->tk_msg.rpc_proc,
                                task->tk_client->cl_prog,
                                task->tk_client->cl_vers,
                goto out_err;
        case RPC_GARBAGE_ARGS:
                dprintk("RPC: %5u %s: server saw garbage\n",
 -                              task->tk_pid, __FUNCTION__);
 +                              task->tk_pid, __func__);
                break;                  /* retry */
        default:
                dprintk("RPC: %5u %s: server accept status: %x\n",
 -                              task->tk_pid, __FUNCTION__, n);
 +                              task->tk_pid, __func__, n);
                /* Also retry */
        }
  
@@@ -1445,7 -1459,7 +1455,7 @@@ out_garbage
        if (task->tk_garb_retry) {
                task->tk_garb_retry--;
                dprintk("RPC: %5u %s: retrying\n",
 -                              task->tk_pid, __FUNCTION__);
 +                              task->tk_pid, __func__);
                task->tk_action = call_bind;
  out_retry:
                return ERR_PTR(-EAGAIN);
@@@ -1455,11 -1469,11 +1465,11 @@@ out_eio
  out_err:
        rpc_exit(task, error);
        dprintk("RPC: %5u %s: call failed with error %d\n", task->tk_pid,
 -                      __FUNCTION__, error);
 +                      __func__, error);
        return ERR_PTR(error);
  out_overflow:
        dprintk("RPC: %5u %s: server reply was truncated.\n", task->tk_pid,
 -                      __FUNCTION__);
 +                      __func__);
        goto out_garbage;
  }
  
@@@ -1531,7 -1545,7 +1541,7 @@@ void rpc_show_tasks(void
                                proc = -1;
  
                        if (RPC_IS_QUEUED(t))
-                               rpc_waitq = rpc_qname(t->u.tk_wait.rpc_waitq);
+                               rpc_waitq = rpc_qname(t->tk_waitqueue);
  
                        printk("%5u %04d %04x %6d %8p %6d %8p %8ld %8s %8p %8p\n",
                                t->tk_pid, proc,
diff --combined net/sunrpc/rpcb_clnt.c
index 56aa018dce3a026b063262e086b6456e2af6b1fa,f480c718b4001c39d526cdc53c00b06cd2231004..0517967a68bf85571919923e9935658d4c63e6f3
@@@ -224,7 -224,7 +224,7 @@@ int rpcb_getport_sync(struct sockaddr_i
        int status;
  
        dprintk("RPC:       %s(" NIPQUAD_FMT ", %u, %u, %d)\n",
 -              __FUNCTION__, NIPQUAD(sin->sin_addr.s_addr), prog, vers, prot);
 +              __func__, NIPQUAD(sin->sin_addr.s_addr), prog, vers, prot);
  
        rpcb_clnt = rpcb_create(NULL, (struct sockaddr *)sin,
                                sizeof(*sin), prot, 2, 0);
@@@ -283,7 -283,7 +283,7 @@@ void rpcb_getport_async(struct rpc_tas
        struct rpcb_info *info;
  
        dprintk("RPC: %5u %s(%s, %u, %u, %d)\n",
 -              task->tk_pid, __FUNCTION__,
 +              task->tk_pid, __func__,
                clnt->cl_server, clnt->cl_prog, clnt->cl_vers, xprt->prot);
  
        /* Autobind on cloned rpc clients is discouraged */
        if (xprt_test_and_set_binding(xprt)) {
                status = -EAGAIN;       /* tell caller to check again */
                dprintk("RPC: %5u %s: waiting for another binder\n",
 -                      task->tk_pid, __FUNCTION__);
 +                      task->tk_pid, __func__);
                goto bailout_nowake;
        }
  
        /* Put self on queue before sending rpcbind request, in case
         * rpcb_getport_done completes before we return from rpc_run_task */
-       rpc_sleep_on(&xprt->binding, task, NULL, NULL);
+       rpc_sleep_on(&xprt->binding, task, NULL);
  
        /* Someone else may have bound if we slept */
        if (xprt_bound(xprt)) {
                status = 0;
                dprintk("RPC: %5u %s: already bound\n",
 -                      task->tk_pid, __FUNCTION__);
 +                      task->tk_pid, __func__);
                goto bailout_nofree;
        }
  
        default:
                status = -EAFNOSUPPORT;
                dprintk("RPC: %5u %s: bad address family\n",
 -                              task->tk_pid, __FUNCTION__);
 +                              task->tk_pid, __func__);
                goto bailout_nofree;
        }
        if (info[xprt->bind_index].rpc_proc == NULL) {
                xprt->bind_index = 0;
                status = -EPFNOSUPPORT;
                dprintk("RPC: %5u %s: no more getport versions available\n",
 -                      task->tk_pid, __FUNCTION__);
 +                      task->tk_pid, __func__);
                goto bailout_nofree;
        }
        bind_version = info[xprt->bind_index].rpc_vers;
  
        dprintk("RPC: %5u %s: trying rpcbind version %u\n",
 -              task->tk_pid, __FUNCTION__, bind_version);
 +              task->tk_pid, __func__, bind_version);
  
        rpcb_clnt = rpcb_create(clnt->cl_server, sap, salen, xprt->prot,
                                bind_version, 0);
        if (IS_ERR(rpcb_clnt)) {
                status = PTR_ERR(rpcb_clnt);
                dprintk("RPC: %5u %s: rpcb_create failed, error %ld\n",
 -                      task->tk_pid, __FUNCTION__, PTR_ERR(rpcb_clnt));
 +                      task->tk_pid, __func__, PTR_ERR(rpcb_clnt));
                goto bailout_nofree;
        }
  
        if (!map) {
                status = -ENOMEM;
                dprintk("RPC: %5u %s: no memory available\n",
 -                      task->tk_pid, __FUNCTION__);
 +                      task->tk_pid, __func__);
                goto bailout_nofree;
        }
        map->r_prog = clnt->cl_prog;
        if (IS_ERR(child)) {
                status = -EIO;
                dprintk("RPC: %5u %s: rpc_run_task failed\n",
 -                      task->tk_pid, __FUNCTION__);
 +                      task->tk_pid, __func__);
                goto bailout;
        }
        rpc_put_task(child);
diff --combined net/sunrpc/xprtsock.c
index 613daf8c1ff7a8ac309759b50133f504a2206952,63d79e347c00397584534d651896501056838cb8..ddbe981ab516a48e42ee289bf0e8ceca88ff7a7e
@@@ -135,12 -135,6 +135,6 @@@ static ctl_table sunrpc_table[] = 
  
  #endif
  
- /*
-  * How many times to try sending a request on a socket before waiting
-  * for the socket buffer to clear.
-  */
- #define XS_SENDMSG_RETRY      (10U)
  /*
   * Time out for an RPC UDP socket connect.  UDP socket connects are
   * synchronous, but we set a timeout anyway in case of resource
@@@ -516,6 -510,14 +510,14 @@@ out
        return sent;
  }
  
+ static void xs_nospace_callback(struct rpc_task *task)
+ {
+       struct sock_xprt *transport = container_of(task->tk_rqstp->rq_xprt, struct sock_xprt, xprt);
+       transport->inet->sk_write_pending--;
+       clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);
+ }
  /**
   * xs_nospace - place task on wait queue if transmit was incomplete
   * @task: task to put to sleep
@@@ -531,20 -533,27 +533,27 @@@ static void xs_nospace(struct rpc_task 
                        task->tk_pid, req->rq_slen - req->rq_bytes_sent,
                        req->rq_slen);
  
-       if (test_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags)) {
-               /* Protect against races with write_space */
-               spin_lock_bh(&xprt->transport_lock);
-               /* Don't race with disconnect */
-               if (!xprt_connected(xprt))
-                       task->tk_status = -ENOTCONN;
-               else if (test_bit(SOCK_NOSPACE, &transport->sock->flags))
-                       xprt_wait_for_buffer_space(task);
+       /* Protect against races with write_space */
+       spin_lock_bh(&xprt->transport_lock);
+       /* Don't race with disconnect */
+       if (xprt_connected(xprt)) {
+               if (test_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags)) {
+                       /*
+                        * Notify TCP that we're limited by the application
+                        * window size
+                        */
+                       set_bit(SOCK_NOSPACE, &transport->sock->flags);
+                       transport->inet->sk_write_pending++;
+                       /* ...and wait for more buffer space */
+                       xprt_wait_for_buffer_space(task, xs_nospace_callback);
+               }
+       } else {
+               clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);
+               task->tk_status = -ENOTCONN;
+       }
  
-               spin_unlock_bh(&xprt->transport_lock);
-       } else
-               /* Keep holding the socket if it is blocked */
-               rpc_delay(task, HZ>>4);
+       spin_unlock_bh(&xprt->transport_lock);
  }
  
  /**
@@@ -588,19 -597,20 +597,20 @@@ static int xs_udp_send_request(struct r
        }
  
        switch (status) {
+       case -EAGAIN:
+               xs_nospace(task);
+               break;
        case -ENETUNREACH:
        case -EPIPE:
        case -ECONNREFUSED:
                /* When the server has died, an ICMP port unreachable message
                 * prompts ECONNREFUSED. */
-               break;
-       case -EAGAIN:
-               xs_nospace(task);
+               clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);
                break;
        default:
+               clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);
                dprintk("RPC:       sendmsg returned unrecognized error %d\n",
                        -status);
-               break;
        }
  
        return status;
@@@ -650,7 -660,6 +660,6 @@@ static int xs_tcp_send_request(struct r
        struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
        struct xdr_buf *xdr = &req->rq_snd_buf;
        int status;
-       unsigned int retry = 0;
  
        xs_encode_tcp_record_marker(&req->rq_snd_buf);
  
                        return 0;
                }
  
+               if (status != 0)
+                       continue;
                status = -EAGAIN;
-               if (retry++ > XS_SENDMSG_RETRY)
-                       break;
+               break;
        }
  
        switch (status) {
        case -ENOTCONN:
        case -EPIPE:
                status = -ENOTCONN;
+               clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);
                break;
        default:
                dprintk("RPC:       sendmsg returned unrecognized error %d\n",
                        -status);
+               clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);
                xs_tcp_shutdown(xprt);
-               break;
        }
  
        return status;
@@@ -1073,6 -1084,7 +1084,7 @@@ static void xs_tcp_data_ready(struct so
  {
        struct rpc_xprt *xprt;
        read_descriptor_t rd_desc;
+       int read;
  
        dprintk("RPC:       xs_tcp_data_ready...\n");
  
  
        /* We use rd_desc to pass struct xprt to xs_tcp_data_recv */
        rd_desc.arg.data = xprt;
-       rd_desc.count = 65536;
-       tcp_read_sock(sk, &rd_desc, xs_tcp_data_recv);
+       do {
+               rd_desc.count = 65536;
+               read = tcp_read_sock(sk, &rd_desc, xs_tcp_data_recv);
+       } while (read > 0);
  out:
        read_unlock(&sk->sk_callback_lock);
  }
@@@ -1128,6 -1142,7 +1142,7 @@@ static void xs_tcp_state_change(struct 
                break;
        case TCP_FIN_WAIT1:
                /* The client initiated a shutdown of the socket */
+               xprt->connect_cookie++;
                xprt->reestablish_timeout = 0;
                set_bit(XPRT_CLOSING, &xprt->state);
                smp_mb__before_clear_bit();
                set_bit(XPRT_CLOSING, &xprt->state);
                xprt_force_disconnect(xprt);
        case TCP_SYN_SENT:
+               xprt->connect_cookie++;
        case TCP_CLOSING:
                /*
                 * If the server closed down the connection, make sure that
@@@ -1186,9 -1202,11 +1202,11 @@@ static void xs_udp_write_space(struct s
  
                if (unlikely(!(sock = sk->sk_socket)))
                        goto out;
+               clear_bit(SOCK_NOSPACE, &sock->flags);
                if (unlikely(!(xprt = xprt_from_sock(sk))))
                        goto out;
-               if (unlikely(!test_and_clear_bit(SOCK_NOSPACE, &sock->flags)))
+               if (test_and_clear_bit(SOCK_ASYNC_NOSPACE, &sock->flags) == 0)
                        goto out;
  
                xprt_write_space(xprt);
@@@ -1219,9 -1237,11 +1237,11 @@@ static void xs_tcp_write_space(struct s
  
                if (unlikely(!(sock = sk->sk_socket)))
                        goto out;
+               clear_bit(SOCK_NOSPACE, &sock->flags);
                if (unlikely(!(xprt = xprt_from_sock(sk))))
                        goto out;
-               if (unlikely(!test_and_clear_bit(SOCK_NOSPACE, &sock->flags)))
+               if (test_and_clear_bit(SOCK_ASYNC_NOSPACE, &sock->flags) == 0)
                        goto out;
  
                xprt_write_space(xprt);
@@@ -1359,7 -1379,7 +1379,7 @@@ static int xs_bind4(struct sock_xprt *t
                        nloop++;
        } while (err == -EADDRINUSE && nloop != 2);
        dprintk("RPC:       %s "NIPQUAD_FMT":%u: %s (%d)\n",
 -                      __FUNCTION__, NIPQUAD(myaddr.sin_addr),
 +                      __func__, NIPQUAD(myaddr.sin_addr),
                        port, err ? "failed" : "ok", err);
        return err;
  }