Merge git://git.linux-nfs.org/pub/linux/nfs-2.6
authorLinus Torvalds <torvalds@woody.linux-foundation.org>
Mon, 15 Oct 2007 17:46:05 +0000 (10:46 -0700)
committerLinus Torvalds <torvalds@woody.linux-foundation.org>
Mon, 15 Oct 2007 17:47:35 +0000 (10:47 -0700)
* git://git.linux-nfs.org/pub/linux/nfs-2.6: (131 commits)
  NFSv4: Fix a typo in nfs_inode_reclaim_delegation
  NFS: Add a boot parameter to disable 64 bit inode numbers
  NFS: nfs_refresh_inode should clear cache_validity flags on success
  NFS: Fix a connectathon regression in NFSv3 and NFSv4
  NFS: Use nfs_refresh_inode() in ops that aren't expected to change the inode
  SUNRPC: Don't call xprt_release in call refresh
  SUNRPC: Don't call xprt_release() if call_allocate fails
  SUNRPC: Fix buggy UDP transmission
  [23/37] Clean up duplicate includes in
  [2.6 patch] net/sunrpc/rpcb_clnt.c: make struct rpcb_program static
  SUNRPC: Use correct type in buffer length calculations
  SUNRPC: Fix default hostname created in rpc_create()
  nfs: add server port to rpc_pipe info file
  NFS: Get rid of some obsolete macros
  NFS: Simplify filehandle revalidation
  NFS: Ensure that nfs_link() returns a hashed dentry
  NFS: Be strict about dentry revalidation when doing exclusive create
  NFS: Don't zap the readdir caches upon error
  NFS: Remove the redundant nfs_reval_fsid()
  NFSv3: Always use directory post-op attributes in nfs3_proc_lookup
  ...

Fix up trivial conflict due to sock_owned_by_user() cleanup manually in
net/sunrpc/xprtsock.c

1  2 
Documentation/kernel-parameters.txt
fs/Kconfig
fs/nfsd/nfs4xdr.c
include/linux/jiffies.h
include/linux/writeback.h
net/sunrpc/xprtsock.c

@@@ -35,7 -35,6 +35,7 @@@ parameter is applicable
        APIC    APIC support is enabled.
        APM     Advanced Power Management support is enabled.
        AX25    Appropriate AX.25 support is enabled.
 +      BLACKFIN Blackfin architecture is enabled.
        DRM     Direct Rendering Management support is enabled.
        EDD     BIOS Enhanced Disk Drive Services (EDD) is enabled
        EFI     EFI Partitioning (GPT) is enabled
@@@ -68,7 -67,6 +68,7 @@@
        PARIDE  The ParIDE (parallel port IDE) subsystem is enabled.
        PARISC  The PA-RISC architecture is enabled.
        PCI     PCI bus support is enabled.
 +      PCIE    PCI Express support is enabled.
        PCMCIA  The PCMCIA subsystem is enabled.
        PNP     Plug & Play support is enabled.
        PPC     PowerPC architecture is enabled.
@@@ -552,7 -550,7 +552,7 @@@ and is between 256 and 4096 characters
  
        dtc3181e=       [HW,SCSI]
  
 -      earlyprintk=    [X86-32,X86-64,SH]
 +      earlyprintk=    [X86-32,X86-64,SH,BLACKFIN]
                        earlyprintk=vga
                        earlyprintk=serial[,ttySn[,baudrate]]
  
        lasi=           [HW,SCSI] PARISC LASI driver for the 53c700 chip
                        Format: addr:<io>,irq:<irq>
  
 +      libata.noacpi   [LIBATA] Disables use of ACPI in libata suspend/resume
 +                      when set.
 +                      Format: <int>
 +
        load_ramdisk=   [RAM] List of ramdisks to load from floppy
                        See Documentation/ramdisk.txt.
  
        meye.*=         [HW] Set MotionEye Camera parameters
                        See Documentation/video4linux/meye.txt.
  
 +      mfgpt_irq=      [IA-32] Specify the IRQ to use for the
 +                      Multi-Function General Purpose Timers on AMD Geode
 +                      platforms.
 +
        mga=            [HW,DRM]
  
        mousedev.tap_time=
                        [NFS] set the maximum lifetime for idmapper cache
                        entries.
  
+       nfs.enable_ino64=
+                       [NFS] enable 64-bit inode numbers.
+                       If zero, the NFS client will fake up a 32-bit inode
+                       number for the readdir() and stat() syscalls instead
+                       of returning the full 64-bit number.
+                       The default is to return 64-bit inode numbers.
        nmi_watchdog=   [KNL,BUGS=X86-32] Debugging features for SMP kernels
  
        no387           [BUGS=X86-32] Tells the kernel to use the 387 maths
                        emulation library even if a 387 maths coprocessor
                        is present.
  
 -      noacpi          [LIBATA] Disables use of ACPI in libata suspend/resume
 -                      when set.
 -                      Format: <int>
 -
        noaliencache    [MM, NUMA, SLAB] Disables the allocation of alien
                        caches in the slab allocator.  Saves per-node memory,
                        but will impact performance.
  
        nomce           [X86-32] Machine Check Exception
  
 +      nomfgpt         [X86-32] Disable Multi-Function General Purpose
 +                      Timer usage (for AMD Geode machines).
 +
        noreplace-paravirt      [X86-32,PV_OPS] Don't patch paravirt_ops
  
        noreplace-smp   [X86-32,SMP] Don't replace SMP instructions
                                Mechanism 1.
                conf2           [X86-32] Force use of PCI Configuration
                                Mechanism 2.
 +              noaer           [PCIE] If the PCIEAER kernel config parameter is
 +                              enabled, this kernel boot option can be used to
 +                              disable the use of PCIE advanced error reporting.
 +              nodomains       [PCI] Disable support for multiple PCI
 +                              root domains (aka PCI segments, in ACPI-speak).
                nommconf        [X86-32,X86_64] Disable use of MMCONFIG for PCI
                                Configuration
                nomsi           [MSI] If the PCI_MSI kernel config parameter is
                                IRQ routing is enabled.
                noacpi          [X86-32] Do not use ACPI for IRQ routing
                                or for PCI scanning.
 +              use_crs         [X86-32] Use _CRS for PCI resource
 +                              allocation.
                routeirq        Do IRQ routing for all PCI devices.
                                This is normally done in pci_enable_device(),
                                so this option is a temporary workaround
        pt.             [PARIDE]
                        See Documentation/paride.txt.
  
 +      pty.legacy_count=
 +                      [KNL] Number of legacy pty's. Overwrites compiled-in
 +                      default number.
 +
        quiet           [KNL] Disable most log messages
  
        r128=           [HW,DRM]
