aboutsummaryrefslogtreecommitdiffstats
path: root/fs/gfs2/glock.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/gfs2/glock.c')
-rw-r--r--fs/gfs2/glock.c93
1 files changed, 74 insertions, 19 deletions
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
index 49512696160e..8abfefe4efd4 100644
--- a/fs/gfs2/glock.c
+++ b/fs/gfs2/glock.c
@@ -53,8 +53,59 @@ typedef void (*glock_examiner) (struct gfs2_glock * gl);
53static int gfs2_dump_lockstate(struct gfs2_sbd *sdp); 53static int gfs2_dump_lockstate(struct gfs2_sbd *sdp);
54static int dump_glock(struct gfs2_glock *gl); 54static int dump_glock(struct gfs2_glock *gl);
55 55
56#define GFS2_GL_HASH_SHIFT 13
57#define GFS2_GL_HASH_SIZE (1 << GFS2_GL_HASH_SHIFT)
58#define GFS2_GL_HASH_MASK (GFS2_GL_HASH_SIZE - 1)
59
56static struct gfs2_gl_hash_bucket gl_hash_table[GFS2_GL_HASH_SIZE]; 60static struct gfs2_gl_hash_bucket gl_hash_table[GFS2_GL_HASH_SIZE];
57static rwlock_t gl_hash_locks[GFS2_GL_HASH_SIZE]; 61
62/*
63 * Despite what you might think, the numbers below are not arbitrary :-)
64 * They are taken from the ipv4 routing hash code, which is well tested
65 * and thus should be nearly optimal. Later on we might tweek the numbers
66 * but for now this should be fine.
67 *
68 * The reason for putting the locks in a separate array from the list heads
69 * is that we can have fewer locks than list heads and save memory. We use
70 * the same hash function for both, but with a different hash mask.
71 */
72#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) || \
73 defined(CONFIG_PROVE_LOCKING)
74
75#ifdef CONFIG_LOCKDEP
76# define GL_HASH_LOCK_SZ 256
77#else
78# if NR_CPUS >= 32
79# define GL_HASH_LOCK_SZ 4096
80# elif NR_CPUS >= 16
81# define GL_HASH_LOCK_SZ 2048
82# elif NR_CPUS >= 8
83# define GL_HASH_LOCK_SZ 1024
84# elif NR_CPUS >= 4
85# define GL_HASH_LOCK_SZ 512
86# else
87# define GL_HASH_LOCK_SZ 256
88# endif
89#endif
90
91/* We never want more locks than chains */
92#if GFS2_GL_HASH_SIZE < GL_HASH_LOCK_SZ
93# undef GL_HASH_LOCK_SZ
94# define GL_HASH_LOCK_SZ GFS2_GL_HASH_SIZE
95#endif
96
97static rwlock_t gl_hash_locks[GL_HASH_LOCK_SZ];
98
99static inline rwlock_t *gl_lock_addr(unsigned int x)
100{
101 return &gl_hash_locks[(x) & (GL_HASH_LOCK_SZ-1)];
102}
103#else /* not SMP, so no spinlocks required */
104static inline rwlock_t *gl_lock_addr(x)
105{
106 return NULL;
107}
108#endif
58 109
59/** 110/**
60 * relaxed_state_ok - is a requested lock compatible with the current lock mode? 111 * relaxed_state_ok - is a requested lock compatible with the current lock mode?
@@ -161,16 +212,16 @@ int gfs2_glock_put(struct gfs2_glock *gl)
161{ 212{
162 int rv = 0; 213 int rv = 0;
163 214
164 write_lock(&gl_hash_locks[gl->gl_hash]); 215 write_lock(gl_lock_addr(gl->gl_hash));
165 if (kref_put(&gl->gl_ref, kill_glock)) { 216 if (kref_put(&gl->gl_ref, kill_glock)) {
166 list_del_init(&gl_hash_table[gl->gl_hash].hb_list); 217 list_del_init(&gl_hash_table[gl->gl_hash].hb_list);
167 write_unlock(&gl_hash_locks[gl->gl_hash]); 218 write_unlock(gl_lock_addr(gl->gl_hash));
168 BUG_ON(spin_is_locked(&gl->gl_spin)); 219 BUG_ON(spin_is_locked(&gl->gl_spin));
169 glock_free(gl); 220 glock_free(gl);
170 rv = 1; 221 rv = 1;
171 goto out; 222 goto out;
172 } 223 }
173 write_unlock(&gl_hash_locks[gl->gl_hash]); 224 write_unlock(gl_lock_addr(gl->gl_hash));
174out: 225out:
175 return rv; 226 return rv;
176} 227}
@@ -243,9 +294,9 @@ static struct gfs2_glock *gfs2_glock_find(const struct gfs2_sbd *sdp,
243 unsigned int hash = gl_hash(sdp, name); 294 unsigned int hash = gl_hash(sdp, name);
244 struct gfs2_glock *gl; 295 struct gfs2_glock *gl;
245 296
246 read_lock(&gl_hash_locks[hash]); 297 read_lock(gl_lock_addr(hash));
247 gl = search_bucket(hash, sdp, name); 298 gl = search_bucket(hash, sdp, name);
248 read_unlock(&gl_hash_locks[hash]); 299 read_unlock(gl_lock_addr(hash));
249 300
250 return gl; 301 return gl;
251} 302}
@@ -272,9 +323,9 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number,
272 unsigned int hash = gl_hash(sdp, &name); 323 unsigned int hash = gl_hash(sdp, &name);
273 int error; 324 int error;
274 325
275 read_lock(&gl_hash_locks[hash]); 326 read_lock(gl_lock_addr(hash));
276 gl = search_bucket(hash, sdp, &name); 327 gl = search_bucket(hash, sdp, &name);
277 read_unlock(&gl_hash_locks[hash]); 328 read_unlock(gl_lock_addr(hash));
278 329
279 if (gl || !create) { 330 if (gl || !create) {
280 *glp = gl; 331 *glp = gl;
@@ -316,15 +367,15 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number,
316 if (error) 367 if (error)
317 goto fail_aspace; 368 goto fail_aspace;
318 369
319 write_lock(&gl_hash_locks[hash]); 370 write_lock(gl_lock_addr(hash));
320 tmp = search_bucket(hash, sdp, &name); 371 tmp = search_bucket(hash, sdp, &name);
321 if (tmp) { 372 if (tmp) {
322 write_unlock(&gl_hash_locks[hash]); 373 write_unlock(gl_lock_addr(hash));
323 glock_free(gl); 374 glock_free(gl);
324 gl = tmp; 375 gl = tmp;
325 } else { 376 } else {
326 list_add_tail(&gl->gl_list, &gl_hash_table[hash].hb_list); 377 list_add_tail(&gl->gl_list, &gl_hash_table[hash].hb_list);
327 write_unlock(&gl_hash_locks[hash]); 378 write_unlock(gl_lock_addr(hash));
328 } 379 }
329 380
330 *glp = gl; 381 *glp = gl;
@@ -1879,12 +1930,12 @@ static int examine_bucket(glock_examiner examiner, struct gfs2_sbd *sdp,
1879 memset(&plug.gl_flags, 0, sizeof(unsigned long)); 1930 memset(&plug.gl_flags, 0, sizeof(unsigned long));
1880 set_bit(GLF_PLUG, &plug.gl_flags); 1931 set_bit(GLF_PLUG, &plug.gl_flags);
1881 1932
1882 write_lock(&gl_hash_locks[hash]); 1933 write_lock(gl_lock_addr(hash));
1883 list_add(&plug.gl_list, &gl_hash_table[hash].hb_list); 1934 list_add(&plug.gl_list, &gl_hash_table[hash].hb_list);
1884 write_unlock(&gl_hash_locks[hash]); 1935 write_unlock(gl_lock_addr(hash));
1885 1936
1886 for (;;) { 1937 for (;;) {
1887 write_lock(&gl_hash_locks[hash]); 1938 write_lock(gl_lock_addr(hash));
1888 1939
1889 for (;;) { 1940 for (;;) {
1890 tmp = plug.gl_list.next; 1941 tmp = plug.gl_list.next;
@@ -1892,7 +1943,7 @@ static int examine_bucket(glock_examiner examiner, struct gfs2_sbd *sdp,
1892 if (tmp == &gl_hash_table[hash].hb_list) { 1943 if (tmp == &gl_hash_table[hash].hb_list) {
1893 list_del(&plug.gl_list); 1944 list_del(&plug.gl_list);
1894 entries = !list_empty(&gl_hash_table[hash].hb_list); 1945 entries = !list_empty(&gl_hash_table[hash].hb_list);
1895 write_unlock(&gl_hash_locks[hash]); 1946 write_unlock(gl_lock_addr(hash));
1896 return entries; 1947 return entries;
1897 } 1948 }
1898 gl = list_entry(tmp, struct gfs2_glock, gl_list); 1949 gl = list_entry(tmp, struct gfs2_glock, gl_list);
@@ -1911,7 +1962,7 @@ static int examine_bucket(glock_examiner examiner, struct gfs2_sbd *sdp,
1911 break; 1962 break;
1912 } 1963 }
1913 1964
1914 write_unlock(&gl_hash_locks[hash]); 1965 write_unlock(gl_lock_addr(hash));
1915 1966
1916 examiner(gl); 1967 examiner(gl);
1917 } 1968 }
@@ -2204,7 +2255,7 @@ static int gfs2_dump_lockstate(struct gfs2_sbd *sdp)
2204 2255
2205 for (x = 0; x < GFS2_GL_HASH_SIZE; x++) { 2256 for (x = 0; x < GFS2_GL_HASH_SIZE; x++) {
2206 2257
2207 read_lock(&gl_hash_locks[x]); 2258 read_lock(gl_lock_addr(x));
2208 2259
2209 list_for_each_entry(gl, &gl_hash_table[x].hb_list, gl_list) { 2260 list_for_each_entry(gl, &gl_hash_table[x].hb_list, gl_list) {
2210 if (test_bit(GLF_PLUG, &gl->gl_flags)) 2261 if (test_bit(GLF_PLUG, &gl->gl_flags))
@@ -2217,7 +2268,7 @@ static int gfs2_dump_lockstate(struct gfs2_sbd *sdp)
2217 break; 2268 break;
2218 } 2269 }
2219 2270
2220 read_unlock(&gl_hash_locks[x]); 2271 read_unlock(gl_lock_addr(x));
2221 2272
2222 if (error) 2273 if (error)
2223 break; 2274 break;
@@ -2231,9 +2282,13 @@ int __init gfs2_glock_init(void)
2231{ 2282{
2232 unsigned i; 2283 unsigned i;
2233 for(i = 0; i < GFS2_GL_HASH_SIZE; i++) { 2284 for(i = 0; i < GFS2_GL_HASH_SIZE; i++) {
2234 rwlock_init(&gl_hash_locks[i]);
2235 INIT_LIST_HEAD(&gl_hash_table[i].hb_list); 2285 INIT_LIST_HEAD(&gl_hash_table[i].hb_list);
2236 } 2286 }
2287#ifdef GL_HASH_LOCK_SZ
2288 for(i = 0; i < GL_HASH_LOCK_SZ; i++) {
2289 rwlock_init(&gl_hash_locks[i]);
2290 }
2291#endif
2237 return 0; 2292 return 0;
2238} 2293}
2239 2294