Whamcloud - gitweb
Branch HEAD
[fs/lustre-release.git] / lustre / kernel_patches / patches / ext3-pdirops-2.6.10-fc3.patch
1  fs/ext3/ialloc.c          |    3 
2  fs/ext3/inode.c           |    3 
3  fs/ext3/namei.c           |  582 +++++++++++++++++++++++++++++++++++++---------
4  fs/ext3/super.c           |   14 +
5  include/linux/ext3_fs.h   |    1 
6  include/linux/ext3_fs_i.h |    6 
7  6 files changed, 500 insertions(+), 109 deletions(-)
8
9 Index: linux-2.6.10/fs/ext3/super.c
10 ===================================================================
11 --- linux-2.6.10.orig/fs/ext3/super.c   2005-04-06 19:38:35.000000000 +0400
12 +++ linux-2.6.10/fs/ext3/super.c        2005-06-29 20:09:30.000000000 +0400
13 @@ -458,6 +458,9 @@
14  #endif
15         ei->i_rsv_window.rsv_end = EXT3_RESERVE_WINDOW_NOT_ALLOCATED;
16         ei->vfs_inode.i_version = 1;
17 +       dynlock_init(&ei->i_htree_lock);
18 +       sema_init(&ei->i_rename_sem, 1);
19 +       sema_init(&ei->i_append_sem, 1);
20         return &ei->vfs_inode;
21  }
22  
23 @@ -588,7 +591,7 @@
24         Opt_commit, Opt_journal_update, Opt_journal_inum,
25         Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback,
26         Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
27 -       Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0,
28 +       Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_pdirops,
29         Opt_ignore, Opt_barrier, Opt_err, Opt_resize,
30  };
31  
32 @@ -637,6 +640,7 @@
33         {Opt_ignore, "quota"},
34         {Opt_ignore, "usrquota"},
35         {Opt_barrier, "barrier=%u"},
36 +       {Opt_pdirops, "pdirops"},
37         {Opt_err, NULL},
38         {Opt_resize, "resize"},
39  };
40 Index: linux-2.6.10/fs/ext3/namei.c
41 ===================================================================
42 --- linux-2.6.10.orig/fs/ext3/namei.c   2004-12-25 00:34:58.000000000 +0300
43 +++ linux-2.6.10/fs/ext3/namei.c        2005-06-29 20:12:23.000000000 +0400
44 @@ -53,6 +53,9 @@
45  {
46         struct buffer_head *bh;
47  
48 +       /* with parallel dir operations all appends
49 +        * have to be serialized -bzzz */
50 +       down(&EXT3_I(inode)->i_append_sem);
51         *block = inode->i_size >> inode->i_sb->s_blocksize_bits;
52  
53         if ((bh = ext3_bread(handle, inode, *block, 1, err))) {
54 @@ -60,6 +63,8 @@
55                 EXT3_I(inode)->i_disksize = inode->i_size;
56                 ext3_journal_get_write_access(handle,bh);
57         }
58 +       up(&EXT3_I(inode)->i_append_sem);
59 +       
60         return bh;
61  }
62  
63 @@ -133,6 +138,8 @@
64         struct buffer_head *bh;
65         struct dx_entry *entries;
66         struct dx_entry *at;
67 +       unsigned long leaf;
68 +       unsigned int curidx;
69  };
70  
71  struct dx_map_entry
72 @@ -141,6 +148,30 @@
73         u32 offs;
74  };
75  
76 +/* FIXME: this should be reworked using bb_spin_lock
77 + * introduced in -mm tree
78 + */
79 +#define BH_DXLock      25
80 +
81 +static inline void dx_lock_bh(struct buffer_head volatile *bh)
82 +{
83 +#ifdef CONFIG_SMP
84 +        while (test_and_set_bit(BH_DXLock, &bh->b_state)) {
85 +                while (test_bit(BH_DXLock, &bh->b_state))
86 +                        cpu_relax();
87 +        }
88 +#endif
89 +}
90 +
91 +static inline void dx_unlock_bh(struct buffer_head *bh)
92 +{
93 +#ifdef CONFIG_SMP
94 +        smp_mb__before_clear_bit();
95 +        clear_bit(BH_DXLock, &bh->b_state);
96 +#endif
97 +}
98 +
99 +
100  #ifdef CONFIG_EXT3_INDEX
101  static inline unsigned dx_get_block (struct dx_entry *entry);
102  static void dx_set_block (struct dx_entry *entry, unsigned value);
103 @@ -152,7 +183,7 @@
104  static void dx_set_limit (struct dx_entry *entries, unsigned value);
105  static unsigned dx_root_limit (struct inode *dir, unsigned infosize);
106  static unsigned dx_node_limit (struct inode *dir);
107 -static struct dx_frame *dx_probe(struct dentry *dentry,
108 +static struct dx_frame *dx_probe(struct qstr *name,
109                                  struct inode *dir,
110                                  struct dx_hash_info *hinfo,
111                                  struct dx_frame *frame,
112 @@ -164,15 +195,18 @@
113  static struct ext3_dir_entry_2 *dx_move_dirents (char *from, char *to,
114                 struct dx_map_entry *offsets, int count);
115  static struct ext3_dir_entry_2* dx_pack_dirents (char *base, int size);
116 -static void dx_insert_block (struct dx_frame *frame, u32 hash, u32 block);
117 +static void dx_insert_block (struct inode *, struct dx_frame *, u32, u32, u32);
118  static int ext3_htree_next_block(struct inode *dir, __u32 hash,
119                                  struct dx_frame *frame,
120                                  struct dx_frame *frames, 
121                                  __u32 *start_hash);
122  static struct buffer_head * ext3_dx_find_entry(struct dentry *dentry,
123 -                      struct ext3_dir_entry_2 **res_dir, int *err);
124 +                      struct ext3_dir_entry_2 **res_dir, int *err,
125 +                      int rwlock, void **lock);
126  static int ext3_dx_add_entry(handle_t *handle, struct dentry *dentry,
127                              struct inode *inode);
128 +static  void *ext3_lock_htree(struct inode *, unsigned long, int);
129 +static  void ext3_unlock_htree(struct inode *, void *);
130  
131  /*
132   * Future: use high four bits of block for coalesce-on-delete flags
133 @@ -316,6 +350,94 @@
134  #endif /* DX_DEBUG */
135  
136  /*
137 + * dx_find_position
138 + *
139 + * search position of specified hash in index
140 + *
141 + */
142 +
143 +struct dx_entry * dx_find_position(struct dx_entry * entries, u32 hash)
144 +{
145 +       struct dx_entry *p, *q, *m;
146 +       int count;
147 +
148 +       count = dx_get_count(entries);
149 +       p = entries + 1;
150 +       q = entries + count - 1;
151 +       while (p <= q)
152 +       {
153 +               m = p + (q - p)/2;
154 +               if (dx_get_hash(m) > hash)
155 +                       q = m - 1;
156 +               else
157 +                       p = m + 1;
158 +       }
159 +       return p - 1;
160 +}
161 +
162 +/*
163 + * returns 1 if path is unchanged
164 + */
165 +int dx_check_path(struct dx_frame *frame, u32 hash)
166 +{
167 +       struct dx_entry *p;
168 +       int ret = 1;
169 +
170 +       dx_lock_bh(frame->bh);
171 +       p = dx_find_position(frame->entries, hash);
172 +       if (frame->leaf != dx_get_block(p))
173 +               ret = 0;
174 +       dx_unlock_bh(frame->bh);
175 +       
176 +       return ret;
177 +}
178 +
179 +/*
180 + * 0 - changed
181 + * 1 - hasn't changed
182 + */
183 +static int
184 +dx_check_full_path(struct dx_frame *frames, struct dx_hash_info *hinfo)
185 +{
186 +       struct dx_entry *p;
187 +       struct dx_frame *frame = frames;
188 +       u32 leaf;
189 +
190 +       /* check first level */
191 +       dx_lock_bh(frame->bh);
192 +       p = dx_find_position(frame->entries, hinfo->hash);
193 +       leaf = dx_get_block(p);
194 +       dx_unlock_bh(frame->bh);
195 +       
196 +       if (leaf != frame->leaf) 
197 +               return 0;
198 +       
199 +       /* is there 2nd level? */
200 +       frame++;
201 +       if (frame->bh == NULL)
202 +               return 1;
203 +
204 +       /* check second level */
205 +       dx_lock_bh(frame->bh);
206 +
207 +       /* probably 1st level got changed, check it */
208 +       if (!dx_check_path(frames, hinfo->hash)) {
209 +               /* path changed */
210 +               dx_unlock_bh(frame->bh);
211 +               return 0;
212 +       }
213 +
214 +       p = dx_find_position(frame->entries, hinfo->hash);
215 +       leaf = dx_get_block(p);
216 +       dx_unlock_bh(frame->bh);
217 +       
218 +       if (leaf != frame->leaf)
219 +               return 0;
220 +
221 +       return 1;
222 +}
223 +
224 +/*
225   * Probe for a directory leaf block to search.
226   *
227   * dx_probe can return ERR_BAD_DX_DIR, which means there was a format
228 @@ -325,19 +447,20 @@
229   * back to userspace.
230   */
231  static struct dx_frame *
232 -dx_probe(struct dentry *dentry, struct inode *dir,
233 +dx_probe(struct qstr *name, struct inode *dir,
234          struct dx_hash_info *hinfo, struct dx_frame *frame_in, int *err)
235  {
236 -       unsigned count, indirect;
237 -       struct dx_entry *at, *entries, *p, *q, *m;
238 +       unsigned indirect;
239 +       struct dx_entry *at, *entries;
240         struct dx_root *root;
241         struct buffer_head *bh;
242         struct dx_frame *frame = frame_in;
243         u32 hash;
244 +       unsigned int curidx;
245  
246         frame->bh = NULL;
247 -       if (dentry)
248 -               dir = dentry->d_parent->d_inode;
249 +       frame[1].bh = NULL;
250 +
251         if (!(bh = ext3_bread (NULL,dir, 0, 0, err)))
252                 goto fail;
253         root = (struct dx_root *) bh->b_data;
254 @@ -353,8 +476,8 @@
255         }
256         hinfo->hash_version = root->info.hash_version;
257         hinfo->seed = EXT3_SB(dir->i_sb)->s_hash_seed;
258 -       if (dentry)
259 -               ext3fs_dirhash(dentry->d_name.name, dentry->d_name.len, hinfo);
260 +       if (name)
261 +               ext3fs_dirhash(name->name, name->len, hinfo);
262         hash = hinfo->hash;
263  
264         if (root->info.unused_flags & 1) {
265 @@ -366,7 +489,19 @@
266                 goto fail;
267         }
268  
269 +repeat:
270 +       curidx = 0;
271 +       entries = (struct dx_entry *) (((char *)&root->info) +
272 +                                      root->info.info_length);
273 +       assert(dx_get_limit(entries) == dx_root_limit(dir,
274 +                                                     root->info.info_length));
275 +       dxtrace (printk("Look up %x", hash));
276 +       dx_lock_bh(bh);
277 +       /* indirect must be initialized under bh lock because
278 +        * 2nd level creation procedure may change it and dx_probe()
279 +        * will suggest htree is still single-level -bzzz */
280         if ((indirect = root->info.indirect_levels) > 1) {
281 +               dx_unlock_bh(bh);
282                 ext3_warning(dir->i_sb, __FUNCTION__,
283                              "Unimplemented inode hash depth: %#06x",
284                              root->info.indirect_levels);
285 @@ -374,56 +509,46 @@
286                 *err = ERR_BAD_DX_DIR;
287                 goto fail;
288         }
289 -
290 -       entries = (struct dx_entry *) (((char *)&root->info) +
291 -                                      root->info.info_length);
292 -       assert(dx_get_limit(entries) == dx_root_limit(dir,
293 -                                                     root->info.info_length));
294 -       dxtrace (printk("Look up %x", hash));
295 +       
296         while (1)
297         {
298 -               count = dx_get_count(entries);
299 -               assert (count && count <= dx_get_limit(entries));
300 -               p = entries + 1;
301 -               q = entries + count - 1;
302 -               while (p <= q)
303 -               {
304 -                       m = p + (q - p)/2;
305 -                       dxtrace(printk("."));
306 -                       if (dx_get_hash(m) > hash)
307 -                               q = m - 1;
308 -                       else
309 -                               p = m + 1;
310 -               }
311 -
312 -               if (0) // linear search cross check
313 -               {
314 -                       unsigned n = count - 1;
315 -                       at = entries;
316 -                       while (n--)
317 -                       {
318 -                               dxtrace(printk(","));
319 -                               if (dx_get_hash(++at) > hash)
320 -                               {
321 -                                       at--;
322 -                                       break;
323 -                               }
324 -                       }
325 -                       assert (at == p - 1);
326 -               }
327 -
328 -               at = p - 1;
329 -               dxtrace(printk(" %x->%u\n", at == entries? 0: dx_get_hash(at), dx_get_block(at)));
330 +               at = dx_find_position(entries, hinfo->hash);
331 +               dxtrace(printk(" %x->%u\n",
332 +                               at == entries? 0: dx_get_hash(at),
333 +                               dx_get_block(at)));
334                 frame->bh = bh;
335                 frame->entries = entries;
336                 frame->at = at;
337 -               if (!indirect--) return frame;
338 -               if (!(bh = ext3_bread (NULL,dir, dx_get_block(at), 0, err)))
339 +               frame->curidx = curidx;
340 +               frame->leaf = dx_get_block(at);
341 +               if (!indirect--) {
342 +                       dx_unlock_bh(bh);
343 +                       return frame;
344 +               }
345 +               
346 +               /* step into next htree level */
347 +               curidx = dx_get_block(at);
348 +               dx_unlock_bh(bh);
349 +               if (!(bh = ext3_bread (NULL,dir, frame->leaf, 0, err)))
350                         goto fail2;
351 +               
352 +               dx_lock_bh(bh);
353 +               /* splitting may change root index block and move
354 +                * hash we're looking for into another index block
355 +                * so, we have to check this situation and repeat
356 +                * from begining if path got changed -bzzz */
357 +               if (!dx_check_path(frame, hash)) {
358 +                       dx_unlock_bh(bh);
359 +                       bh = frame->bh;
360 +                       indirect++;
361 +                       goto repeat;
362 +               }
363 +               
364                 at = entries = ((struct dx_node *) bh->b_data)->entries;
365                 assert (dx_get_limit(entries) == dx_node_limit (dir));
366                 frame++;
367         }
368 +       dx_unlock_bh(bh);
369  fail2:
370         while (frame >= frame_in) {
371                 brelse(frame->bh);
372 @@ -437,8 +562,7 @@
373  {
374         if (frames[0].bh == NULL)
375                 return;
376 -
377 -       if (((struct dx_root *) frames[0].bh->b_data)->info.indirect_levels)
378 +       if (frames[1].bh != NULL)
379                 brelse(frames[1].bh);
380         brelse(frames[0].bh);
381  }
382 @@ -479,8 +603,10 @@
383          * nodes need to be read.
384          */
385         while (1) {
386 -               if (++(p->at) < p->entries + dx_get_count(p->entries))
387 +               if (++(p->at) < p->entries + dx_get_count(p->entries)) {
388 +                       p->leaf = dx_get_block(p->at);
389                         break;
390 +               }
391                 if (p == frames)
392                         return 0;
393                 num_frames++;
394 @@ -506,13 +632,17 @@
395          * block so no check is necessary
396          */
397         while (num_frames--) {
398 -               if (!(bh = ext3_bread(NULL, dir, dx_get_block(p->at),
399 -                                     0, &err)))
400 +               u32 idx;
401 +               
402 +               idx = p->leaf = dx_get_block(p->at);
403 +               if (!(bh = ext3_bread(NULL, dir, idx, 0, &err)))
404                         return err; /* Failure */
405                 p++;
406                 brelse (p->bh);
407                 p->bh = bh;
408                 p->at = p->entries = ((struct dx_node *) bh->b_data)->entries;
409 +               p->curidx = idx;
410 +               p->leaf = dx_get_block(p->at);
411         }
412         return 1;
413  }
414 @@ -673,7 +803,8 @@
415                         count++;
416                 }
417                 /* XXX: do we need to check rec_len == 0 case? -Chris */
418 -               de = (struct ext3_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len));
419 +               de = (struct ext3_dir_entry_2 *)((char*)de +
420 +                               le16_to_cpu(de->rec_len));
421         }
422         return count;
423  }
424 @@ -706,7 +837,8 @@
425         } while(more);
426  }
427  
428 -static void dx_insert_block(struct dx_frame *frame, u32 hash, u32 block)
429 +static void dx_insert_block(struct inode *dir, struct dx_frame *frame,
430 +                       u32 hash, u32 block, u32 idx)
431  {
432         struct dx_entry *entries = frame->entries;
433         struct dx_entry *old = frame->at, *new = old + 1;
434 @@ -718,6 +850,7 @@
435         dx_set_hash(new, hash);
436         dx_set_block(new, block);
437         dx_set_count(entries, count + 1);
438 +       
439  }
440  #endif
441  
442 @@ -798,7 +931,8 @@
443   * to brelse() it when appropriate.
444   */
445  static struct buffer_head * ext3_find_entry (struct dentry *dentry,
446 -                                       struct ext3_dir_entry_2 ** res_dir)
447 +                                       struct ext3_dir_entry_2 ** res_dir,
448 +                                       int rwlock, void **lock)
449  {
450         struct super_block * sb;
451         struct buffer_head * bh_use[NAMEI_RA_SIZE];
452 @@ -814,6 +948,7 @@
453         int namelen;
454         const u8 *name;
455         unsigned blocksize;
456 +       int do_not_use_dx = 0;
457  
458         *res_dir = NULL;
459         sb = dir->i_sb;
460 @@ -822,9 +957,10 @@
461         name = dentry->d_name.name;
462         if (namelen > EXT3_NAME_LEN)
463                 return NULL;
464 +repeat:
465  #ifdef CONFIG_EXT3_INDEX
466         if (is_dx(dir)) {
467 -               bh = ext3_dx_find_entry(dentry, res_dir, &err);
468 +               bh = ext3_dx_find_entry(dentry, res_dir, &err, rwlock, lock);
469                 /*
470                  * On success, or if the error was file not found,
471                  * return.  Otherwise, fall back to doing a search the
472 @@ -833,8 +969,14 @@
473                 if (bh || (err != ERR_BAD_DX_DIR))
474                         return bh;
475                 dxtrace(printk("ext3_find_entry: dx failed, falling back\n"));
476 +               do_not_use_dx = 1;
477         }
478  #endif
479 +       *lock = ext3_lock_htree(dir, 0, rwlock);
480 +       if (is_dx(dir) && !do_not_use_dx) {
481 +               ext3_unlock_htree(dir, *lock);
482 +               goto repeat;
483 +       }
484         nblocks = dir->i_size >> EXT3_BLOCK_SIZE_BITS(sb);
485         start = EXT3_I(dir)->i_dir_start_lookup;
486         if (start >= nblocks)
487 @@ -907,12 +1049,17 @@
488         /* Clean up the read-ahead blocks */
489         for (; ra_ptr < ra_max; ra_ptr++)
490                 brelse (bh_use[ra_ptr]);
491 +       if (!ret) {
492 +               ext3_unlock_htree(dir, *lock);
493 +               *lock = NULL;
494 +       }
495         return ret;
496  }
497  
498  #ifdef CONFIG_EXT3_INDEX
499  static struct buffer_head * ext3_dx_find_entry(struct dentry *dentry,
500 -                      struct ext3_dir_entry_2 **res_dir, int *err)
501 +                      struct ext3_dir_entry_2 **res_dir, int *err,
502 +                      int rwlock, void **lock)
503  {
504         struct super_block * sb;
505         struct dx_hash_info     hinfo;
506 @@ -927,11 +1074,21 @@
507         struct inode *dir = dentry->d_parent->d_inode;
508  
509         sb = dir->i_sb;
510 -       if (!(frame = dx_probe(dentry, NULL, &hinfo, frames, err)))
511 +repeat:
512 +       if (!(frame = dx_probe (&dentry->d_name, dir, &hinfo, frames, err)))
513                 return NULL;
514 +       
515 +       *lock = ext3_lock_htree(dir, frame->leaf, rwlock);
516 +       /* while locking leaf we just found may get splitted
517 +        * so, we need another leaf. check this */
518 +       if (!dx_check_full_path(frames, &hinfo)) {
519 +               ext3_unlock_htree(dir, *lock);
520 +               dx_release(frames);
521 +               goto repeat;
522 +       }
523         hash = hinfo.hash;
524         do {
525 -               block = dx_get_block(frame->at);
526 +               block = frame->leaf;
527                 if (!(bh = ext3_bread (NULL,dir, block, 0, err)))
528                         goto errout;
529                 de = (struct ext3_dir_entry_2 *) bh->b_data;
530 @@ -966,6 +1123,8 @@
531         *err = -ENOENT;
532  errout:
533         dxtrace(printk("%s not found\n", name));
534 +       ext3_unlock_htree(dir, *lock);
535 +       *lock = NULL;
536         dx_release (frames);
537         return NULL;
538  }
539 @@ -976,14 +1135,16 @@
540         struct inode * inode;
541         struct ext3_dir_entry_2 * de;
542         struct buffer_head * bh;
543 +       void *lock = NULL;
544  
545         if (dentry->d_name.len > EXT3_NAME_LEN)
546                 return ERR_PTR(-ENAMETOOLONG);
547  
548 -       bh = ext3_find_entry(dentry, &de);
549 +       bh = ext3_find_entry(dentry, &de, 0, &lock);
550         inode = NULL;
551         if (bh) {
552                 unsigned long ino = le32_to_cpu(de->inode);
553 +               ext3_unlock_htree(dir, lock);
554                 brelse (bh);
555                 inode = iget(dir->i_sb, ino);
556  
557 @@ -1005,17 +1166,19 @@
558         struct dentry dotdot;
559         struct ext3_dir_entry_2 * de;
560         struct buffer_head *bh;
561 +       void *lock = NULL;
562  
563         dotdot.d_name.name = "..";
564         dotdot.d_name.len = 2;
565         dotdot.d_parent = child; /* confusing, isn't it! */
566  
567 -       bh = ext3_find_entry(&dotdot, &de);
568 +       bh = ext3_find_entry(&dotdot, &de, 0, &lock);
569         inode = NULL;
570         if (!bh)
571                 return ERR_PTR(-ENOENT);
572         ino = le32_to_cpu(de->inode);
573         brelse(bh);
574 +       ext3_unlock_htree(child->d_inode, lock);
575         inode = iget(child->d_inode->i_sb, ino);
576  
577         if (!inode)
578 @@ -1054,7 +1217,8 @@
579         unsigned rec_len = 0;
580  
581         while (count--) {
582 -               struct ext3_dir_entry_2 *de = (struct ext3_dir_entry_2 *) (from + map->offs);
583 +               struct ext3_dir_entry_2 *de =
584 +                       (struct ext3_dir_entry_2 *) (from + map->offs);
585                 rec_len = EXT3_DIR_REC_LEN(de->name_len);
586                 memcpy (to, de, rec_len);
587                 ((struct ext3_dir_entry_2 *) to)->rec_len =
588 @@ -1068,7 +1232,8 @@
589  
590  static struct ext3_dir_entry_2* dx_pack_dirents(char *base, int size)
591  {
592 -       struct ext3_dir_entry_2 *next, *to, *prev, *de = (struct ext3_dir_entry_2 *) base;
593 +       struct ext3_dir_entry_2 *next, *to, *prev;
594 +       struct ext3_dir_entry_2 *de = (struct ext3_dir_entry_2 *) base;
595         unsigned rec_len = 0;
596  
597         prev = to = de;
598 @@ -1090,7 +1255,8 @@
599  
600  static struct ext3_dir_entry_2 *do_split(handle_t *handle, struct inode *dir,
601                         struct buffer_head **bh,struct dx_frame *frame,
602 -                       struct dx_hash_info *hinfo, int *error)
603 +                       struct dx_hash_info *hinfo, void **target,
604 +                       int *error)
605  {
606         unsigned blocksize = dir->i_sb->s_blocksize;
607         unsigned count, continued;
608 @@ -1137,23 +1303,30 @@
609         hash2 = map[split].hash;
610         continued = hash2 == map[split - 1].hash;
611         dxtrace(printk("Split block %i at %x, %i/%i\n",
612 -               dx_get_block(frame->at), hash2, split, count-split));
613 -
614 +               frame->leaf, hash2, split, count-split));
615 +       
616         /* Fancy dance to stay within two buffers */
617         de2 = dx_move_dirents(data1, data2, map + split, count - split);
618         de = dx_pack_dirents(data1,blocksize);
619         de->rec_len = cpu_to_le16(data1 + blocksize - (char *) de);
620         de2->rec_len = cpu_to_le16(data2 + blocksize - (char *) de2);
621 -       dxtrace(dx_show_leaf (hinfo, (struct ext3_dir_entry_2 *) data1, blocksize, 1));
622 -       dxtrace(dx_show_leaf (hinfo, (struct ext3_dir_entry_2 *) data2, blocksize, 1));
623 +       dxtrace(dx_show_leaf(hinfo,(struct ext3_dir_entry_2*) data1, blocksize, 1));
624 +       dxtrace(dx_show_leaf(hinfo,(struct ext3_dir_entry_2*) data2, blocksize, 1));
625  
626         /* Which block gets the new entry? */
627 +       *target = NULL;
628         if (hinfo->hash >= hash2)
629         {
630                 swap(*bh, bh2);
631                 de = de2;
632 -       }
633 -       dx_insert_block (frame, hash2 + continued, newblock);
634 +
635 +               /* entry will be stored into new block
636 +                * we have to lock it before add_dirent_to_buf */
637 +               *target = ext3_lock_htree(dir, newblock, 1);
638 +       }
639 +       dx_lock_bh(frame->bh);
640 +       dx_insert_block (dir, frame, hash2 + continued, newblock, frame->curidx);
641 +       dx_unlock_bh(frame->bh);
642         err = ext3_journal_dirty_metadata (handle, bh2);
643         if (err)
644                 goto journal_error;
645 @@ -1227,7 +1400,8 @@
646         nlen = EXT3_DIR_REC_LEN(de->name_len);
647         rlen = le16_to_cpu(de->rec_len);
648         if (de->inode) {
649 -               struct ext3_dir_entry_2 *de1 = (struct ext3_dir_entry_2 *)((char *)de + nlen);
650 +               struct ext3_dir_entry_2 *de1 =
651 +                       (struct ext3_dir_entry_2 *)((char *)de + nlen);
652                 de1->rec_len = cpu_to_le16(rlen - nlen);
653                 de->rec_len = cpu_to_le16(nlen);
654                 de = de1;
655 @@ -1286,6 +1460,7 @@
656         struct dx_hash_info hinfo;
657         u32             block;
658         struct fake_dirent *fde;
659 +       void            *lock, *new_lock;
660  
661         blocksize =  dir->i_sb->s_blocksize;
662         dxtrace(printk("Creating index\n"));
663 @@ -1305,6 +1480,8 @@
664         EXT3_I(dir)->i_flags |= EXT3_INDEX_FL;
665         data1 = bh2->b_data;
666  
667 +       lock = ext3_lock_htree(dir, block, 1);
668 +
669         /* The 0th block becomes the root, move the dirents out */
670         fde = &root->dotdot;
671         de = (struct ext3_dir_entry_2 *)((char *)fde + le16_to_cpu(fde->rec_len));
672 @@ -1334,13 +1511,25 @@
673         frame->entries = entries;
674         frame->at = entries;
675         frame->bh = bh;
676 +       frame->curidx = 0;
677 +       frame->leaf = 0;
678 +       frame[1].bh = NULL;
679         bh = bh2;
680 -       de = do_split(handle,dir, &bh, frame, &hinfo, &retval);
681 +       de = do_split(handle,dir, &bh, frame, &hinfo, &new_lock, &retval);
682         dx_release (frames);
683         if (!(de))
684 -               return retval;
685 +               goto cleanup;
686 +
687 +       retval = add_dirent_to_buf(handle, dentry, inode, de, bh);
688 +cleanup:
689 +       if (new_lock)
690 +               ext3_unlock_htree(dir, new_lock);
691 +       /* we mark directory indexed in order to
692 +        * avoid races while htree being created -bzzz */
693 +       EXT3_I(dir)->i_flags |= EXT3_INDEX_FL;
694 +       ext3_unlock_htree(dir, lock);
695  
696 -       return add_dirent_to_buf(handle, dentry, inode, de, bh);
697 +       return retval;
698  }
699  #endif
700  
701 @@ -1369,11 +1558,13 @@
702         unsigned blocksize;
703         unsigned nlen, rlen;
704         u32 block, blocks;
705 +       void *lock;
706  
707         sb = dir->i_sb;
708         blocksize = sb->s_blocksize;
709         if (!dentry->d_name.len)
710                 return -EINVAL;
711 +repeat:
712  #ifdef CONFIG_EXT3_INDEX
713         if (is_dx(dir)) {
714                 retval = ext3_dx_add_entry(handle, dentry, inode);
715 @@ -1384,30 +1575,52 @@
716                 ext3_mark_inode_dirty(handle, dir);
717         }
718  #endif
719 +       lock = ext3_lock_htree(dir, 0, 1);
720 +       if (is_dx(dir)) {
721 +               /* we got lock for block 0
722 +                * probably previous holder of the lock
723 +                * created htree -bzzz */
724 +               ext3_unlock_htree(dir, lock);
725 +               goto repeat;
726 +       }
727 +
728         blocks = dir->i_size >> sb->s_blocksize_bits;
729         for (block = 0, offset = 0; block < blocks; block++) {
730                 bh = ext3_bread(handle, dir, block, 0, &retval);
731 -               if(!bh)
732 -                       return retval;
733 +               if(!bh) {
734 +                       ext3_unlock_htree(dir, lock);
735 +                       return retval;
736 +               }
737                 retval = add_dirent_to_buf(handle, dentry, inode, NULL, bh);
738 +               if (retval != -ENOSPC) {
739 +                       ext3_unlock_htree(dir, lock);
740 +                       return retval;
741 +               }
742                 if (retval != -ENOSPC)
743                         return retval;
744  
745  #ifdef CONFIG_EXT3_INDEX
746                 if (blocks == 1 && !dx_fallback &&
747 -                   EXT3_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_DIR_INDEX))
748 -                       return make_indexed_dir(handle, dentry, inode, bh);
749 +                   EXT3_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_DIR_INDEX)) {
750 +                       retval = make_indexed_dir(handle, dentry, inode, bh);
751 +                       ext3_unlock_htree(dir, lock);
752 +                       return retval;
753 +               }
754  #endif
755                 brelse(bh);
756         }
757         bh = ext3_append(handle, dir, &block, &retval);
758 -       if (!bh)
759 -               return retval;
760 -       de = (struct ext3_dir_entry_2 *) bh->b_data;
761 -       de->inode = 0;
762 -       de->rec_len = cpu_to_le16(rlen = blocksize);
763 -       nlen = 0;
764 -       return add_dirent_to_buf(handle, dentry, inode, de, bh);
765 +       if (!bh) {
766 +               ext3_unlock_htree(dir, lock);
767 +               return retval;
768 +       }
769 +       de = (struct ext3_dir_entry_2 *) bh->b_data;
770 +       de->inode = 0;
771 +       de->rec_len = cpu_to_le16(rlen = blocksize);
772 +       nlen = 0;
773 +       retval = add_dirent_to_buf(handle, dentry, inode, de, bh);
774 +       ext3_unlock_htree(dir, lock);
775 +       return retval;
776  }
777  
778  #ifdef CONFIG_EXT3_INDEX
779 @@ -1425,15 +1638,27 @@
780         struct super_block * sb = dir->i_sb;
781         struct ext3_dir_entry_2 *de;
782         int err;
783 -
784 -       frame = dx_probe(dentry, NULL, &hinfo, frames, &err);
785 +       int curidx;
786 +       void *idx_lock, *leaf_lock, *newleaf_lock;
787 +       
788 +repeat:
789 +       frame = dx_probe(&dentry->d_name, dir, &hinfo, frames, &err);
790         if (!frame)
791                 return err;
792 -       entries = frame->entries;
793 -       at = frame->at;
794 -
795 -       if (!(bh = ext3_bread(handle,dir, dx_get_block(frame->at), 0, &err)))
796 -               goto cleanup;
797 +       /* we're going to chage leaf, so lock it first */
798 +       leaf_lock = ext3_lock_htree(dir, frame->leaf, 1);
799
800 +       /* while locking leaf we just found may get splitted
801 +        * so we need to check this */
802 +       if (!dx_check_full_path(frames, &hinfo)) {
803 +               ext3_unlock_htree(dir, leaf_lock);
804 +               dx_release(frames);
805 +               goto repeat;
806 +       }
807 +       if (!(bh = ext3_bread(handle,dir, frame->leaf, 0, &err))) {
808 +               printk("can't ext3_bread(%d) = %d\n", (int) frame->leaf, err);
809 +               goto cleanup;
810 +       }
811  
812         BUFFER_TRACE(bh, "get_write_access");
813         err = ext3_journal_get_write_access(handle, bh);
814 @@ -1446,6 +1671,35 @@
815                 goto cleanup;
816         }
817  
818 +       /* our leaf has no enough space. hence, we have to
819 +        * split it. so lock index for this leaf first */
820 +       curidx = frame->curidx;
821 +       idx_lock = ext3_lock_htree(dir, curidx, 1);
822 +
823 +       /* now check did path get changed? */
824 +       dx_release(frames);
825 +
826 +       frame = dx_probe(&dentry->d_name, dentry->d_parent->d_inode,
827 +                       &hinfo, frames, &err);
828 +       if (!frame) {
829 +               /* FIXME: error handling here */
830 +               brelse(bh);
831 +               ext3_unlock_htree(dir, idx_lock);
832 +               return err;
833 +       }
834 +       
835 +       if (frame->curidx != curidx) {
836 +               /* path has been changed. we have to drop old lock
837 +                * and repeat */
838 +               brelse(bh);
839 +               ext3_unlock_htree(dir, idx_lock);
840 +               ext3_unlock_htree(dir, leaf_lock);
841 +               dx_release(frames);
842 +               goto repeat;
843 +       }
844 +       entries = frame->entries;
845 +       at = frame->at;
846 +
847         /* Block full, should compress but for now just split */
848         dxtrace(printk("using %u of %u node entries\n",
849                        dx_get_count(entries), dx_get_limit(entries)));
850 @@ -1457,7 +1711,8 @@
851                 struct dx_entry *entries2;
852                 struct dx_node *node2;
853                 struct buffer_head *bh2;
854 -
855 +               void *nb_lock;
856 +               
857                 if (levels && (dx_get_count(frames->entries) ==
858                                dx_get_limit(frames->entries))) {
859                         ext3_warning(sb, __FUNCTION__,
860 @@ -1468,6 +1723,7 @@
861                 bh2 = ext3_append (handle, dir, &newblock, &err);
862                 if (!(bh2))
863                         goto cleanup;
864 +               nb_lock = ext3_lock_htree(dir, newblock, 1);
865                 node2 = (struct dx_node *)(bh2->b_data);
866                 entries2 = node2->entries;
867                 node2->fake.rec_len = cpu_to_le16(sb->s_blocksize);
868 @@ -1479,27 +1735,73 @@
869                 if (levels) {
870                         unsigned icount1 = icount/2, icount2 = icount - icount1;
871                         unsigned hash2 = dx_get_hash(entries + icount1);
872 -                       dxtrace(printk("Split index %i/%i\n", icount1, icount2));
873 +                       void *ri_lock;
874  
875 -                       BUFFER_TRACE(frame->bh, "get_write_access"); /* index root */
876 +                       /* we have to protect root htree index against
877 +                        * another dx_add_entry() which would want to
878 +                        * split it too -bzzz */
879 +                       ri_lock = ext3_lock_htree(dir, 0, 1);
880 +
881 +                       /* as root index block blocked we must repeat
882 +                        * searching for current position of our 2nd index -bzzz */
883 +                       dx_lock_bh(frame->bh);
884 +                       frames->at = dx_find_position(frames->entries, hinfo.hash);
885 +                       dx_unlock_bh(frame->bh);
886 +                       
887 +                       dxtrace(printk("Split index %i/%i\n", icount1, icount2));
888 +       
889 +                       BUFFER_TRACE(frame->bh, "get_write_access");
890                         err = ext3_journal_get_write_access(handle,
891                                                              frames[0].bh);
892                         if (err)
893                                 goto journal_error;
894  
895 +                       /* copy index into new one */
896                         memcpy ((char *) entries2, (char *) (entries + icount1),
897                                 icount2 * sizeof(struct dx_entry));
898 -                       dx_set_count (entries, icount1);
899                         dx_set_count (entries2, icount2);
900                         dx_set_limit (entries2, dx_node_limit(dir));
901  
902                         /* Which index block gets the new entry? */
903                         if (at - entries >= icount1) {
904 +                               /* unlock index we won't use */
905 +                               ext3_unlock_htree(dir, idx_lock);
906 +                               idx_lock = nb_lock;
907                                 frame->at = at = at - entries - icount1 + entries2;
908 -                               frame->entries = entries = entries2;
909 +                               frame->entries = entries2;
910 +                               frame->curidx = curidx = newblock;
911                                 swap(frame->bh, bh2);
912 +                       } else {
913 +                               /* we'll use old index,so new one may be freed */
914 +                               ext3_unlock_htree(dir, nb_lock);
915                         }
916 -                       dx_insert_block (frames + 0, hash2, newblock);
917 +               
918 +                       /* NOTE: very subtle piece of code
919 +                        * competing dx_probe() may find 2nd level index in root
920 +                        * index, then we insert new index here and set new count
921 +                        * in that 2nd level index. so, dx_probe() may see 2nd
922 +                        * level index w/o hash it looks for. the solution is
923 +                        * to check root index after we locked just founded 2nd
924 +                        * level index -bzzz */
925 +                       dx_lock_bh(frames[0].bh);
926 +                       dx_insert_block (dir, frames + 0, hash2, newblock, 0);
927 +                       dx_unlock_bh(frames[0].bh);
928 +                       
929 +                       /* now old and new 2nd level index blocks contain
930 +                        * all pointers, so dx_probe() may find it in the both.
931 +                        * it's OK -bzzz */
932 +                       
933 +                       dx_lock_bh(frame->bh);
934 +                       dx_set_count(entries, icount1);
935 +                       dx_unlock_bh(frame->bh);
936 +
937 +                       /* now old 2nd level index block points to first half
938 +                        * of leafs. it's importand that dx_probe() must
939 +                        * check root index block for changes under
940 +                        * dx_lock_bh(frame->bh) -bzzz */
941 +
942 +                       ext3_unlock_htree(dir, ri_lock);
943 +               
944                         dxtrace(dx_show_index ("node", frames[1].entries));
945                         dxtrace(dx_show_index ("node",
946                                ((struct dx_node *) bh2->b_data)->entries));
947 @@ -1508,38 +1810,60 @@
948                                 goto journal_error;
949                         brelse (bh2);
950                 } else {
951 +                       unsigned long leaf = frame->leaf;
952                         dxtrace(printk("Creating second level index...\n"));
953                         memcpy((char *) entries2, (char *) entries,
954                                icount * sizeof(struct dx_entry));
955                         dx_set_limit(entries2, dx_node_limit(dir));
956  
957                         /* Set up root */
958 +                       dx_lock_bh(frames[0].bh);
959                         dx_set_count(entries, 1);
960                         dx_set_block(entries + 0, newblock);
961                         ((struct dx_root *) frames[0].bh->b_data)->info.indirect_levels = 1;
962 +                       dx_unlock_bh(frames[0].bh);
963  
964                         /* Add new access path frame */
965                         frame = frames + 1;
966                         frame->at = at = at - entries + entries2;
967                         frame->entries = entries = entries2;
968                         frame->bh = bh2;
969 +                       frame->curidx = newblock;
970 +                       frame->leaf = leaf;
971                         err = ext3_journal_get_write_access(handle,
972                                                              frame->bh);
973                         if (err)
974                                 goto journal_error;
975 +                
976 +                       /* first level index was root. it's already initialized */
977 +                       /* we my unlock it now */
978 +                       ext3_unlock_htree(dir, idx_lock);
979
980 +                       /* current index is just created 2nd level index */
981 +                       curidx = newblock;
982 +                       idx_lock = nb_lock;
983                 }
984                 ext3_journal_dirty_metadata(handle, frames[0].bh);
985         }
986 -       de = do_split(handle, dir, &bh, frame, &hinfo, &err);
987 +       de = do_split(handle, dir, &bh, frame, &hinfo, &newleaf_lock, &err);
988         if (!de)
989                 goto cleanup;
990 +        
991 +       /* index splitted */
992 +       ext3_unlock_htree(dir, idx_lock);
993 +       
994         err = add_dirent_to_buf(handle, dentry, inode, de, bh);
995
996 +       if (newleaf_lock)
997 +               ext3_unlock_htree(dir, newleaf_lock);
998 +       
999         bh = NULL;
1000         goto cleanup;
1001  
1002  journal_error:
1003         ext3_std_error(dir->i_sb, err);
1004  cleanup:
1005 +       ext3_unlock_htree(dir, leaf_lock);
1006         if (bh)
1007                 brelse(bh);
1008         dx_release(frames);
1009 @@ -1753,7 +2077,9 @@
1010                 iput (inode);
1011                 goto out_stop;
1012         }
1013 +       spin_lock(&EXT3_SB(dir->i_sb)->s_next_gen_lock);
1014         dir->i_nlink++;
1015 +       spin_unlock(&EXT3_SB(dir->i_sb)->s_next_gen_lock);
1016         ext3_update_dx_flag(dir);
1017         ext3_mark_inode_dirty(handle, dir);
1018         d_instantiate(dentry, inode);
1019 @@ -1989,6 +2315,7 @@
1020         struct buffer_head * bh;
1021         struct ext3_dir_entry_2 * de;
1022         handle_t *handle;
1023 +       void *lock;
1024  
1025         /* Initialize quotas before so that eventual writes go in
1026          * separate transaction */
1027 @@ -1998,7 +2325,7 @@
1028                 return PTR_ERR(handle);
1029  
1030         retval = -ENOENT;
1031 -       bh = ext3_find_entry (dentry, &de);
1032 +       bh = ext3_find_entry (dentry, &de, 1, &lock);
1033         if (!bh)
1034                 goto end_rmdir;
1035  
1036 @@ -2008,14 +2335,19 @@
1037         inode = dentry->d_inode;
1038  
1039         retval = -EIO;
1040 -       if (le32_to_cpu(de->inode) != inode->i_ino)
1041 +       if (le32_to_cpu(de->inode) != inode->i_ino) {
1042 +               ext3_unlock_htree(dir, lock);
1043                 goto end_rmdir;
1044 +       }
1045  
1046         retval = -ENOTEMPTY;
1047 -       if (!empty_dir (inode))
1048 +       if (!empty_dir (inode)) {
1049 +               ext3_unlock_htree(dir, lock);
1050                 goto end_rmdir;
1051 +       }
1052  
1053         retval = ext3_delete_entry(handle, dir, de, bh);
1054 +       ext3_unlock_htree(dir, lock);
1055         if (retval)
1056                 goto end_rmdir;
1057         if (inode->i_nlink != 2)
1058 @@ -2031,7 +2363,9 @@
1059         ext3_orphan_add(handle, inode);
1060         inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
1061         ext3_mark_inode_dirty(handle, inode);
1062 +       spin_lock(&EXT3_SB(dir->i_sb)->s_next_gen_lock);
1063         dir->i_nlink--;
1064 +       spin_unlock(&EXT3_SB(dir->i_sb)->s_next_gen_lock);
1065         ext3_update_dx_flag(dir);
1066         ext3_mark_inode_dirty(handle, dir);
1067  
1068 @@ -2048,6 +2382,7 @@
1069         struct buffer_head * bh;
1070         struct ext3_dir_entry_2 * de;
1071         handle_t *handle;
1072 +       void *lock;
1073  
1074         /* Initialize quotas before so that eventual writes go
1075          * in separate transaction */
1076 @@ -2060,15 +2395,17 @@
1077                 handle->h_sync = 1;
1078  
1079         retval = -ENOENT;
1080 -       bh = ext3_find_entry (dentry, &de);
1081 +       bh = ext3_find_entry (dentry, &de, 1, &lock);
1082         if (!bh)
1083                 goto end_unlink;
1084  
1085         inode = dentry->d_inode;
1086  
1087         retval = -EIO;
1088 -       if (le32_to_cpu(de->inode) != inode->i_ino)
1089 +       if (le32_to_cpu(de->inode) != inode->i_ino) {
1090 +               ext3_unlock_htree(dir, lock);
1091                 goto end_unlink;
1092 +       }
1093  
1094         if (!inode->i_nlink) {
1095                 ext3_warning (inode->i_sb, "ext3_unlink",
1096 @@ -2077,6 +2414,7 @@
1097                 inode->i_nlink = 1;
1098         }
1099         retval = ext3_delete_entry(handle, dir, de, bh);
1100 +       ext3_unlock_htree(dir, lock);
1101         if (retval)
1102                 goto end_unlink;
1103         dir->i_ctime = dir->i_mtime = CURRENT_TIME;
1104 @@ -2196,6 +2534,7 @@
1105         struct buffer_head * old_bh, * new_bh, * dir_bh;
1106         struct ext3_dir_entry_2 * old_de, * new_de;
1107         int retval;
1108 +       void *lock1 = NULL, *lock2 = NULL, *lock3 = NULL;
1109  
1110         old_bh = new_bh = dir_bh = NULL;
1111  
1112 @@ -2211,7 +2550,10 @@
1113         if (IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir))
1114                 handle->h_sync = 1;
1115  
1116 -       old_bh = ext3_find_entry (old_dentry, &old_de);
1117 +       if (old_dentry->d_parent == new_dentry->d_parent)
1118 +               down(&EXT3_I(old_dentry->d_parent->d_inode)->i_rename_sem);
1119 +
1120 +       old_bh = ext3_find_entry (old_dentry, &old_de, 1, &lock1 /* FIXME */);
1121         /*
1122          *  Check for inode number is _not_ due to possible IO errors.
1123          *  We might rmdir the source, keep it as pwd of some process
1124 @@ -2224,7 +2566,7 @@
1125                 goto end_rename;
1126  
1127         new_inode = new_dentry->d_inode;
1128 -       new_bh = ext3_find_entry (new_dentry, &new_de);
1129 +       new_bh = ext3_find_entry (new_dentry, &new_de, 1, &lock2 /* FIXME */);
1130         if (new_bh) {
1131                 if (!new_inode) {
1132                         brelse (new_bh);
1133 @@ -2288,7 +2630,7 @@
1134                 struct buffer_head *old_bh2;
1135                 struct ext3_dir_entry_2 *old_de2;
1136  
1137 -               old_bh2 = ext3_find_entry(old_dentry, &old_de2);
1138 +               old_bh2 = ext3_find_entry(old_dentry, &old_de2, 1, &lock3 /* FIXME */);
1139                 if (old_bh2) {
1140                         retval = ext3_delete_entry(handle, old_dir,
1141                                                    old_de2, old_bh2);
1142 @@ -2331,6 +2673,14 @@
1143         retval = 0;
1144  
1145  end_rename:
1146 +       if (lock1)
1147 +               ext3_unlock_htree(old_dentry->d_parent->d_inode, lock1);
1148 +       if (lock2)
1149 +               ext3_unlock_htree(new_dentry->d_parent->d_inode, lock2);
1150 +       if (lock3)
1151 +               ext3_unlock_htree(old_dentry->d_parent->d_inode, lock3);
1152 +       if (old_dentry->d_parent == new_dentry->d_parent)
1153 +               up(&EXT3_I(old_dentry->d_parent->d_inode)->i_rename_sem);
1154         brelse (dir_bh);
1155         brelse (old_bh);
1156         brelse (new_bh);
1157 @@ -2339,6 +2689,29 @@
1158  }
1159  
1160  /*
1161 + * this locking primitives are used to protect parts
1162 + * of dir's htree. protection unit is block: leaf or index
1163 + */
1164 +static  void *ext3_lock_htree(struct inode *dir,
1165 +                                       unsigned long value, int rwlock)
1166 +{
1167 +       void *lock;
1168 +       
1169 +       if (!test_opt(dir->i_sb, PDIROPS))
1170 +               return NULL;
1171 +       lock = dynlock_lock(&EXT3_I(dir)->i_htree_lock, value, 1, GFP_KERNEL);
1172 +       return lock;
1173 +}
1174 +
1175 +static  void ext3_unlock_htree(struct inode *dir,
1176 +                                       void *lock)
1177 +{
1178 +       if (!test_opt(dir->i_sb, PDIROPS) || !lock)
1179 +               return;
1180 +       dynlock_unlock(&EXT3_I(dir)->i_htree_lock, lock);
1181 +}
1182 +
1183 +/*
1184   * directories can handle most operations...
1185   */
1186  struct inode_operations ext3_dir_inode_operations = {
1187 Index: linux-2.6.10/include/linux/ext3_fs_i.h
1188 ===================================================================
1189 --- linux-2.6.10.orig/include/linux/ext3_fs_i.h 2004-12-25 00:33:49.000000000 +0300
1190 +++ linux-2.6.10/include/linux/ext3_fs_i.h      2005-06-29 20:09:30.000000000 +0400
1191 @@ -19,6 +19,7 @@
1192  #include <linux/rwsem.h>
1193  #include <linux/rbtree.h>
1194  #include <linux/seqlock.h>
1195 +#include <linux/dynlocks.h>
1196  
1197  struct ext3_reserve_window {
1198         __u32                   _rsv_start;     /* First byte reserved */
1199 @@ -125,6 +126,11 @@
1200          */
1201         struct semaphore truncate_sem;
1202         struct inode vfs_inode;
1203
1204 +       /* following fields for parallel directory operations -bzzz */
1205 +       struct dynlock i_htree_lock;
1206 +       struct semaphore i_append_sem;
1207 +       struct semaphore i_rename_sem;
1208  };
1209  
1210  #endif /* _LINUX_EXT3_FS_I */
1211 Index: linux-2.6.10/include/linux/ext3_fs.h
1212 ===================================================================
1213 --- linux-2.6.10.orig/include/linux/ext3_fs.h   2004-12-25 00:34:58.000000000 +0300
1214 +++ linux-2.6.10/include/linux/ext3_fs.h        2005-06-29 20:09:30.000000000 +0400
1215 @@ -355,6 +355,7 @@
1216  #define EXT3_MOUNT_POSIX_ACL           0x08000 /* POSIX Access Control Lists */
1217  #define EXT3_MOUNT_RESERVATION         0x10000 /* Preallocation */
1218  #define EXT3_MOUNT_BARRIER             0x20000 /* Use block barriers */
1219 +#define EXT3_MOUNT_PDIROPS             0x800000/* Parallel dir operations */
1220  
1221  /* Compatibility, for having both ext2_fs.h and ext3_fs.h included at once */
1222  #ifndef _LINUX_EXT2_FS_H