diff --combined fs/Kconfig
@@@ -1225,14 -1225,6 +1225,14 @@@ config JFFS2_FS_WRITEBUFFE
            - NOR flash with transparent ECC
            - DataFlash
  
 +config JFFS2_FS_WBUF_VERIFY
 +      bool "Verify JFFS2 write-buffer reads"
 +      depends on JFFS2_FS_WRITEBUFFER
 +      default n
 +      help
 +        This causes JFFS2 to read back every page written through the
 +        write-buffer, and check for errors.
 +
  config JFFS2_SUMMARY
        bool "JFFS2 summary support (EXPERIMENTAL)"
        depends on JFFS2_FS && EXPERIMENTAL
@@@ -1303,71 -1295,52 +1303,71 @@@ config JFFS2_ZLI
        select ZLIB_DEFLATE
        depends on JFFS2_FS
        default y
 -        help
 -          Zlib is designed to be a free, general-purpose, legally unencumbered,
 -          lossless data-compression library for use on virtually any computer
 -          hardware and operating system. See <http://www.gzip.org/zlib/> for
 -          further information.
 +      help
 +        Zlib is designed to be a free, general-purpose, legally unencumbered,
 +        lossless data-compression library for use on virtually any computer
 +        hardware and operating system. See <http://www.gzip.org/zlib/> for
 +        further information.
  
 -          Say 'Y' if unsure.
 +        Say 'Y' if unsure.
 +
 +config JFFS2_LZO
 +      bool "JFFS2 LZO compression support" if JFFS2_COMPRESSION_OPTIONS
 +      select LZO_COMPRESS
 +      select LZO_DECOMPRESS
 +      depends on JFFS2_FS
 +      default n
 +      help
 +        minilzo-based compression. Generally works better than Zlib.
 +
 +        This feature was added in July, 2007. Say 'N' if you need
 +        compatibility with older bootloaders or kernels.
  
  config JFFS2_RTIME
        bool "JFFS2 RTIME compression support" if JFFS2_COMPRESSION_OPTIONS
        depends on JFFS2_FS
        default y
 -        help
 -          Rtime does manage to recompress already-compressed data. Say 'Y' if unsure.
 +      help
 +        Rtime does manage to recompress already-compressed data. Say 'Y' if unsure.
  
  config JFFS2_RUBIN
        bool "JFFS2 RUBIN compression support" if JFFS2_COMPRESSION_OPTIONS
        depends on JFFS2_FS
        default n
 -        help
 -          RUBINMIPS and DYNRUBIN compressors. Say 'N' if unsure.
 +      help
 +        RUBINMIPS and DYNRUBIN compressors. Say 'N' if unsure.
  
  choice
 -        prompt "JFFS2 default compression mode" if JFFS2_COMPRESSION_OPTIONS
 -        default JFFS2_CMODE_PRIORITY
 -        depends on JFFS2_FS
 -        help
 -          You can set here the default compression mode of JFFS2 from
 -          the available compression modes. Don't touch if unsure.
 +      prompt "JFFS2 default compression mode" if JFFS2_COMPRESSION_OPTIONS
 +      default JFFS2_CMODE_PRIORITY
 +      depends on JFFS2_FS
 +      help
 +        You can set here the default compression mode of JFFS2 from
 +        the available compression modes. Don't touch if unsure.
  
  config JFFS2_CMODE_NONE
 -        bool "no compression"
 -        help
 -          Uses no compression.
 +      bool "no compression"
 +      help
 +        Uses no compression.
  
  config JFFS2_CMODE_PRIORITY
 -        bool "priority"
 -        help
 -          Tries the compressors in a predefined order and chooses the first
 -          successful one.
 +      bool "priority"
 +      help
 +        Tries the compressors in a predefined order and chooses the first
 +        successful one.
  
  config JFFS2_CMODE_SIZE
 -        bool "size (EXPERIMENTAL)"
 -        help
 -          Tries all compressors and chooses the one which has the smallest
 -          result.
 +      bool "size (EXPERIMENTAL)"
 +      help
 +        Tries all compressors and chooses the one which has the smallest
 +        result.
 +
 +config JFFS2_CMODE_FAVOURLZO
 +      bool "Favour LZO"
 +      help
 +        Tries all compressors and chooses the one which has the smallest
 +        result but gives some preference to LZO (which has faster
 +        decompression) at the expense of size.
  
  endchoice
  
@@@ -1755,6 -1728,14 +1755,14 @@@ config SUNRP
  config SUNRPC_GSS
        tristate
  
+ config SUNRPC_XPRT_RDMA
+       tristate "RDMA transport for sunrpc (EXPERIMENTAL)"
+       depends on SUNRPC && INFINIBAND && EXPERIMENTAL
+       default m
+       help
+         Adds a client RPC transport for supporting kernel NFS over RDMA
+         mounts, including Infiniband and iWARP. Experimental.
  config SUNRPC_BIND34
        bool "Support for rpcbind versions 3 & 4 (EXPERIMENTAL)"
        depends on SUNRPC && EXPERIMENTAL
diff --combined fs/nfsd/nfs4xdr.c
@@@ -102,7 -102,8 +102,8 @@@ check_filename(char *str, int len, __be
  out:                                          \
        return status;                          \
  xdr_error:                                    \
-       printk(KERN_NOTICE "xdr error! (%s:%d)\n", __FILE__, __LINE__); \
+       dprintk("NFSD: xdr error (%s:%d)\n",    \
+                       __FILE__, __LINE__);    \
        status = nfserr_bad_xdr;                \
        goto out
  
        if (!(x = (p==argp->tmp || p == argp->tmpp) ? \
                savemem(argp, p, nbytes) :      \
                (char *)p)) {                   \
-               printk(KERN_NOTICE "xdr error! (%s:%d)\n", __FILE__, __LINE__); \
+               dprintk("NFSD: xdr error (%s:%d)\n", \
+                               __FILE__, __LINE__); \
                goto xdr_error;                 \
                }                               \
        p += XDR_QUADLEN(nbytes);               \
                p = argp->p;                    \
                argp->p += XDR_QUADLEN(nbytes); \
        } else if (!(p = read_buf(argp, nbytes))) { \
-               printk(KERN_NOTICE "xdr error! (%s:%d)\n", __FILE__, __LINE__); \
+               dprintk("NFSD: xdr error (%s:%d)\n", \
+                               __FILE__, __LINE__); \
                goto xdr_error;                 \
        }                                       \
  } while (0)
