Whamcloud - gitweb
LU-264 Integrate upstream ext4 MMP chnages
[fs/lustre-release.git] / ldiskfs / kernel_patches / patches / ext4-dynlocks-common-rhel6.patch
1 Index: linux-stage/fs/ext4/dynlocks.c
2 ===================================================================
3 --- /dev/null
4 +++ linux-stage/fs/ext4/dynlocks.c
5 @@ -0,0 +1,236 @@
6 +/*
7 + * Dynamic Locks
8 + *
9 + * struct dynlock is lockspace
10 + * one may request lock (exclusive or shared) for some value
11 + * in that lockspace
12 + *
13 + */
14 +
15 +#include <linux/dynlocks.h>
16 +#include <linux/module.h>
17 +#include <linux/slab.h>
18 +#include <linux/sched.h>
19 +
20 +#define DYNLOCK_HANDLE_MAGIC   0xd19a10c
21 +#define DYNLOCK_HANDLE_DEAD    0xd1956ee
22 +#define DYNLOCK_LIST_MAGIC     0x11ee91e6
23 +
24 +static struct kmem_cache * dynlock_cachep = NULL;
25 +
26 +struct dynlock_handle {
27 +       unsigned                dh_magic;
28 +       struct list_head        dh_list;
29 +       unsigned long           dh_value;       /* lock value */
30 +       int                     dh_refcount;    /* number of users */
31 +       int                     dh_readers;
32 +       int                     dh_writers;
33 +       int                     dh_pid;         /* holder of the lock */
34 +       wait_queue_head_t       dh_wait;
35 +};
36 +
37 +int __init dynlock_cache_init(void)
38 +{
39 +       int rc = 0;
40 +
41 +       printk(KERN_INFO "init dynlocks cache\n");
42 +       dynlock_cachep = kmem_cache_create("dynlock_cache",
43 +                                        sizeof(struct dynlock_handle),
44 +                                        0,
45 +                                        SLAB_HWCACHE_ALIGN,
46 +                                        NULL);
47 +       if (dynlock_cachep == NULL) {
48 +               printk(KERN_ERR "Not able to create dynlock cache");
49 +               rc = -ENOMEM;
50 +       }
51 +       return rc;
52 +}
53 +
54 +void __exit dynlock_cache_exit(void)
55 +{
56 +       printk(KERN_INFO "exit dynlocks cache\n");
57 +       kmem_cache_destroy(dynlock_cachep);
58 +}
59 +
60 +/*
61 + * dynlock_init
62 + *
63 + * initialize lockspace
64 + *
65 + */
66 +void dynlock_init(struct dynlock *dl)
67 +{
68 +       spin_lock_init(&dl->dl_list_lock);
69 +       INIT_LIST_HEAD(&dl->dl_list);
70 +       dl->dl_magic = DYNLOCK_LIST_MAGIC;
71 +}
72 +EXPORT_SYMBOL(dynlock_init);
73 +
74 +/*
75 + * dynlock_lock
76 + *
77 + * acquires lock (exclusive or shared) in specified lockspace
78 + * each lock in lockspace is allocated separately, so user have
79 + * to specify GFP flags.
80 + * routine returns pointer to lock. this pointer is intended to
81 + * be passed to dynlock_unlock
82 + *
83 + */
84 +struct dynlock_handle *dynlock_lock(struct dynlock *dl, unsigned long value,
85 +                                   enum dynlock_type lt, gfp_t gfp)
86 +{
87 +       struct dynlock_handle *nhl = NULL;
88 +       struct dynlock_handle *hl;
89 +
90 +       BUG_ON(dl == NULL);
91 +       BUG_ON(dl->dl_magic != DYNLOCK_LIST_MAGIC);
92 +
93 +repeat:
94 +       /* find requested lock in lockspace */
95 +       spin_lock(&dl->dl_list_lock);
96 +       BUG_ON(dl->dl_list.next == NULL);
97 +       BUG_ON(dl->dl_list.prev == NULL);
98 +       list_for_each_entry(hl, &dl->dl_list, dh_list) {
99 +               BUG_ON(hl->dh_list.next == NULL);
100 +               BUG_ON(hl->dh_list.prev == NULL);
101 +               BUG_ON(hl->dh_magic != DYNLOCK_HANDLE_MAGIC);
102 +               if (hl->dh_value == value) {
103 +                       /* lock is found */
104 +                       if (nhl) {
105 +                               /* someone else just allocated
106 +                                * lock we didn't find and just created
107 +                                * so, we drop our lock
108 +                                */
109 +                               kmem_cache_free(dynlock_cachep, nhl);
110 +                               nhl = NULL;
111 +                       }
112 +                       hl->dh_refcount++;
113 +                       goto found;
114 +               }
115 +       }
116 +       /* lock not found */
117 +       if (nhl) {
118 +               /* we already have allocated lock. use it */
119 +               hl = nhl;
120 +               nhl = NULL;
121 +               list_add(&hl->dh_list, &dl->dl_list);
122 +               goto found;
123 +       }
124 +       spin_unlock(&dl->dl_list_lock);
125 +       
126 +       /* lock not found and we haven't allocated lock yet. allocate it */
127 +       nhl = kmem_cache_alloc(dynlock_cachep, gfp);
128 +       if (nhl == NULL)
129 +               return NULL;
130 +       nhl->dh_refcount = 1;
131 +       nhl->dh_value = value;
132 +       nhl->dh_readers = 0;
133 +       nhl->dh_writers = 0;
134 +       nhl->dh_magic = DYNLOCK_HANDLE_MAGIC;
135 +       init_waitqueue_head(&nhl->dh_wait);
136 +
137 +       /* while lock is being allocated, someone else may allocate it
138 +        * and put onto to list. check this situation
139 +        */
140 +       goto repeat;
141 +
142 +found:
143 +       if (lt == DLT_WRITE) {
144 +               /* exclusive lock: user don't want to share lock at all
145 +                * NOTE: one process may take the same lock several times
146 +                * this functionaly is useful for rename operations */
147 +               while ((hl->dh_writers && hl->dh_pid != current->pid) ||
148 +                               hl->dh_readers) {
149 +                       spin_unlock(&dl->dl_list_lock);
150 +                       wait_event(hl->dh_wait,
151 +                               hl->dh_writers == 0 && hl->dh_readers == 0);
152 +                       spin_lock(&dl->dl_list_lock);
153 +               }
154 +               hl->dh_writers++;
155 +       } else {
156 +               /* shared lock: user do not want to share lock with writer */
157 +               while (hl->dh_writers) {
158 +                       spin_unlock(&dl->dl_list_lock);
159 +                       wait_event(hl->dh_wait, hl->dh_writers == 0);
160 +                       spin_lock(&dl->dl_list_lock);
161 +               }
162 +               hl->dh_readers++;
163 +       }
164 +       hl->dh_pid = current->pid;
165 +       spin_unlock(&dl->dl_list_lock);
166 +
167 +       return hl;
168 +}
169 +EXPORT_SYMBOL(dynlock_lock);
170 +
171 +
172 +/*
173 + * dynlock_unlock
174 + *
175 + * user have to specify lockspace (dl) and pointer to lock structure
176 + * returned by dynlock_lock()
177 + *
178 + */
179 +void dynlock_unlock(struct dynlock *dl, struct dynlock_handle *hl)
180 +{
181 +       int wakeup = 0;
182 +       
183 +       BUG_ON(dl == NULL);
184 +       BUG_ON(hl == NULL);
185 +       BUG_ON(dl->dl_magic != DYNLOCK_LIST_MAGIC);
186 +
187 +       if (hl->dh_magic != DYNLOCK_HANDLE_MAGIC)
188 +               printk(KERN_EMERG "wrong lock magic: %#x\n", hl->dh_magic);
189 +
190 +       BUG_ON(hl->dh_magic != DYNLOCK_HANDLE_MAGIC);
191 +       BUG_ON(hl->dh_writers != 0 && current->pid != hl->dh_pid);
192 +
193 +       spin_lock(&dl->dl_list_lock);
194 +       if (hl->dh_writers) {
195 +               BUG_ON(hl->dh_readers != 0);
196 +               hl->dh_writers--;
197 +               if (hl->dh_writers == 0)
198 +                       wakeup = 1;
199 +       } else if (hl->dh_readers) {
200 +               hl->dh_readers--;
201 +               if (hl->dh_readers == 0)
202 +                       wakeup = 1;
203 +       } else {
204 +               BUG();
205 +       }
206 +       if (wakeup) {
207 +               hl->dh_pid = 0;
208 +               wake_up(&hl->dh_wait);
209 +       }
210 +       if (--(hl->dh_refcount) == 0) {
211 +               hl->dh_magic = DYNLOCK_HANDLE_DEAD;
212 +               list_del(&hl->dh_list);
213 +               kmem_cache_free(dynlock_cachep, hl);
214 +       }
215 +       spin_unlock(&dl->dl_list_lock);
216 +}
217 +EXPORT_SYMBOL(dynlock_unlock);
218 +
219 +int dynlock_is_locked(struct dynlock *dl, unsigned long value)
220 +{
221 +       struct dynlock_handle *hl;
222 +       int result = 0;
223 +
224 +       /* find requested lock in lockspace */
225 +       spin_lock(&dl->dl_list_lock);
226 +       BUG_ON(dl->dl_list.next == NULL);
227 +       BUG_ON(dl->dl_list.prev == NULL);
228 +       list_for_each_entry(hl, &dl->dl_list, dh_list) {
229 +               BUG_ON(hl->dh_list.next == NULL);
230 +               BUG_ON(hl->dh_list.prev == NULL);
231 +               BUG_ON(hl->dh_magic != DYNLOCK_HANDLE_MAGIC);
232 +               if (hl->dh_value == value && hl->dh_pid == current->pid) {
233 +                       /* lock is found */
234 +                       result = 1;
235 +                       break;
236 +               }
237 +       }
238 +       spin_unlock(&dl->dl_list_lock);
239 +       return result;
240 +}
241 +EXPORT_SYMBOL(dynlock_is_locked);
242 Index: linux-stage/include/linux/dynlocks.h
243 ===================================================================
244 --- /dev/null
245 +++ linux-stage/include/linux/dynlocks.h
246 @@ -0,0 +1,34 @@
247 +#ifndef _LINUX_DYNLOCKS_H
248 +#define _LINUX_DYNLOCKS_H
249 +
250 +#include <linux/list.h>
251 +#include <linux/wait.h>
252 +
253 +struct dynlock_handle;
254 +
255 +/*
256 + * lock's namespace:
257 + *   - list of locks
258 + *   - lock to protect this list
259 + */
260 +struct dynlock {
261 +       unsigned                dl_magic;
262 +       struct list_head        dl_list;
263 +       spinlock_t              dl_list_lock;
264 +};
265 +
266 +enum dynlock_type {
267 +       DLT_WRITE,
268 +       DLT_READ
269 +};
270 +
271 +int dynlock_cache_init(void);
272 +void dynlock_cache_exit(void);
273 +void dynlock_init(struct dynlock *dl);
274 +struct dynlock_handle *dynlock_lock(struct dynlock *dl, unsigned long value,
275 +                                   enum dynlock_type lt, gfp_t gfp);
276 +void dynlock_unlock(struct dynlock *dl, struct dynlock_handle *lock);
277 +int dynlock_is_locked(struct dynlock *dl, unsigned long value);
278 +
279 +#endif
280 +
281 Index: linux-stage/fs/ext4/Makefile
282 ===================================================================
283 --- linux-stage.orig/fs/ext4/Makefile
284 +++ linux-stage/fs/ext4/Makefile
285 @@ -7,7 +7,7 @@ obj-$(CONFIG_EXT4_FS) += ext4.o
286  ext4-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \
287                 ioctl.o namei.o super.o symlink.o hash.o resize.o extents.o \
288                 ext4_jbd2.o migrate.o mballoc.o block_validity.o move_extent.o \
289 -               mmp.o
290 +               mmp.o dynlocks.o
291  
292  ext4-$(CONFIG_EXT4_FS_XATTR)           += xattr.o xattr_user.o xattr_trusted.o
293  ext4-$(CONFIG_EXT4_FS_POSIX_ACL)       += acl.o
294 Index: linux-stage/fs/ext4/super.c
295 ===================================================================
296 --- linux-stage.orig/fs/ext4/super.c
297 +++ linux-stage/fs/ext4/super.c
298 @@ -4125,32 +4125,37 @@ static int __init init_ext4_fs(void)
299                 return err;
300         ext4_kset = kset_create_and_add("ext4", NULL, fs_kobj);
301         if (!ext4_kset)
302 -               goto out4;
303 +               goto out5;
304         ext4_proc_root = proc_mkdir("fs/ext4", NULL);
305         err = init_ext4_mballoc();
306         if (err)
307 -               goto out3;
308 +               goto out4;
309  
310         err = init_ext4_xattr();
311         if (err)
312 -               goto out2;
313 +               goto out3;
314         err = init_inodecache();
315         if (err)
316 +               goto out2;
317 +       err = dynlock_cache_init();
318 +       if (err)
319                 goto out1;
320         err = register_filesystem(&ext4_fs_type);
321         if (err)
322                 goto out;
323         return 0;
324  out:
325 -       destroy_inodecache();
326 +       dynlock_cache_exit();
327  out1:
328 -       exit_ext4_xattr();
329 +       destroy_inodecache();
330  out2:
331 -       exit_ext4_mballoc();
332 +       exit_ext4_xattr();
333  out3:
334 +       exit_ext4_mballoc();
335 +out4:
336         remove_proc_entry("fs/ext4", NULL);
337         kset_unregister(ext4_kset);
338 -out4:
339 +out5:
340         exit_ext4_system_zone();
341         return err;
342  }
343 @@ -4158,6 +4163,7 @@ out4:
344  static void __exit exit_ext4_fs(void)
345  {
346         unregister_filesystem(&ext4_fs_type);
347 +       dynlock_cache_exit();
348         destroy_inodecache();
349         exit_ext4_xattr();
350         exit_ext4_mballoc();