Linux 2.6.16.61-rc1
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / net / dccp / ccid.c
blob9d8fc0e289ea51c5cdecb924e26b2ce4c3d79150
1 /*
2 * net/dccp/ccid.c
4 * An implementation of the DCCP protocol
5 * Arnaldo Carvalho de Melo <acme@conectiva.com.br>
7 * CCID infrastructure
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
14 #include "ccid.h"
16 static struct ccid *ccids[CCID_MAX];
17 #if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT)
18 static atomic_t ccids_lockct = ATOMIC_INIT(0);
19 static DEFINE_SPINLOCK(ccids_lock);
22 * The strategy is: modifications ccids vector are short, do not sleep and
23 * veeery rare, but read access should be free of any exclusive locks.
25 static void ccids_write_lock(void)
27 spin_lock(&ccids_lock);
28 while (atomic_read(&ccids_lockct) != 0) {
29 spin_unlock(&ccids_lock);
30 yield();
31 spin_lock(&ccids_lock);
35 static inline void ccids_write_unlock(void)
37 spin_unlock(&ccids_lock);
40 static inline void ccids_read_lock(void)
42 atomic_inc(&ccids_lockct);
43 spin_unlock_wait(&ccids_lock);
46 static inline void ccids_read_unlock(void)
48 atomic_dec(&ccids_lockct);
51 #else
52 #define ccids_write_lock() do { } while(0)
53 #define ccids_write_unlock() do { } while(0)
54 #define ccids_read_lock() do { } while(0)
55 #define ccids_read_unlock() do { } while(0)
56 #endif
58 int ccid_register(struct ccid *ccid)
60 int err;
62 if (ccid->ccid_init == NULL)
63 return -1;
65 ccids_write_lock();
66 err = -EEXIST;
67 if (ccids[ccid->ccid_id] == NULL) {
68 ccids[ccid->ccid_id] = ccid;
69 err = 0;
71 ccids_write_unlock();
72 if (err == 0)
73 pr_info("CCID: Registered CCID %d (%s)\n",
74 ccid->ccid_id, ccid->ccid_name);
75 return err;
78 EXPORT_SYMBOL_GPL(ccid_register);
80 int ccid_unregister(struct ccid *ccid)
82 ccids_write_lock();
83 ccids[ccid->ccid_id] = NULL;
84 ccids_write_unlock();
85 pr_info("CCID: Unregistered CCID %d (%s)\n",
86 ccid->ccid_id, ccid->ccid_name);
87 return 0;
90 EXPORT_SYMBOL_GPL(ccid_unregister);
92 struct ccid *ccid_init(unsigned char id, struct sock *sk)
94 struct ccid *ccid;
96 #ifdef CONFIG_KMOD
97 if (ccids[id] == NULL)
98 request_module("net-dccp-ccid-%d", id);
99 #endif
100 ccids_read_lock();
102 ccid = ccids[id];
103 if (ccid == NULL)
104 goto out;
106 if (!try_module_get(ccid->ccid_owner))
107 goto out_err;
109 if (ccid->ccid_init(sk) != 0)
110 goto out_module_put;
111 out:
112 ccids_read_unlock();
113 return ccid;
114 out_module_put:
115 module_put(ccid->ccid_owner);
116 out_err:
117 ccid = NULL;
118 goto out;
121 EXPORT_SYMBOL_GPL(ccid_init);
123 void ccid_exit(struct ccid *ccid, struct sock *sk)
125 if (ccid == NULL)
126 return;
128 ccids_read_lock();
130 if (ccids[ccid->ccid_id] != NULL) {
131 if (ccid->ccid_exit != NULL)
132 ccid->ccid_exit(sk);
133 module_put(ccid->ccid_owner);
136 ccids_read_unlock();
139 EXPORT_SYMBOL_GPL(ccid_exit);