@@@ -948,7 -951,8 +951,8 @@@ nfsd4_decode_write(struct nfsd4_compoun
         */
        avail = (char*)argp->end - (char*)argp->p;
        if (avail + argp->pagelen < write->wr_buflen) {
-               printk(KERN_NOTICE "xdr error! (%s:%d)\n", __FILE__, __LINE__); 
+               dprintk("NFSD: xdr error (%s:%d)\n",
+                               __FILE__, __LINE__);
                goto xdr_error;
        }
        argp->rqstp->rq_vec[0].iov_base = p;
@@@ -1019,7 -1023,7 +1023,7 @@@ nfsd4_decode_compound(struct nfsd4_comp
                argp->ops = kmalloc(argp->opcnt * sizeof(*argp->ops), GFP_KERNEL);
                if (!argp->ops) {
                        argp->ops = argp->iops;
-                       printk(KERN_INFO "nfsd: couldn't allocate room for COMPOUND\n");
+                       dprintk("nfsd: couldn't allocate room for COMPOUND\n");
                        goto xdr_error;
                }
        }
@@@ -1326,7 -1330,7 +1330,7 @@@ static char *nfsd4_path(struct svc_rqs
        path = exp->ex_path;
  
        if (strncmp(path, rootpath, strlen(rootpath))) {
-               printk("nfsd: fs_locations failed;"
+               dprintk("nfsd: fs_locations failed;"
                        "%s is not contained in %s\n", path, rootpath);
                *stat = nfserr_notsupp;
                return NULL;
@@@ -1475,8 -1479,7 +1479,8 @@@ nfsd4_encode_fattr(struct svc_fh *fhp, 
        err = vfs_getattr(exp->ex_mnt, dentry, &stat);
        if (err)
                goto out_nfserr;
 -      if ((bmval0 & (FATTR4_WORD0_FILES_FREE | FATTR4_WORD0_FILES_TOTAL)) ||
 +      if ((bmval0 & (FATTR4_WORD0_FILES_FREE | FATTR4_WORD0_FILES_TOTAL |
 +                      FATTR4_WORD0_MAXNAME)) ||
            (bmval1 & (FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE |
                       FATTR4_WORD1_SPACE_TOTAL))) {
                err = vfs_statfs(dentry, &statfs);
@@@ -1680,7 -1683,7 +1684,7 @@@ out_acl
        if (bmval0 & FATTR4_WORD0_FILEID) {
                if ((buflen -= 8) < 0)
                        goto out_resource;
 -              WRITE64((u64) stat.ino);
 +              WRITE64(stat.ino);
        }
        if (bmval0 & FATTR4_WORD0_FILES_AVAIL) {
                if ((buflen -= 8) < 0)
        if (bmval0 & FATTR4_WORD0_MAXNAME) {
                if ((buflen -= 4) < 0)
                        goto out_resource;
 -              WRITE32(~(u32) 0);
 +              WRITE32(statfs.f_namelen);
        }
        if (bmval0 & FATTR4_WORD0_MAXREAD) {
                if ((buflen -= 8) < 0)
                WRITE32(stat.mtime.tv_nsec);
        }
        if (bmval1 & FATTR4_WORD1_MOUNTED_ON_FILEID) {
 -              struct dentry *mnt_pnt, *mnt_root;
 -
                if ((buflen -= 8) < 0)
                        goto out_resource;
 -              mnt_root = exp->ex_mnt->mnt_root;
 -              if (mnt_root->d_inode == dentry->d_inode) {
 -                      mnt_pnt = exp->ex_mnt->mnt_mountpoint;
 -                      WRITE64((u64) mnt_pnt->d_inode->i_ino);
 -              } else
 -                      WRITE64((u64) stat.ino);
 +              if (exp->ex_mnt->mnt_root->d_inode == dentry->d_inode) {
 +                      err = vfs_getattr(exp->ex_mnt->mnt_parent,
 +                              exp->ex_mnt->mnt_mountpoint, &stat);
 +                      if (err)
 +                              goto out_nfserr;
 +              }
 +              WRITE64(stat.ino);
        }
        *attrlenp = htonl((char *)p - (char *)attrlenp - 4);
        *countp = p - buffer;
diff --combined include/linux/jiffies.h
@@@ -36,6 -36,8 +36,6 @@@
  /* LATCH is used in the interval timer and ftape setup. */
  #define LATCH  ((CLOCK_TICK_RATE + HZ/2) / HZ)        /* For divider */
  
 -#define LATCH_HPET ((HPET_TICK_RATE + HZ/2) / HZ)
 -
  /* Suppose we want to devide two numbers NOM and DEN: NOM/DEN, the we can
   * improve accuracy by shifting LSH bits, hence calculating:
   *     (NOM << LSH) / DEN
  /* HZ is the requested value. ACTHZ is actual HZ ("<< 8" is for accuracy) */
  #define ACTHZ (SH_DIV (CLOCK_TICK_RATE, LATCH, 8))
  
 -#define ACTHZ_HPET (SH_DIV (HPET_TICK_RATE, LATCH_HPET, 8))
 -
  /* TICK_NSEC is the time between ticks in nsec assuming real ACTHZ */
  #define TICK_NSEC (SH_DIV (1000000UL * 1000, ACTHZ, 8))
  
 -#define TICK_NSEC_HPET (SH_DIV(1000000UL * 1000, ACTHZ_HPET, 8))
 -
  /* TICK_USEC is the time between ticks in usec assuming fake USER_HZ */
  #define TICK_USEC ((1000000UL + USER_HZ/2) / USER_HZ)
  
@@@ -109,6 -115,10 +109,10 @@@ static inline u64 get_jiffies_64(void
         ((long)(a) - (long)(b) >= 0))
  #define time_before_eq(a,b)   time_after_eq(b,a)
  
+ #define time_in_range(a,b,c) \
+       (time_after_eq(a,b) && \
+        time_before_eq(a,c))
  /* Same as above, but does so with platform independent 64bit types.
   * These must be used when utilizing jiffies_64 (i.e. return value of
   * get_jiffies_64() */
@@@ -5,7 -5,6 +5,7 @@@
  #define WRITEBACK_H
  
  #include <linux/sched.h>
 +#include <linux/fs.h>
  
  struct backing_dev_info;
  
@@@ -62,8 -61,6 +62,6 @@@ struct writeback_control 
        unsigned for_reclaim:1;         /* Invoked from the page allocator */
        unsigned for_writepages:1;      /* This is a writepages() call */
        unsigned range_cyclic:1;        /* range_start is cyclic */
-       void *fs_private;               /* For use by ->writepages() */
  };
  
  /*
diff --combined net/sunrpc/xprtsock.c
   *  (C) 1999 Trond Myklebust <trond.myklebust@fys.uio.no>
   *
   * IP socket transport implementation, (C) 2005 Chuck Lever <cel@netapp.com>
+  *
+  * IPv6 support contributed by Gilles Quillard, Bull Open Source, 2005.
+  *   <gilles.quillard@bull.net>
   */
  
  #include <linux/types.h>
  #include <linux/slab.h>
+ #include <linux/module.h>
  #include <linux/capability.h>
  #include <linux/pagemap.h>
  #include <linux/errno.h>
@@@ -28,6 -32,7 +32,7 @@@
  #include <linux/tcp.h>
  #include <linux/sunrpc/clnt.h>
  #include <linux/sunrpc/sched.h>
+ #include <linux/sunrpc/xprtsock.h>
  #include <linux/file.h>
  
  #include <net/sock.h>
@@@ -260,14 -265,29 +265,29 @@@ struct sock_xprt 
  #define TCP_RCV_COPY_XID      (1UL << 2)
  #define TCP_RCV_COPY_DATA     (1UL << 3)
  
- static void xs_format_peer_addresses(struct rpc_xprt *xprt)
+ static inline struct sockaddr *xs_addr(struct rpc_xprt *xprt)
+ {
+       return (struct sockaddr *) &xprt->addr;
+ }
+ static inline struct sockaddr_in *xs_addr_in(struct rpc_xprt *xprt)
  {
-       struct sockaddr_in *addr = (struct sockaddr_in *) &xprt->addr;
+       return (struct sockaddr_in *) &xprt->addr;
+ }
+ static inline struct sockaddr_in6 *xs_addr_in6(struct rpc_xprt *xprt)
+ {
+       return (struct sockaddr_in6 *) &xprt->addr;
+ }
+ static void xs_format_ipv4_peer_addresses(struct rpc_xprt *xprt)
+ {
+       struct sockaddr_in *addr = xs_addr_in(xprt);
        char *buf;
  
        buf = kzalloc(20, GFP_KERNEL);
        if (buf) {
-               snprintf(buf, 20, "%u.%u.%u.%u",
+               snprintf(buf, 20, NIPQUAD_FMT,
                                NIPQUAD(addr->sin_addr.s_addr));
        }
        xprt->address_strings[RPC_DISPLAY_ADDR] = buf;
        }
        xprt->address_strings[RPC_DISPLAY_PORT] = buf;
  
-       if (xprt->prot == IPPROTO_UDP)
-               xprt->address_strings[RPC_DISPLAY_PROTO] = "udp";
-       else
-               xprt->address_strings[RPC_DISPLAY_PROTO] = "tcp";
+       buf = kzalloc(8, GFP_KERNEL);
+       if (buf) {
+               if (xprt->prot == IPPROTO_UDP)
+                       snprintf(buf, 8, "udp");
+               else
+                       snprintf(buf, 8, "tcp");
+       }
+       xprt->address_strings[RPC_DISPLAY_PROTO] = buf;
  
        buf = kzalloc(48, GFP_KERNEL);
        if (buf) {
-               snprintf(buf, 48, "addr=%u.%u.%u.%u port=%u proto=%s",
+               snprintf(buf, 48, "addr="NIPQUAD_FMT" port=%u proto=%s",
                        NIPQUAD(addr->sin_addr.s_addr),
                        ntohs(addr->sin_port),
                        xprt->prot == IPPROTO_UDP ? "udp" : "tcp");
        }
        xprt->address_strings[RPC_DISPLAY_ALL] = buf;
+       buf = kzalloc(10, GFP_KERNEL);
+       if (buf) {
+               snprintf(buf, 10, "%02x%02x%02x%02x",
+                               NIPQUAD(addr->sin_addr.s_addr));
+       }
+       xprt->address_strings[RPC_DISPLAY_HEX_ADDR] = buf;
+       buf = kzalloc(8, GFP_KERNEL);
+       if (buf) {
+               snprintf(buf, 8, "%4hx",
+                               ntohs(addr->sin_port));
+       }
+       xprt->address_strings[RPC_DISPLAY_HEX_PORT] = buf;
+       buf = kzalloc(30, GFP_KERNEL);
+       if (buf) {
+               snprintf(buf, 30, NIPQUAD_FMT".%u.%u",
+                               NIPQUAD(addr->sin_addr.s_addr),
+                               ntohs(addr->sin_port) >> 8,
+                               ntohs(addr->sin_port) & 0xff);
+       }
+       xprt->address_strings[RPC_DISPLAY_UNIVERSAL_ADDR] = buf;
+       xprt->address_strings[RPC_DISPLAY_NETID] =
+               kstrdup(xprt->prot == IPPROTO_UDP ?
+                       RPCBIND_NETID_UDP : RPCBIND_NETID_TCP, GFP_KERNEL);
+ }
+ static void xs_format_ipv6_peer_addresses(struct rpc_xprt *xprt)
+ {
+       struct sockaddr_in6 *addr = xs_addr_in6(xprt);
+       char *buf;
+       buf = kzalloc(40, GFP_KERNEL);
+       if (buf) {
+               snprintf(buf, 40, NIP6_FMT,
+                               NIP6(addr->sin6_addr));
+       }
+       xprt->address_strings[RPC_DISPLAY_ADDR] = buf;
+       buf = kzalloc(8, GFP_KERNEL);
+       if (buf) {
+               snprintf(buf, 8, "%u",
+                               ntohs(addr->sin6_port));
+       }
+       xprt->address_strings[RPC_DISPLAY_PORT] = buf;
+       buf = kzalloc(8, GFP_KERNEL);
+       if (buf) {
+               if (xprt->prot == IPPROTO_UDP)
+                       snprintf(buf, 8, "udp");
+               else
+                       snprintf(buf, 8, "tcp");
+       }
+       xprt->address_strings[RPC_DISPLAY_PROTO] = buf;
+       buf = kzalloc(64, GFP_KERNEL);
+       if (buf) {
+               snprintf(buf, 64, "addr="NIP6_FMT" port=%u proto=%s",
+                               NIP6(addr->sin6_addr),
+                               ntohs(addr->sin6_port),
+                               xprt->prot == IPPROTO_UDP ? "udp" : "tcp");
+       }
+       xprt->address_strings[RPC_DISPLAY_ALL] = buf;
+       buf = kzalloc(36, GFP_KERNEL);
+       if (buf) {
+               snprintf(buf, 36, NIP6_SEQFMT,
+                               NIP6(addr->sin6_addr));
+       }
+       xprt->address_strings[RPC_DISPLAY_HEX_ADDR] = buf;
+       buf = kzalloc(8, GFP_KERNEL);
+       if (buf) {
+               snprintf(buf, 8, "%4hx",
+                               ntohs(addr->sin6_port));
+       }
+       xprt->address_strings[RPC_DISPLAY_HEX_PORT] = buf;
+       buf = kzalloc(50, GFP_KERNEL);
+       if (buf) {
+               snprintf(buf, 50, NIP6_FMT".%u.%u",
+                               NIP6(addr->sin6_addr),
+                               ntohs(addr->sin6_port) >> 8,
+                               ntohs(addr->sin6_port) & 0xff);
+       }
+       xprt->address_strings[RPC_DISPLAY_UNIVERSAL_ADDR] = buf;
+       xprt->address_strings[RPC_DISPLAY_NETID] =
+               kstrdup(xprt->prot == IPPROTO_UDP ?
+                       RPCBIND_NETID_UDP6 : RPCBIND_NETID_TCP6, GFP_KERNEL);
  }
  
  static void xs_free_peer_addresses(struct rpc_xprt *xprt)
  {
-       kfree(xprt->address_strings[RPC_DISPLAY_ADDR]);
-       kfree(xprt->address_strings[RPC_DISPLAY_PORT]);
-       kfree(xprt->address_strings[RPC_DISPLAY_ALL]);
+       int i;
+       for (i = 0; i < RPC_DISPLAY_MAX; i++)
+               kfree(xprt->address_strings[i]);
  }
  
  #define XS_SENDMSG_FLAGS      (MSG_DONTWAIT | MSG_NOSIGNAL)
@@@ -463,19 -580,20 +580,20 @@@ static int xs_udp_send_request(struct r
  
        req->rq_xtime = jiffies;
        status = xs_sendpages(transport->sock,
-                             (struct sockaddr *) &xprt->addr,
+                             xs_addr(xprt),
                              xprt->addrlen, xdr,
                              req->rq_bytes_sent);
  
        dprintk("RPC:       xs_udp_send_request(%u) = %d\n",
                        xdr->len - req->rq_bytes_sent, status);
  
-       if (likely(status >= (int) req->rq_slen))
-               return 0;
-       /* Still some bytes left; set up for a retry later. */
-       if (status > 0)
+       if (status >= 0) {
+               task->tk_bytes_sent += status;
+               if (status >= req->rq_slen)
+                       return 0;
+               /* Still some bytes left; set up for a retry later. */
                status = -EAGAIN;
+       }
  
        switch (status) {
        case -ENETUNREACH:
@@@ -523,7 -641,8 +641,8 @@@ static int xs_tcp_send_request(struct r
        struct rpc_xprt *xprt = req->rq_xprt;
        struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
        struct xdr_buf *xdr = &req->rq_snd_buf;
-       int status, retry = 0;
+       int status;
+       unsigned int retry = 0;
  
        xs_encode_tcp_record_marker(&req->rq_snd_buf);
  
@@@ -661,6 -780,7 +780,7 @@@ static void xs_destroy(struct rpc_xprt 
        xs_free_peer_addresses(xprt);
        kfree(xprt->slot);
        kfree(xprt);
+       module_put(THIS_MODULE);
  }
  
  static inline struct rpc_xprt *xprt_from_sock(struct sock *sk)
@@@ -1139,14 -1259,23 +1259,23 @@@ static unsigned short xs_get_random_por
   */
  static void xs_set_port(struct rpc_xprt *xprt, unsigned short port)
  {
-       struct sockaddr_in *sap = (struct sockaddr_in *) &xprt->addr;
+       struct sockaddr *addr = xs_addr(xprt);
  
        dprintk("RPC:       setting port for xprt %p to %u\n", xprt, port);
  
-       sap->sin_port = htons(port);
+       switch (addr->sa_family) {
+       case AF_INET:
+               ((struct sockaddr_in *)addr)->sin_port = htons(port);
+               break;
+       case AF_INET6:
+               ((struct sockaddr_in6 *)addr)->sin6_port = htons(port);
+               break;
+       default:
+               BUG();
+       }
  }
  
- static int xs_bind(struct sock_xprt *transport, struct socket *sock)
+ static int xs_bind4(struct sock_xprt *transport, struct socket *sock)
  {
        struct sockaddr_in myaddr = {
                .sin_family = AF_INET,
                else
                        port--;
        } while (err == -EADDRINUSE && port != transport->port);
-       dprintk("RPC:       xs_bind "NIPQUAD_FMT":%u: %s (%d)\n",
-               NIPQUAD(myaddr.sin_addr), port, err ? "failed" : "ok", err);
+       dprintk("RPC:       %s "NIPQUAD_FMT":%u: %s (%d)\n",
+                       __FUNCTION__, NIPQUAD(myaddr.sin_addr),
+                       port, err ? "failed" : "ok", err);
+       return err;
+ }
+ static int xs_bind6(struct sock_xprt *transport, struct socket *sock)
+ {
+       struct sockaddr_in6 myaddr = {
+               .sin6_family = AF_INET6,
+       };
+       struct sockaddr_in6 *sa;
+       int err;
+       unsigned short port = transport->port;
+       if (!transport->xprt.resvport)
+               port = 0;
+       sa = (struct sockaddr_in6 *)&transport->addr;
+       myaddr.sin6_addr = sa->sin6_addr;
+       do {
+               myaddr.sin6_port = htons(port);
+               err = kernel_bind(sock, (struct sockaddr *) &myaddr,
+                                               sizeof(myaddr));
+               if (!transport->xprt.resvport)
+                       break;
+               if (err == 0) {
+                       transport->port = port;
+                       break;
+               }
+               if (port <= xprt_min_resvport)
+                       port = xprt_max_resvport;
+               else
+                       port--;
+       } while (err == -EADDRINUSE && port != transport->port);
+       dprintk("RPC:       xs_bind6 "NIP6_FMT":%u: %s (%d)\n",
+               NIP6(myaddr.sin6_addr), port, err ? "failed" : "ok", err);
        return err;
  }
  
  static struct lock_class_key xs_key[2];
  static struct lock_class_key xs_slock_key[2];
  
- static inline void xs_reclassify_socket(struct socket *sock)
+ static inline void xs_reclassify_socket4(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-NFS",
-                       &xs_slock_key[0], "sk_lock-AF_INET-NFS", &xs_key[0]);
-               break;
 +      BUG_ON(sock_owned_by_user(sk));
+       sock_lock_init_class_and_name(sk, "slock-AF_INET-RPC",
+               &xs_slock_key[0], "sk_lock-AF_INET-RPC", &xs_key[0]);
+ }
  
-       case AF_INET6:
-               sock_lock_init_class_and_name(sk, "slock-AF_INET6-NFS",
-                       &xs_slock_key[1], "sk_lock-AF_INET6-NFS", &xs_key[1]);
-               break;
+ static inline void xs_reclassify_socket6(struct socket *sock)
+ {
+       struct sock *sk = sock->sk;
  
-       default:
-               BUG();
-       }
 -      BUG_ON(sk->sk_lock.owner != NULL);
++      BUG_ON(sock_owned_by_user(sk));
+       sock_lock_init_class_and_name(sk, "slock-AF_INET6-RPC",
+               &xs_slock_key[1], "sk_lock-AF_INET6-RPC", &xs_key[1]);
  }
  #else
- static inline void xs_reclassify_socket(struct socket *sock)
+ static inline void xs_reclassify_socket4(struct socket *sock)
+ {
+ }
+ static inline void xs_reclassify_socket6(struct socket *sock)
  {
  }
  #endif
  
+ static void xs_udp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)
+ {
+       struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
+       if (!transport->inet) {
+               struct sock *sk = sock->sk;
+               write_lock_bh(&sk->sk_callback_lock);
+               sk->sk_user_data = xprt;
+               transport->old_data_ready = sk->sk_data_ready;
+               transport->old_state_change = sk->sk_state_change;
+               transport->old_write_space = sk->sk_write_space;
+               sk->sk_data_ready = xs_udp_data_ready;
+               sk->sk_write_space = xs_udp_write_space;
+               sk->sk_no_check = UDP_CSUM_NORCV;
+               sk->sk_allocation = GFP_ATOMIC;
+               xprt_set_connected(xprt);
+               /* Reset to new socket */
+               transport->sock = sock;
+               transport->inet = sk;
+               write_unlock_bh(&sk->sk_callback_lock);
+       }
+       xs_udp_do_set_buffer_size(xprt);
+ }
  /**
-  * xs_udp_connect_worker - set up a UDP socket
+  * xs_udp_connect_worker4 - set up a UDP socket
   * @work: RPC transport to connect
   *
   * Invoked by a work queue tasklet.
   */
- static void xs_udp_connect_worker(struct work_struct *work)
+ static void xs_udp_connect_worker4(struct work_struct *work)
  {
        struct sock_xprt *transport =
                container_of(work, struct sock_xprt, connect_worker.work);
                dprintk("RPC:       can't create UDP transport socket (%d).\n", -err);
                goto out;
        }
-       xs_reclassify_socket(sock);
+       xs_reclassify_socket4(sock);
  
-       if (xs_bind(transport, sock)) {
+       if (xs_bind4(transport, sock)) {
                sock_release(sock);
                goto out;
        }
        dprintk("RPC:       worker connecting xprt %p to address: %s\n",
                        xprt, xprt->address_strings[RPC_DISPLAY_ALL]);
  
-       if (!transport->inet) {
-               struct sock *sk = sock->sk;
+       xs_udp_finish_connecting(xprt, sock);
+       status = 0;
+ out:
+       xprt_wake_pending_tasks(xprt, status);
+       xprt_clear_connecting(xprt);
+ }
  
-               write_lock_bh(&sk->sk_callback_lock);
+ /**
+  * xs_udp_connect_worker6 - set up a UDP socket
+  * @work: RPC transport to connect
+  *
+  * Invoked by a work queue tasklet.
+  */
+ static void xs_udp_connect_worker6(struct work_struct *work)
+ {
+       struct sock_xprt *transport =
+               container_of(work, struct sock_xprt, connect_worker.work);
+       struct rpc_xprt *xprt = &transport->xprt;
+       struct socket *sock = transport->sock;
+       int err, status = -EIO;
  
-               sk->sk_user_data = xprt;
-               transport->old_data_ready = sk->sk_data_ready;
-               transport->old_state_change = sk->sk_state_change;
-               transport->old_write_space = sk->sk_write_space;
-               sk->sk_data_ready = xs_udp_data_ready;
-               sk->sk_write_space = xs_udp_write_space;
-               sk->sk_no_check = UDP_CSUM_NORCV;
-               sk->sk_allocation = GFP_ATOMIC;
+       if (xprt->shutdown || !xprt_bound(xprt))
+               goto out;
  
-               xprt_set_connected(xprt);
+       /* Start by resetting any existing state */
+       xs_close(xprt);
  
-               /* Reset to new socket */
-               transport->sock = sock;
-               transport->inet = sk;
+       if ((err = sock_create_kern(PF_INET6, SOCK_DGRAM, IPPROTO_UDP, &sock)) < 0) {
+               dprintk("RPC:       can't create UDP transport socket (%d).\n", -err);
+               goto out;
+       }
+       xs_reclassify_socket6(sock);
  
-               write_unlock_bh(&sk->sk_callback_lock);
+       if (xs_bind6(transport, sock) < 0) {
+               sock_release(sock);
+               goto out;
        }
-       xs_udp_do_set_buffer_size(xprt);
+       dprintk("RPC:       worker connecting xprt %p to address: %s\n",
+                       xprt, xprt->address_strings[RPC_DISPLAY_ALL]);
+       xs_udp_finish_connecting(xprt, sock);
        status = 0;
  out:
        xprt_wake_pending_tasks(xprt, status);
@@@ -1295,13 -1508,52 +1508,52 @@@ static void xs_tcp_reuse_connection(str
                                result);
  }
  
+ static int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)
+ {
+       struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
+       if (!transport->inet) {
+               struct sock *sk = sock->sk;
+               write_lock_bh(&sk->sk_callback_lock);
+               sk->sk_user_data = xprt;
+               transport->old_data_ready = sk->sk_data_ready;
+               transport->old_state_change = sk->sk_state_change;
+               transport->old_write_space = sk->sk_write_space;
+               sk->sk_data_ready = xs_tcp_data_ready;
+               sk->sk_state_change = xs_tcp_state_change;
+               sk->sk_write_space = xs_tcp_write_space;
+               sk->sk_allocation = GFP_ATOMIC;
+               /* socket options */
+               sk->sk_userlocks |= SOCK_BINDPORT_LOCK;
+               sock_reset_flag(sk, SOCK_LINGER);
+               tcp_sk(sk)->linger2 = 0;
+               tcp_sk(sk)->nonagle |= TCP_NAGLE_OFF;
+               xprt_clear_connected(xprt);
+               /* Reset to new socket */
+               transport->sock = sock;
+               transport->inet = sk;
+               write_unlock_bh(&sk->sk_callback_lock);
+       }
+       /* Tell the socket layer to start connecting... */
+       xprt->stat.connect_count++;
+       xprt->stat.connect_start = jiffies;
+       return kernel_connect(sock, xs_addr(xprt), xprt->addrlen, O_NONBLOCK);
+ }
  /**
-  * xs_tcp_connect_worker - connect a TCP socket to a remote endpoint
+  * xs_tcp_connect_worker4 - connect a TCP socket to a remote endpoint
   * @work: RPC transport to connect
   *
   * Invoked by a work queue tasklet.
   */
- static void xs_tcp_connect_worker(struct work_struct *work)
+ static void xs_tcp_connect_worker4(struct work_struct *work)
  {
        struct sock_xprt *transport =
                container_of(work, struct sock_xprt, connect_worker.work);
        if (!sock) {
                /* start from scratch */
                if ((err = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock)) < 0) {
-                       dprintk("RPC:       can't create TCP transport "
-                                       "socket (%d).\n", -err);
+                       dprintk("RPC:       can't create TCP transport socket (%d).\n", -err);
                        goto out;
                }
-               xs_reclassify_socket(sock);
+               xs_reclassify_socket4(sock);
  
-               if (xs_bind(transport, sock)) {
+               if (xs_bind4(transport, sock) < 0) {
                        sock_release(sock);
                        goto out;
                }
        dprintk("RPC:       worker connecting xprt %p to address: %s\n",
                        xprt, xprt->address_strings[RPC_DISPLAY_ALL]);
  
-       if (!transport->inet) {
-               struct sock *sk = sock->sk;
-               write_lock_bh(&sk->sk_callback_lock);
+       status = xs_tcp_finish_connecting(xprt, sock);
+       dprintk("RPC:       %p connect status %d connected %d sock state %d\n",
+                       xprt, -status, xprt_connected(xprt),
+                       sock->sk->sk_state);
+       if (status < 0) {
+               switch (status) {
+                       case -EINPROGRESS:
+                       case -EALREADY:
+                               goto out_clear;
+                       case -ECONNREFUSED:
+                       case -ECONNRESET:
+                               /* retry with existing socket, after a delay */
+                               break;
+                       default:
+                               /* get rid of existing socket, and retry */
+                               xs_close(xprt);
+                               break;
+               }
+       }
+ out:
+       xprt_wake_pending_tasks(xprt, status);
+ out_clear:
+       xprt_clear_connecting(xprt);
+ }
  
-               sk->sk_user_data = xprt;
-               transport->old_data_ready = sk->sk_data_ready;
-               transport->old_state_change = sk->sk_state_change;
-               transport->old_write_space = sk->sk_write_space;
-               sk->sk_data_ready = xs_tcp_data_ready;
-               sk->sk_state_change = xs_tcp_state_change;
-               sk->sk_write_space = xs_tcp_write_space;
-               sk->sk_allocation = GFP_ATOMIC;
+ /**
+  * xs_tcp_connect_worker6 - connect a TCP socket to a remote endpoint
+  * @work: RPC transport to connect
+  *
+  * Invoked by a work queue tasklet.
+  */
+ static void xs_tcp_connect_worker6(struct work_struct *work)
+ {
+       struct sock_xprt *transport =
+               container_of(work, struct sock_xprt, connect_worker.work);
+       struct rpc_xprt *xprt = &transport->xprt;
+       struct socket *sock = transport->sock;
+       int err, status = -EIO;
  
-               /* socket options */
-               sk->sk_userlocks |= SOCK_BINDPORT_LOCK;
-               sock_reset_flag(sk, SOCK_LINGER);
-               tcp_sk(sk)->linger2 = 0;
-               tcp_sk(sk)->nonagle |= TCP_NAGLE_OFF;
+       if (xprt->shutdown || !xprt_bound(xprt))
+               goto out;
  
-               xprt_clear_connected(xprt);
+       if (!sock) {
+               /* start from scratch */
+               if ((err = sock_create_kern(PF_INET6, SOCK_STREAM, IPPROTO_TCP, &sock)) < 0) {
+                       dprintk("RPC:       can't create TCP transport socket (%d).\n", -err);
+                       goto out;
+               }
+               xs_reclassify_socket6(sock);
  
-               /* Reset to new socket */
-               transport->sock = sock;
-               transport->inet = sk;
+               if (xs_bind6(transport, sock) < 0) {
+                       sock_release(sock);
+                       goto out;
+               }
+       } else
+               /* "close" the socket, preserving the local port */
+               xs_tcp_reuse_connection(xprt);
  
-               write_unlock_bh(&sk->sk_callback_lock);
-       }
+       dprintk("RPC:       worker connecting xprt %p to address: %s\n",
+                       xprt, xprt->address_strings[RPC_DISPLAY_ALL]);
  
-       /* Tell the socket layer to start connecting... */
-       xprt->stat.connect_count++;
-       xprt->stat.connect_start = jiffies;
-       status = kernel_connect(sock, (struct sockaddr *) &xprt->addr,
-                       xprt->addrlen, O_NONBLOCK);
+       status = xs_tcp_finish_connecting(xprt, sock);
        dprintk("RPC:       %p connect status %d connected %d sock state %d\n",
-                       xprt, -status, xprt_connected(xprt),
-                       sock->sk->sk_state);
+                       xprt, -status, xprt_connected(xprt), sock->sk->sk_state);
        if (status < 0) {
                switch (status) {
                        case -EINPROGRESS:
@@@ -1508,7 -1786,8 +1786,8 @@@ static struct rpc_xprt_ops xs_tcp_ops 
        .print_stats            = xs_tcp_print_stats,
  };
  
- static struct rpc_xprt *xs_setup_xprt(struct rpc_xprtsock_create *args, unsigned int slot_table_size)
+ static struct rpc_xprt *xs_setup_xprt(struct xprt_create *args,
+                                     unsigned int slot_table_size)
  {
        struct rpc_xprt *xprt;
        struct sock_xprt *new;
   * @args: rpc transport creation arguments
   *
   */
- struct rpc_xprt *xs_setup_udp(struct rpc_xprtsock_create *args)
+ struct rpc_xprt *xs_setup_udp(struct xprt_create *args)
  {
+       struct sockaddr *addr = args->dstaddr;
        struct rpc_xprt *xprt;
        struct sock_xprt *transport;
  
                return xprt;
        transport = container_of(xprt, struct sock_xprt, xprt);
  
-       if (ntohs(((struct sockaddr_in *)args->dstaddr)->sin_port) != 0)
-               xprt_set_bound(xprt);
        xprt->prot = IPPROTO_UDP;
        xprt->tsh_size = 0;
        /* XXX: header size can vary due to auth type, IPv6, etc. */
        xprt->max_payload = (1U << 16) - (MAX_HEADER << 3);
  
-       INIT_DELAYED_WORK(&transport->connect_worker, xs_udp_connect_worker);
        xprt->bind_timeout = XS_BIND_TO;
        xprt->connect_timeout = XS_UDP_CONN_TO;
        xprt->reestablish_timeout = XS_UDP_REEST_TO;
        else
                xprt_set_timeout(&xprt->timeout, 5, 5 * HZ);
  
-       xs_format_peer_addresses(xprt);
+       switch (addr->sa_family) {
+       case AF_INET:
+               if (((struct sockaddr_in *)addr)->sin_port != htons(0))
+                       xprt_set_bound(xprt);
+               INIT_DELAYED_WORK(&transport->connect_worker,
+                                       xs_udp_connect_worker4);
+               xs_format_ipv4_peer_addresses(xprt);
+               break;
+       case AF_INET6:
+               if (((struct sockaddr_in6 *)addr)->sin6_port != htons(0))
+                       xprt_set_bound(xprt);
+               INIT_DELAYED_WORK(&transport->connect_worker,
+                                       xs_udp_connect_worker6);
+               xs_format_ipv6_peer_addresses(xprt);
+               break;
+       default:
+               kfree(xprt);
+               return ERR_PTR(-EAFNOSUPPORT);
+       }
        dprintk("RPC:       set up transport to address %s\n",
                        xprt->address_strings[RPC_DISPLAY_ALL]);
  
-       return xprt;
+       if (try_module_get(THIS_MODULE))
+               return xprt;
+       kfree(xprt->slot);
+       kfree(xprt);
+       return ERR_PTR(-EINVAL);
  }
  
  /**
   * @args: rpc transport creation arguments
   *
   */
- struct rpc_xprt *xs_setup_tcp(struct rpc_xprtsock_create *args)
+ struct rpc_xprt *xs_setup_tcp(struct xprt_create *args)
  {
+       struct sockaddr *addr = args->dstaddr;
        struct rpc_xprt *xprt;
        struct sock_xprt *transport;
  
                return xprt;
        transport = container_of(xprt, struct sock_xprt, xprt);
  
-       if (ntohs(((struct sockaddr_in *)args->dstaddr)->sin_port) != 0)
-               xprt_set_bound(xprt);
        xprt->prot = IPPROTO_TCP;
        xprt->tsh_size = sizeof(rpc_fraghdr) / sizeof(u32);
        xprt->max_payload = RPC_MAX_FRAGMENT_SIZE;
  
-       INIT_DELAYED_WORK(&transport->connect_worker, xs_tcp_connect_worker);
        xprt->bind_timeout = XS_BIND_TO;
        xprt->connect_timeout = XS_TCP_CONN_TO;
        xprt->reestablish_timeout = XS_TCP_INIT_REEST_TO;
        else
                xprt_set_timeout(&xprt->timeout, 2, 60 * HZ);
  
-       xs_format_peer_addresses(xprt);
+       switch (addr->sa_family) {
+       case AF_INET:
+               if (((struct sockaddr_in *)addr)->sin_port != htons(0))
+                       xprt_set_bound(xprt);
+               INIT_DELAYED_WORK(&transport->connect_worker, xs_tcp_connect_worker4);
+               xs_format_ipv4_peer_addresses(xprt);
+               break;
+       case AF_INET6:
+               if (((struct sockaddr_in6 *)addr)->sin6_port != htons(0))
+                       xprt_set_bound(xprt);
+               INIT_DELAYED_WORK(&transport->connect_worker, xs_tcp_connect_worker6);
+               xs_format_ipv6_peer_addresses(xprt);
+               break;
+       default:
+               kfree(xprt);
+               return ERR_PTR(-EAFNOSUPPORT);
+       }
        dprintk("RPC:       set up transport to address %s\n",
                        xprt->address_strings[RPC_DISPLAY_ALL]);
  
-       return xprt;
+       if (try_module_get(THIS_MODULE))
+               return xprt;
+       kfree(xprt->slot);
+       kfree(xprt);
+       return ERR_PTR(-EINVAL);
  }
  
+ static struct xprt_class      xs_udp_transport = {
+       .list           = LIST_HEAD_INIT(xs_udp_transport.list),
+       .name           = "udp",
+       .owner          = THIS_MODULE,
+       .ident          = IPPROTO_UDP,
+       .setup          = xs_setup_udp,
+ };
+ static struct xprt_class      xs_tcp_transport = {
+       .list           = LIST_HEAD_INIT(xs_tcp_transport.list),
+       .name           = "tcp",
+       .owner          = THIS_MODULE,
+       .ident          = IPPROTO_TCP,
+       .setup          = xs_setup_tcp,
+ };
  /**
-  * init_socket_xprt - set up xprtsock's sysctls
+  * init_socket_xprt - set up xprtsock's sysctls, register with RPC client
   *
   */
  int init_socket_xprt(void)
                sunrpc_table_header = register_sysctl_table(sunrpc_table);
  #endif
  
+       xprt_register_transport(&xs_udp_transport);
+       xprt_register_transport(&xs_tcp_transport);
        return 0;
  }
  
  /**
-  * cleanup_socket_xprt - remove xprtsock's sysctls
+  * cleanup_socket_xprt - remove xprtsock's sysctls, unregister
   *
   */
  void cleanup_socket_xprt(void)
                sunrpc_table_header = NULL;
        }
  #endif
+       xprt_unregister_transport(&xs_udp_transport);
+       xprt_unregister_transport(&xs_tcp_transport);
  }