123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139 |
- /*
- * net/dccp/ccid.c
- *
- * An implementation of the DCCP protocol
- * Arnaldo Carvalho de Melo <acme@conectiva.com.br>
- *
- * CCID infrastructure
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
- #include "ccid.h"
- static struct ccid *ccids[CCID_MAX];
- #if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT)
- static atomic_t ccids_lockct = ATOMIC_INIT(0);
- static DEFINE_SPINLOCK(ccids_lock);
- /*
- * The strategy is: modifications ccids vector are short, do not sleep and
- * veeery rare, but read access should be free of any exclusive locks.
- */
- static void ccids_write_lock(void)
- {
- spin_lock(&ccids_lock);
- while (atomic_read(&ccids_lockct) != 0) {
- spin_unlock(&ccids_lock);
- yield();
- spin_lock(&ccids_lock);
- }
- }
- static inline void ccids_write_unlock(void)
- {
- spin_unlock(&ccids_lock);
- }
- static inline void ccids_read_lock(void)
- {
- atomic_inc(&ccids_lockct);
- spin_unlock_wait(&ccids_lock);
- }
- static inline void ccids_read_unlock(void)
- {
- atomic_dec(&ccids_lockct);
- }
- #else
- #define ccids_write_lock() do { } while(0)
- #define ccids_write_unlock() do { } while(0)
- #define ccids_read_lock() do { } while(0)
- #define ccids_read_unlock() do { } while(0)
- #endif
- int ccid_register(struct ccid *ccid)
- {
- int err;
- if (ccid->ccid_init == NULL)
- return -1;
- ccids_write_lock();
- err = -EEXIST;
- if (ccids[ccid->ccid_id] == NULL) {
- ccids[ccid->ccid_id] = ccid;
- err = 0;
- }
- ccids_write_unlock();
- if (err == 0)
- pr_info("CCID: Registered CCID %d (%s)\n",
- ccid->ccid_id, ccid->ccid_name);
- return err;
- }
- EXPORT_SYMBOL_GPL(ccid_register);
- int ccid_unregister(struct ccid *ccid)
- {
- ccids_write_lock();
- ccids[ccid->ccid_id] = NULL;
- ccids_write_unlock();
- pr_info("CCID: Unregistered CCID %d (%s)\n",
- ccid->ccid_id, ccid->ccid_name);
- return 0;
- }
- EXPORT_SYMBOL_GPL(ccid_unregister);
- struct ccid *ccid_init(unsigned char id, struct sock *sk)
- {
- struct ccid *ccid;
- #ifdef CONFIG_KMOD
- if (ccids[id] == NULL)
- request_module("net-dccp-ccid-%d", id);
- #endif
- ccids_read_lock();
- ccid = ccids[id];
- if (ccid == NULL)
- goto out;
- if (!try_module_get(ccid->ccid_owner))
- goto out_err;
- if (ccid->ccid_init(sk) != 0)
- goto out_module_put;
- out:
- ccids_read_unlock();
- return ccid;
- out_module_put:
- module_put(ccid->ccid_owner);
- out_err:
- ccid = NULL;
- goto out;
- }
- EXPORT_SYMBOL_GPL(ccid_init);
- void ccid_exit(struct ccid *ccid, struct sock *sk)
- {
- if (ccid == NULL)
- return;
- ccids_read_lock();
- if (ccids[ccid->ccid_id] != NULL) {
- if (ccid->ccid_exit != NULL)
- ccid->ccid_exit(sk);
- module_put(ccid->ccid_owner);
- }
- ccids_read_unlock();
- }
- EXPORT_SYMBOL_GPL(ccid_exit);
|