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-03-31 15:35:26.000000000 +0800
12 +++ linux-2.6.10/fs/ext3/super.c        2005-03-31 19:44:54.251322480 +0800
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 05:34:58.000000000 +0800
43 +++ linux-2.6.10/fs/ext3/namei.c        2005-03-31 19:48:53.958881392 +0800
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 @@ -1989,6 +2313,7 @@
1010         struct buffer_head * bh;
1011         struct ext3_dir_entry_2 * de;
1012         handle_t *handle;
1013 +       void *lock;
1014  
1015         /* Initialize quotas before so that eventual writes go in
1016          * separate transaction */
1017 @@ -1998,7 +2323,7 @@
1018                 return PTR_ERR(handle);
1019  
1020         retval = -ENOENT;
1021 -       bh = ext3_find_entry (dentry, &de);
1022 +       bh = ext3_find_entry (dentry, &de, 1, &lock);
1023         if (!bh)
1024                 goto end_rmdir;
1025  
1026 @@ -2008,14 +2333,19 @@
1027         inode = dentry->d_inode;
1028  
1029         retval = -EIO;
1030 -       if (le32_to_cpu(de->inode) != inode->i_ino)
1031 +       if (le32_to_cpu(de->inode) != inode->i_ino) {
1032 +               ext3_unlock_htree(dir, lock);
1033                 goto end_rmdir;
1034 +       }
1035  
1036         retval = -ENOTEMPTY;
1037 -       if (!empty_dir (inode))
1038 +       if (!empty_dir (inode)) {
1039 +               ext3_unlock_htree(dir, lock);
1040                 goto end_rmdir;
1041 +       }
1042  
1043         retval = ext3_delete_entry(handle, dir, de, bh);
1044 +       ext3_unlock_htree(dir, lock);
1045         if (retval)
1046                 goto end_rmdir;
1047         if (inode->i_nlink != 2)
1048 @@ -2048,6 +2378,7 @@
1049         struct buffer_head * bh;
1050         struct ext3_dir_entry_2 * de;
1051         handle_t *handle;
1052 +       void *lock;
1053  
1054         /* Initialize quotas before so that eventual writes go
1055          * in separate transaction */
1056 @@ -2060,15 +2391,17 @@
1057                 handle->h_sync = 1;
1058  
1059         retval = -ENOENT;
1060 -       bh = ext3_find_entry (dentry, &de);
1061 +       bh = ext3_find_entry (dentry, &de, 1, &lock);
1062         if (!bh)
1063                 goto end_unlink;
1064  
1065         inode = dentry->d_inode;
1066  
1067         retval = -EIO;
1068 -       if (le32_to_cpu(de->inode) != inode->i_ino)
1069 +       if (le32_to_cpu(de->inode) != inode->i_ino) {
1070 +               ext3_unlock_htree(dir, lock);
1071                 goto end_unlink;
1072 +       }
1073  
1074         if (!inode->i_nlink) {
1075                 ext3_warning (inode->i_sb, "ext3_unlink",
1076 @@ -2077,6 +2410,7 @@
1077                 inode->i_nlink = 1;
1078         }
1079         retval = ext3_delete_entry(handle, dir, de, bh);
1080 +       ext3_unlock_htree(dir, lock);
1081         if (retval)
1082                 goto end_unlink;
1083         dir->i_ctime = dir->i_mtime = CURRENT_TIME;
1084 @@ -2196,6 +2530,7 @@
1085         struct buffer_head * old_bh, * new_bh, * dir_bh;
1086         struct ext3_dir_entry_2 * old_de, * new_de;
1087         int retval;
1088 +       void *lock1 = NULL, *lock2 = NULL, *lock3 = NULL;
1089  
1090         old_bh = new_bh = dir_bh = NULL;
1091  
1092 @@ -2211,7 +2546,10 @@
1093         if (IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir))
1094                 handle->h_sync = 1;
1095  
1096 -       old_bh = ext3_find_entry (old_dentry, &old_de);
1097 +       if (old_dentry->d_parent == new_dentry->d_parent)
1098 +               down(&EXT3_I(old_dentry->d_parent->d_inode)->i_rename_sem);
1099 +
1100 +       old_bh = ext3_find_entry (old_dentry, &old_de, 1, &lock1 /* FIXME */);
1101         /*
1102          *  Check for inode number is _not_ due to possible IO errors.
1103          *  We might rmdir the source, keep it as pwd of some process
1104 @@ -2224,7 +2562,7 @@
1105                 goto end_rename;
1106  
1107         new_inode = new_dentry->d_inode;
1108 -       new_bh = ext3_find_entry (new_dentry, &new_de);
1109 +       new_bh = ext3_find_entry (new_dentry, &new_de, 1, &lock2 /* FIXME */);
1110         if (new_bh) {
1111                 if (!new_inode) {
1112                         brelse (new_bh);
1113 @@ -2288,7 +2626,7 @@
1114                 struct buffer_head *old_bh2;
1115                 struct ext3_dir_entry_2 *old_de2;
1116  
1117 -               old_bh2 = ext3_find_entry(old_dentry, &old_de2);
1118 +               old_bh2 = ext3_find_entry(old_dentry, &old_de2, 1, &lock3 /* FIXME */);
1119                 if (old_bh2) {
1120                         retval = ext3_delete_entry(handle, old_dir,
1121                                                    old_de2, old_bh2);
1122 @@ -2331,6 +2669,14 @@
1123         retval = 0;
1124  
1125  end_rename:
1126 +       if (lock1)
1127 +               ext3_unlock_htree(old_dentry->d_parent->d_inode, lock1);
1128 +       if (lock2)
1129 +               ext3_unlock_htree(new_dentry->d_parent->d_inode, lock2);
1130 +       if (lock3)
1131 +               ext3_unlock_htree(old_dentry->d_parent->d_inode, lock3);
1132 +       if (old_dentry->d_parent == new_dentry->d_parent)
1133 +               up(&EXT3_I(old_dentry->d_parent->d_inode)->i_rename_sem);
1134         brelse (dir_bh);
1135         brelse (old_bh);
1136         brelse (new_bh);
1137 @@ -2339,6 +2685,29 @@
1138  }
1139  
1140  /*
1141 + * this locking primitives are used to protect parts
1142 + * of dir's htree. protection unit is block: leaf or index
1143 + */
1144 +static  void *ext3_lock_htree(struct inode *dir,
1145 +                                       unsigned long value, int rwlock)
1146 +{
1147 +       void *lock;
1148 +       
1149 +       if (!test_opt(dir->i_sb, PDIROPS))
1150 +               return NULL;
1151 +       lock = dynlock_lock(&EXT3_I(dir)->i_htree_lock, value, 1, GFP_KERNEL);
1152 +       return lock;
1153 +}
1154 +
1155 +static  void ext3_unlock_htree(struct inode *dir,
1156 +                                       void *lock)
1157 +{
1158 +       if (!test_opt(dir->i_sb, PDIROPS) || !lock)
1159 +               return;
1160 +       dynlock_unlock(&EXT3_I(dir)->i_htree_lock, lock);
1161 +}
1162 +
1163 +/*
1164   * directories can handle most operations...
1165   */
1166  struct inode_operations ext3_dir_inode_operations = {
1167 Index: linux-2.6.10/include/linux/ext3_fs_i.h
1168 ===================================================================
1169 --- linux-2.6.10.orig/include/linux/ext3_fs_i.h 2004-12-25 05:33:49.000000000 +0800
1170 +++ linux-2.6.10/include/linux/ext3_fs_i.h      2005-03-31 19:44:54.254322024 +0800
1171 @@ -19,6 +19,7 @@
1172  #include <linux/rwsem.h>
1173  #include <linux/rbtree.h>
1174  #include <linux/seqlock.h>
1175 +#include <linux/dynlocks.h>
1176  
1177  struct ext3_reserve_window {
1178         __u32                   _rsv_start;     /* First byte reserved */
1179 @@ -125,6 +126,11 @@
1180          */
1181         struct semaphore truncate_sem;
1182         struct inode vfs_inode;
1183
1184 +       /* following fields for parallel directory operations -bzzz */
1185 +       struct dynlock i_htree_lock;
1186 +       struct semaphore i_append_sem;
1187 +       struct semaphore i_rename_sem;
1188  };
1189  
1190  #endif /* _LINUX_EXT3_FS_I */
1191 Index: linux-2.6.10/include/linux/ext3_fs.h
1192 ===================================================================
1193 --- linux-2.6.10.orig/include/linux/ext3_fs.h   2004-12-25 05:34:58.000000000 +0800
1194 +++ linux-2.6.10/include/linux/ext3_fs.h        2005-03-31 19:44:54.254322024 +0800
1195 @@ -355,6 +355,7 @@
1196  #define EXT3_MOUNT_POSIX_ACL           0x08000 /* POSIX Access Control Lists */
1197  #define EXT3_MOUNT_RESERVATION         0x10000 /* Preallocation */
1198  #define EXT3_MOUNT_BARRIER             0x20000 /* Use block barriers */
1199 +#define EXT3_MOUNT_PDIROPS             0x800000/* Parallel dir operations */
1200  
1201  /* Compatibility, for having both ext2_fs.h and ext3_fs.h included at once */
1202  #ifndef _LINUX_EXT2_FS_H