}
 EXPORT_SYMBOL_GPL(svc_xprt_init);
 
-static struct svc_xprt *__svc_xpo_create(struct svc_xprt_class *xcl,
-                                        struct svc_serv *serv,
-                                        struct net *net,
-                                        const int family,
-                                        const unsigned short port,
-                                        int flags)
-{
-       struct sockaddr_in sin = {
-               .sin_family             = AF_INET,
-               .sin_addr.s_addr        = htonl(INADDR_ANY),
-               .sin_port               = htons(port),
-       };
-#if IS_ENABLED(CONFIG_IPV6)
-       struct sockaddr_in6 sin6 = {
-               .sin6_family            = AF_INET6,
-               .sin6_addr              = IN6ADDR_ANY_INIT,
-               .sin6_port              = htons(port),
-       };
-#endif
-       struct svc_xprt *xprt;
-       struct sockaddr *sap;
-       size_t len;
-
-       switch (family) {
-       case PF_INET:
-               sap = (struct sockaddr *)&sin;
-               len = sizeof(sin);
-               break;
-#if IS_ENABLED(CONFIG_IPV6)
-       case PF_INET6:
-               sap = (struct sockaddr *)&sin6;
-               len = sizeof(sin6);
-               break;
-#endif
-       default:
-               return ERR_PTR(-EAFNOSUPPORT);
-       }
-
-       xprt = xcl->xcl_ops->xpo_create(serv, net, sap, len, flags);
-       if (IS_ERR(xprt))
-               trace_svc_xprt_create_err(serv->sv_program->pg_name,
-                                         xcl->xcl_name, sap, len, xprt);
-       return xprt;
-}
-
 /**
  * svc_xprt_received - start next receiver thread
  * @xprt: controlling transport
 }
 
 static int _svc_xprt_create(struct svc_serv *serv, const char *xprt_name,
-                           struct net *net, const int family,
-                           const unsigned short port, int flags,
-                           const struct cred *cred)
+                           struct net *net, struct sockaddr *sap,
+                           size_t len, int flags, const struct cred *cred)
 {
        struct svc_xprt_class *xcl;
 
                        goto err;
 
                spin_unlock(&svc_xprt_class_lock);
-               newxprt = __svc_xpo_create(xcl, serv, net, family, port, flags);
+               newxprt = xcl->xcl_ops->xpo_create(serv, net, sap, len, flags);
                if (IS_ERR(newxprt)) {
+                       trace_svc_xprt_create_err(serv->sv_program->pg_name,
+                                                 xcl->xcl_name, sap, len,
+                                                 newxprt);
                        module_put(xcl->xcl_owner);
                        return PTR_ERR(newxprt);
                }
        return -EPROTONOSUPPORT;
 }
 
+/**
+ * svc_xprt_create_from_sa - Add a new listener to @serv from socket address
+ * @serv: target RPC service
+ * @xprt_name: transport class name
+ * @net: network namespace
+ * @sap: socket address pointer
+ * @flags: SVC_SOCK flags
+ * @cred: credential to bind to this transport
+ *
+ * Return local xprt port on success or %-EPROTONOSUPPORT on failure
+ */
+int svc_xprt_create_from_sa(struct svc_serv *serv, const char *xprt_name,
+                           struct net *net, struct sockaddr *sap,
+                           int flags, const struct cred *cred)
+{
+       size_t len;
+       int err;
+
+       switch (sap->sa_family) {
+       case AF_INET:
+               len = sizeof(struct sockaddr_in);
+               break;
+#if IS_ENABLED(CONFIG_IPV6)
+       case AF_INET6:
+               len = sizeof(struct sockaddr_in6);
+               break;
+#endif
+       default:
+               return -EAFNOSUPPORT;
+       }
+
+       err = _svc_xprt_create(serv, xprt_name, net, sap, len, flags, cred);
+       if (err == -EPROTONOSUPPORT) {
+               request_module("svc%s", xprt_name);
+               err = _svc_xprt_create(serv, xprt_name, net, sap, len, flags,
+                                      cred);
+       }
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(svc_xprt_create_from_sa);
+
 /**
  * svc_xprt_create - Add a new listener to @serv
  * @serv: target RPC service
  * @flags: SVC_SOCK flags
  * @cred: credential to bind to this transport
  *
- * Return values:
- *   %0: New listener added successfully
- *   %-EPROTONOSUPPORT: Requested transport type not supported
+ * Return local xprt port on success or %-EPROTONOSUPPORT on failure
  */
 int svc_xprt_create(struct svc_serv *serv, const char *xprt_name,
                    struct net *net, const int family,
                    const unsigned short port, int flags,
                    const struct cred *cred)
 {
-       int err;
+       struct sockaddr_in sin = {
+               .sin_family             = AF_INET,
+               .sin_addr.s_addr        = htonl(INADDR_ANY),
+               .sin_port               = htons(port),
+       };
+#if IS_ENABLED(CONFIG_IPV6)
+       struct sockaddr_in6 sin6 = {
+               .sin6_family            = AF_INET6,
+               .sin6_addr              = IN6ADDR_ANY_INIT,
+               .sin6_port              = htons(port),
+       };
+#endif
+       struct sockaddr *sap;
 
-       err = _svc_xprt_create(serv, xprt_name, net, family, port, flags, cred);
-       if (err == -EPROTONOSUPPORT) {
-               request_module("svc%s", xprt_name);
-               err = _svc_xprt_create(serv, xprt_name, net, family, port, flags, cred);
+       switch (family) {
+       case PF_INET:
+               sap = (struct sockaddr *)&sin;
+               break;
+#if IS_ENABLED(CONFIG_IPV6)
+       case PF_INET6:
+               sap = (struct sockaddr *)&sin6;
+               break;
+#endif
+       default:
+               return -EAFNOSUPPORT;
        }
-       return err;
+
+       return svc_xprt_create_from_sa(serv, xprt_name, net, sap, flags, cred);
 }
 EXPORT_SYMBOL_GPL(svc_xprt_create);