|
@@ -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 spinlock_t xprt_list_lock = SPIN_LOCK_UNLOCKED;
|
|
|
+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 == transport)
|
|
|
+ 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
|