]> err.no Git - linux-2.6/blobdiff - net/sunrpc/xprt.c
Merge branch 'for-2.6.25' of git://git.kernel.org/pub/scm/linux/kernel/git/olof/pasem...
[linux-2.6] / net / sunrpc / xprt.c
index bc13616e7fdc527c3aef355c86020b4bfb28d926..cd641c8634f044c6bb580c2d725bdb908e97849d 100644 (file)
@@ -62,6 +62,9 @@ static inline void    do_xprt_reserve(struct rpc_task *);
 static void    xprt_connect_status(struct rpc_task *task);
 static int      __xprt_get_cong(struct rpc_xprt *, struct rpc_task *);
 
+static DEFINE_SPINLOCK(xprt_list_lock);
+static LIST_HEAD(xprt_list);
+
 /*
  * The transport code maintains an estimate on the maximum number of out-
  * standing RPC requests, using a smoothed version of the congestion
@@ -80,6 +83,78 @@ static int      __xprt_get_cong(struct rpc_xprt *, struct rpc_task *);
 
 #define RPCXPRT_CONGESTED(xprt) ((xprt)->cong >= (xprt)->cwnd)
 
+/**
+ * xprt_register_transport - register a transport implementation
+ * @transport: transport to register
+ *
+ * If a transport implementation is loaded as a kernel module, it can
+ * call this interface to make itself known to the RPC client.
+ *
+ * Returns:
+ * 0:          transport successfully registered
+ * -EEXIST:    transport already registered
+ * -EINVAL:    transport module being unloaded
+ */
+int xprt_register_transport(struct xprt_class *transport)
+{
+       struct xprt_class *t;
+       int result;
+
+       result = -EEXIST;
+       spin_lock(&xprt_list_lock);
+       list_for_each_entry(t, &xprt_list, list) {
+               /* don't register the same transport class twice */
+               if (t->ident == transport->ident)
+                       goto out;
+       }
+
+       result = -EINVAL;
+       if (try_module_get(THIS_MODULE)) {
+               list_add_tail(&transport->list, &xprt_list);
+               printk(KERN_INFO "RPC: Registered %s transport module.\n",
+                       transport->name);
+               result = 0;
+       }
+
+out:
+       spin_unlock(&xprt_list_lock);
+       return result;
+}
+EXPORT_SYMBOL_GPL(xprt_register_transport);
+
+/**
+ * xprt_unregister_transport - unregister a transport implementation
+ * transport: transport to unregister
+ *
+ * Returns:
+ * 0:          transport successfully unregistered
+ * -ENOENT:    transport never registered
+ */
+int xprt_unregister_transport(struct xprt_class *transport)
+{
+       struct xprt_class *t;
+       int result;
+
+       result = 0;
+       spin_lock(&xprt_list_lock);
+       list_for_each_entry(t, &xprt_list, list) {
+               if (t == transport) {
+                       printk(KERN_INFO
+                               "RPC: Unregistered %s transport module.\n",
+                               transport->name);
+                       list_del_init(&transport->list);
+                       module_put(THIS_MODULE);
+                       goto out;
+               }
+       }
+       result = -ENOENT;
+
+out:
+       spin_unlock(&xprt_list_lock);
+       return result;
+}
+EXPORT_SYMBOL_GPL(xprt_unregister_transport);
+
 /**
  * xprt_reserve_xprt - serialize write access to transports
  * @task: task that is requesting access to the transport
@@ -904,23 +979,25 @@ void xprt_set_timeout(struct rpc_timeout *to, unsigned int retr, unsigned long i
  * @args: rpc transport creation arguments
  *
  */
-struct rpc_xprt *xprt_create_transport(struct rpc_xprtsock_create *args)
+struct rpc_xprt *xprt_create_transport(struct xprt_create *args)
 {
        struct rpc_xprt *xprt;
        struct rpc_rqst *req;
+       struct xprt_class *t;
 
-       switch (args->proto) {
-       case IPPROTO_UDP:
-               xprt = xs_setup_udp(args);
-               break;
-       case IPPROTO_TCP:
-               xprt = xs_setup_tcp(args);
-               break;
-       default:
-               printk(KERN_ERR "RPC: unrecognized transport protocol: %d\n",
-                               args->proto);
-               return ERR_PTR(-EIO);
+       spin_lock(&xprt_list_lock);
+       list_for_each_entry(t, &xprt_list, list) {
+               if (t->ident == args->ident) {
+                       spin_unlock(&xprt_list_lock);
+                       goto found;
+               }
        }
+       spin_unlock(&xprt_list_lock);
+       printk(KERN_ERR "RPC: transport (%d) not supported\n", args->ident);
+       return ERR_PTR(-EIO);
+
+found:
+       xprt = t->setup(args);
        if (IS_ERR(xprt)) {
                dprintk("RPC:       xprt_create_transport: failed, %ld\n",
                                -PTR_ERR(xprt));