Locking a collection of objects is fairly easy: you get a single spinlock, and you make sure you grab it before searching, adding or deleting an object.
The purpose of this lock is not to protect the individual objects: you might have a separate lock inside each one for that. It is to protect the data structure containing the objects from race conditions. Often the same lock is used to protect the contents of all the objects as well, for simplicity, but they are inherently orthogonal (and many other big words designed to confuse).
Changing this to a read-write lock will often help markedly if reads are far more common that writes. If not, there is another approach you can use to reduce the time the lock is held: reference counts.
In this approach, an object has an owner, who sets the reference count to one. Whenever you get a pointer to the object, you increment the reference count (a `get' operation). Whenever you relinquish a pointer, you decrement the reference count (a `put' operation). When the owner wants to destroy it, they mark it dead, and do a put.
Whoever drops the reference count to zero (usually implemented with atomic_dec_and_test()) actually cleans up and frees the object.
This means that you are guaranteed that the object won't vanish underneath you, even though you no longer have a lock for the collection.
Here's some skeleton code:
void create_foo(struct foo *x) { atomic_set(&x->use, 1); spin_lock_bh(&list_lock); ... insert in list ... spin_unlock_bh(&list_lock); } struct foo *get_foo(int desc) { struct foo *ret; spin_lock_bh(&list_lock); ... find in list ... if (ret) atomic_inc(&ret->use); spin_unlock_bh(&list_lock); return ret; } void put_foo(struct foo *x) { if (atomic_dec_and_test(&x->use)) kfree(foo); } void destroy_foo(struct foo *x) { spin_lock_bh(&list_lock); ... remove from list ... spin_unlock_bh(&list_lock); put_foo(x); } |
There are a set of debugging macros tucked inside include/linux/netfilter_ipv4/lockhelp.h and listhelp.h: these are very useful for ensuring that locks are held in the right places to protect infrastructure.