Whamcloud - gitweb
Land b1_2 onto HEAD (20040317_2319)
[fs/lustre-release.git] / lustre / kernel_patches / patches / vfs_intent-2.4.20-rh.patch
1  fs/dcache.c               |   19 ++
2  fs/exec.c                 |   17 +-
3  fs/namei.c                |  333 ++++++++++++++++++++++++++++++++++++++--------
4  fs/namespace.c            |   28 ++-
5  fs/open.c                 |  176 +++++++++++++++++-------
6  fs/proc/base.c            |    3 
7  fs/stat.c                 |   28 ++-
8  include/linux/dcache.h    |   60 ++++++++
9  include/linux/fs.h        |   32 ++++
10  include/linux/fs_struct.h |    4 
11  kernel/exit.c             |    3 
12  kernel/fork.c             |    3 
13  kernel/ksyms.c            |    1 
14  13 files changed, 578 insertions(+), 129 deletions(-)
15
16 Index: linux-2.4.20/fs/dcache.c
17 ===================================================================
18 --- linux-2.4.20.orig/fs/dcache.c       Wed Mar 17 13:57:05 2004
19 +++ linux-2.4.20/fs/dcache.c    Wed Mar 17 13:57:11 2004
20 @@ -186,6 +186,13 @@
21                 spin_unlock(&dcache_lock);
22                 return 0;
23         }
24 +
25 +       /* network invalidation by Lustre */
26 +       if (dentry->d_flags & DCACHE_LUSTRE_INVALID) {
27 +               spin_unlock(&dcache_lock);
28 +               return 0;
29 +       }
30 +
31         /*
32          * Check whether to do a partial shrink_dcache
33          * to get rid of unused child entries.
34 @@ -841,13 +848,19 @@
35   * Adds a dentry to the hash according to its name.
36   */
37   
38 -void d_rehash(struct dentry * entry)
39 +void __d_rehash(struct dentry * entry, int lock)
40  {
41         struct list_head *list = d_hash(entry->d_parent, entry->d_name.hash);
42         if (!list_empty(&entry->d_hash)) BUG();
43 -       spin_lock(&dcache_lock);
44 +       if (lock) spin_lock(&dcache_lock);
45         list_add(&entry->d_hash, list);
46 -       spin_unlock(&dcache_lock);
47 +       if (lock) spin_unlock(&dcache_lock);
48 +}
49 +EXPORT_SYMBOL(__d_rehash);
50 +
51 +void d_rehash(struct dentry * entry)
52 +{
53 +       __d_rehash(entry, 1);
54  }
55  
56  #define do_switch(x,y) do { \
57 Index: linux-2.4.20/fs/exec.c
58 ===================================================================
59 --- linux-2.4.20.orig/fs/exec.c Wed Mar 17 13:57:05 2004
60 +++ linux-2.4.20/fs/exec.c      Wed Mar 17 13:57:11 2004
61 @@ -114,8 +114,10 @@
62         struct file * file;
63         struct nameidata nd;
64         int error;
65 +       struct lookup_intent it = { .it_op = IT_OPEN,
66 +                                   .it_flags = FMODE_READ|FMODE_EXEC };
67  
68 -       error = user_path_walk(library, &nd);
69 +       error = user_path_walk_it(library, &nd, &it);
70         if (error)
71                 goto out;
72  
73 @@ -127,7 +129,8 @@
74         if (error)
75                 goto exit;
76  
77 -       file = dentry_open(nd.dentry, nd.mnt, O_RDONLY);
78 +       file = dentry_open_it(nd.dentry, nd.mnt, O_RDONLY, &it);
79 +       intent_release(&it);
80         error = PTR_ERR(file);
81         if (IS_ERR(file))
82                 goto out;
83 @@ -382,8 +385,10 @@
84         struct inode *inode;
85         struct file *file;
86         int err = 0;
87 +       struct lookup_intent it = { .it_op = IT_OPEN,
88 +                                   .it_flags = FMODE_READ|FMODE_EXEC };
89  
90 -       err = path_lookup(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd);
91 +       err = path_lookup_it(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd, &it);
92         file = ERR_PTR(err);
93         if (!err) {
94                 inode = nd.dentry->d_inode;
95 @@ -395,7 +400,8 @@
96                                 err = -EACCES;
97                         file = ERR_PTR(err);
98                         if (!err) {
99 -                               file = dentry_open(nd.dentry, nd.mnt, O_RDONLY);
100 +                               file = dentry_open_it(nd.dentry, nd.mnt, O_RDONLY, &it);
101 +                               intent_release(&it);
102                                 if (!IS_ERR(file)) {
103                                         err = deny_write_access(file);
104                                         if (err) {
105 @@ -407,6 +413,7 @@
106                                 return file;
107                         }
108                 }
109 +               intent_release(&it);
110                 path_release(&nd);
111         }
112         goto out;
113 @@ -1296,7 +1303,7 @@
114                 goto close_fail;
115         if (!file->f_op->write)
116                 goto close_fail;
117 -       if (do_truncate(file->f_dentry, 0) != 0)
118 +       if (do_truncate(file->f_dentry, 0, 0) != 0)
119                 goto close_fail;
120  
121         retval = binfmt->core_dump(signr, regs, file);
122 Index: linux-2.4.20/fs/namei.c
123 ===================================================================
124 --- linux-2.4.20.orig/fs/namei.c        Wed Mar 17 13:57:03 2004
125 +++ linux-2.4.20/fs/namei.c     Wed Mar 17 13:58:01 2004
126 @@ -94,6 +94,13 @@
127   * XEmacs seems to be relying on it...
128   */
129  
130 +void intent_release(struct lookup_intent *it)
131 +{
132 +       if (it && it->it_op_release)
133 +               it->it_op_release(it);
134 +
135 +}
136 +
137  /* In order to reduce some races, while at the same time doing additional
138   * checking and hopefully speeding things up, we copy filenames to the
139   * kernel data space before using them..
140 @@ -260,10 +267,19 @@
141   * Internal lookup() using the new generic dcache.
142   * SMP-safe
143   */
144 -static struct dentry * cached_lookup(struct dentry * parent, struct qstr * name, int flags)
145 +static struct dentry *cached_lookup(struct dentry *parent, struct qstr *name,
146 +                                   int flags, struct lookup_intent *it)
147  {
148         struct dentry * dentry = d_lookup(parent, name);
149  
150 +       if (dentry && dentry->d_op && dentry->d_op->d_revalidate_it) {
151 +               if (!dentry->d_op->d_revalidate_it(dentry, flags, it) &&
152 +                   !d_invalidate(dentry)) {
153 +                       dput(dentry);
154 +                       dentry = NULL;
155 +               }
156 +               return dentry;
157 +       } else
158         if (dentry && dentry->d_op && dentry->d_op->d_revalidate) {
159                 if (!dentry->d_op->d_revalidate(dentry, flags) && !d_invalidate(dentry)) {
160                         dput(dentry);
161 @@ -281,11 +297,15 @@
162   * make sure that nobody added the entry to the dcache in the meantime..
163   * SMP-safe
164   */
165 -static struct dentry * real_lookup(struct dentry * parent, struct qstr * name, int flags)
166 +static struct dentry *real_lookup(struct dentry *parent, struct qstr *name,
167 +                                 int flags, struct lookup_intent *it)
168  {
169         struct dentry * result;
170         struct inode *dir = parent->d_inode;
171 +       int counter = 0;
172  
173 +again:
174 +       counter++;
175         down(&dir->i_sem);
176         /*
177          * First re-do the cached lookup just in case it was created
178 @@ -300,6 +320,9 @@
179                 result = ERR_PTR(-ENOMEM);
180                 if (dentry) {
181                         lock_kernel();
182 +                       if (dir->i_op->lookup_it)
183 +                               result = dir->i_op->lookup_it(dir, dentry, it, flags);
184 +                       else
185                         result = dir->i_op->lookup(dir, dentry);
186                         unlock_kernel();
187                         if (result)
188 @@ -321,6 +344,15 @@
189                         dput(result);
190                         result = ERR_PTR(-ENOENT);
191                 }
192 +       } else if (result->d_op && result->d_op->d_revalidate_it) {
193 +               if (!result->d_op->d_revalidate_it(result, flags, it) &&
194 +                   !d_invalidate(result)) {
195 +                       dput(result);
196 +                       if (counter > 10)
197 +                               result = ERR_PTR(-ESTALE);
198 +                       if (!IS_ERR(result))
199 +                               goto again;
200 +               }
201         }
202         return result;
203  }
204 @@ -334,7 +366,8 @@
205   * Without that kind of total limit, nasty chains of consecutive
206   * symlinks can cause almost arbitrarily long lookups. 
207   */
208 -static inline int do_follow_link(struct dentry *dentry, struct nameidata *nd)
209 +static inline int do_follow_link(struct dentry *dentry, struct nameidata *nd,
210 +                                struct lookup_intent *it)
211  {
212         int err;
213         if (current->link_count >= max_recursive_link)
214 @@ -348,10 +381,18 @@
215         current->link_count++;
216         current->total_link_count++;
217         UPDATE_ATIME(dentry->d_inode);
218 +       nd->intent = it;
219         err = dentry->d_inode->i_op->follow_link(dentry, nd);
220 +       if (!err && it != NULL && !(it->d.lustre.it_int_flags & IT_FL_FOLLOWED)) {
221 +               /* vfs_follow_link was never called */
222 +               intent_release(it);
223 +               path_release(nd);
224 +               err = -ENOLINK;
225 +       }
226         current->link_count--;
227         return err;
228  loop:
229 +       intent_release(it);
230         path_release(nd);
231         return -ELOOP;
232  }
233 @@ -381,15 +422,26 @@
234         return __follow_up(mnt, dentry);
235  }
236  
237 -static inline int __follow_down(struct vfsmount **mnt, struct dentry **dentry)
238 +static inline int __follow_down(struct vfsmount **mnt, struct dentry **dentry,
239 +                               struct lookup_intent *it)
240  {
241         struct vfsmount *mounted;
242  
243         spin_lock(&dcache_lock);
244         mounted = lookup_mnt(*mnt, *dentry);
245         if (mounted) {
246 +               int opc = 0, mode = 0;
247                 *mnt = mntget(mounted);
248                 spin_unlock(&dcache_lock);
249 +               if (it) {
250 +                       opc = it->it_op;
251 +                       mode = it->it_create_mode;
252 +               }
253 +               intent_release(it);
254 +               if (it) {
255 +                       it->it_op = opc;
256 +                       it->it_create_mode = mode;
257 +               }
258                 dput(*dentry);
259                 mntput(mounted->mnt_parent);
260                 *dentry = dget(mounted->mnt_root);
261 @@ -401,7 +453,7 @@
262  
263  int follow_down(struct vfsmount **mnt, struct dentry **dentry)
264  {
265 -       return __follow_down(mnt,dentry);
266 +       return __follow_down(mnt,dentry,NULL);
267  }
268   
269  static inline void follow_dotdot(struct nameidata *nd)
270 @@ -437,7 +489,7 @@
271                 mntput(nd->mnt);
272                 nd->mnt = parent;
273         }
274 -       while (d_mountpoint(nd->dentry) && __follow_down(&nd->mnt, &nd->dentry))
275 +       while (d_mountpoint(nd->dentry) && __follow_down(&nd->mnt, &nd->dentry, NULL))
276                 ;
277  }
278  
279 @@ -449,7 +501,8 @@
280   *
281   * We expect 'base' to be positive and a directory.
282   */
283 -int link_path_walk(const char * name, struct nameidata *nd)
284 +int link_path_walk_it(const char *name, struct nameidata *nd,
285 +                     struct lookup_intent *it)
286  {
287         struct dentry *dentry;
288         struct inode *inode;
289 @@ -526,19 +579,18 @@
290                                 break;
291                 }
292                 /* This does the actual lookups.. */
293 -               dentry = cached_lookup(nd->dentry, &this, LOOKUP_CONTINUE);
294 +               dentry = cached_lookup(nd->dentry, &this, LOOKUP_CONTINUE, NULL);
295                 if (!dentry) {
296                         err = -EWOULDBLOCKIO;
297                         if (atomic)
298                                 break;
299 -                       dentry = real_lookup(nd->dentry, &this, LOOKUP_CONTINUE);
300 +                       dentry = real_lookup(nd->dentry, &this, LOOKUP_CONTINUE, NULL);
301                         err = PTR_ERR(dentry);
302                         if (IS_ERR(dentry))
303                                 break;
304                 }
305                 /* Check mountpoints.. */
306 -               while (d_mountpoint(dentry) && __follow_down(&nd->mnt, &dentry))
307 -                       ;
308 +               while (d_mountpoint(dentry) && __follow_down(&nd->mnt, &dentry, NULL));
309  
310                 err = -ENOENT;
311                 inode = dentry->d_inode;
312 @@ -549,7 +601,7 @@
313                         goto out_dput;
314  
315                 if (inode->i_op->follow_link) {
316 -                       err = do_follow_link(dentry, nd);
317 +                       err = do_follow_link(dentry, nd, NULL);
318                         dput(dentry);
319                         if (err)
320                                 goto return_err;
321 @@ -565,7 +617,7 @@
322                         nd->dentry = dentry;
323                 }
324                 err = -ENOTDIR; 
325 -               if (!inode->i_op->lookup)
326 +               if (!inode->i_op->lookup && !inode->i_op->lookup_it)
327                         break;
328                 continue;
329                 /* here ends the main loop */
330 @@ -592,22 +644,22 @@
331                         if (err < 0)
332                                 break;
333                 }
334 -               dentry = cached_lookup(nd->dentry, &this, 0);
335 +               dentry = cached_lookup(nd->dentry, &this, 0, it);
336                 if (!dentry) {
337                         err = -EWOULDBLOCKIO;
338                         if (atomic)
339                                 break;
340 -                       dentry = real_lookup(nd->dentry, &this, 0);
341 +                       dentry = real_lookup(nd->dentry, &this, 0, it);
342                         err = PTR_ERR(dentry);
343                         if (IS_ERR(dentry))
344                                 break;
345                 }
346 -               while (d_mountpoint(dentry) && __follow_down(&nd->mnt, &dentry))
347 +               while (d_mountpoint(dentry) && __follow_down(&nd->mnt, &dentry, it))
348                         ;
349                 inode = dentry->d_inode;
350                 if ((lookup_flags & LOOKUP_FOLLOW)
351                     && inode && inode->i_op && inode->i_op->follow_link) {
352 -                       err = do_follow_link(dentry, nd);
353 +                       err = do_follow_link(dentry, nd, it);
354                         dput(dentry);
355                         if (err)
356                                 goto return_err;
357 @@ -621,7 +673,8 @@
358                         goto no_inode;
359                 if (lookup_flags & LOOKUP_DIRECTORY) {
360                         err = -ENOTDIR; 
361 -                       if (!inode->i_op || !inode->i_op->lookup)
362 +                       if (!inode->i_op ||
363 +                           (!inode->i_op->lookup && !inode->i_op->lookup_it))
364                                 break;
365                 }
366                 goto return_base;
367 @@ -645,6 +698,27 @@
368                  * Check the cached dentry for staleness.
369                  */
370                 dentry = nd->dentry;
371 +               if (dentry && dentry->d_op && dentry->d_op->d_revalidate_it) {
372 +                       err = -ESTALE;
373 +                       if (!dentry->d_op->d_revalidate_it(dentry, 0, it)) {
374 +                               struct dentry *new;
375 +                               err = permission(dentry->d_parent->d_inode,
376 +                                                MAY_EXEC);
377 +                               if (err)
378 +                                       break;
379 +                               new = real_lookup(dentry->d_parent,
380 +                                                 &dentry->d_name, 0, NULL);
381 +                               d_invalidate(dentry);
382 +                               dput(dentry);
383 +                               if (IS_ERR(new)) {
384 +                                       err = PTR_ERR(new);
385 +                                       break;
386 +                               }
387 +                               nd->dentry = new;
388 +                       }
389 +                       if (!nd->dentry->d_inode)
390 +                               goto no_inode;
391 +               } else
392                 if (dentry && dentry->d_op && dentry->d_op->d_revalidate) {
393                         err = -ESTALE;
394                         if (!dentry->d_op->d_revalidate(dentry, 0)) {
395 @@ -658,15 +732,28 @@
396                 dput(dentry);
397                 break;
398         }
399 +       if (err)
400 +               intent_release(it);
401         path_release(nd);
402  return_err:
403         return err;
404  }
405  
406 +int link_path_walk(const char * name, struct nameidata *nd)
407 +{
408 +       return link_path_walk_it(name, nd, NULL);
409 +}
410 +
411 +int path_walk_it(const char * name, struct nameidata *nd, struct lookup_intent *it)
412 +{
413 +       current->total_link_count = 0;
414 +       return link_path_walk_it(name, nd, it);
415 +}
416 +
417  int path_walk(const char * name, struct nameidata *nd)
418  {
419         current->total_link_count = 0;
420 -       return link_path_walk(name, nd);
421 +       return link_path_walk_it(name, nd, NULL);
422  }
423  
424  /* SMP-safe */
425 @@ -751,6 +838,17 @@
426  }
427  
428  /* SMP-safe */
429 +int path_lookup_it(const char *path, unsigned flags, struct nameidata *nd,
430 +                  struct lookup_intent *it)
431 +{
432 +       int error = 0;
433 +       if (path_init(path, flags, nd))
434 +               error = path_walk_it(path, nd, it);
435 +       return error;
436 +}
437 +
438 +
439 +/* SMP-safe */
440  int path_lookup(const char *path, unsigned flags, struct nameidata *nd)
441  {
442         int error = 0;
443 @@ -765,6 +863,7 @@
444  {
445         nd->last_type = LAST_ROOT; /* if there are only slashes... */
446         nd->flags = flags;
447 +       nd->intent = NULL;
448         if (*name=='/')
449                 return walk_init_root(name,nd);
450         read_lock(&current->fs->lock);
451 @@ -779,7 +878,8 @@
452   * needs parent already locked. Doesn't follow mounts.
453   * SMP-safe.
454   */
455 -struct dentry * lookup_hash(struct qstr *name, struct dentry * base)
456 +struct dentry * lookup_hash_it(struct qstr *name, struct dentry * base,
457 +                              struct lookup_intent *it)
458  {
459         struct dentry * dentry;
460         struct inode *inode;
461 @@ -802,13 +902,16 @@
462                         goto out;
463         }
464  
465 -       dentry = cached_lookup(base, name, 0);
466 +       dentry = cached_lookup(base, name, 0, it);
467         if (!dentry) {
468                 struct dentry *new = d_alloc(base, name);
469                 dentry = ERR_PTR(-ENOMEM);
470                 if (!new)
471                         goto out;
472                 lock_kernel();
473 +               if (inode->i_op->lookup_it)
474 +                       dentry = inode->i_op->lookup_it(inode, new, it, 0);
475 +               else
476                 dentry = inode->i_op->lookup(inode, new);
477                 unlock_kernel();
478                 if (!dentry)
479 @@ -820,6 +923,12 @@
480         return dentry;
481  }
482  
483 +struct dentry * lookup_hash(struct qstr *name, struct dentry * base)
484 +{
485 +       return lookup_hash_it(name, base, NULL);
486 +}
487 +
488 +
489  /* SMP-safe */
490  struct dentry * lookup_one_len(const char * name, struct dentry * base, int len)
491  {
492 @@ -841,7 +950,7 @@
493         }
494         this.hash = end_name_hash(hash);
495  
496 -       return lookup_hash(&this, base);
497 +       return lookup_hash_it(&this, base, NULL);
498  access:
499         return ERR_PTR(-EACCES);
500  }
501 @@ -872,6 +981,23 @@
502         return err;
503  }
504  
505 +int __user_walk_it(const char *name, unsigned flags, struct nameidata *nd,
506 +                  struct lookup_intent *it)
507 +{
508 +       char *tmp;
509 +       int err;
510 +
511 +       tmp = getname(name);
512 +       err = PTR_ERR(tmp);
513 +       if (!IS_ERR(tmp)) {
514 +               err = 0;
515 +               if (path_init(tmp, flags, nd))
516 +                       err = path_walk_it(tmp, nd, it);
517 +               putname(tmp);
518 +       }
519 +       return err;
520 +}
521 +
522  /*
523   * It's inline, so penalty for filesystems that don't use sticky bit is
524   * minimal.
525 @@ -969,7 +1095,8 @@
526         return retval;
527  }
528  
529 -int vfs_create(struct inode *dir, struct dentry *dentry, int mode)
530 +static int vfs_create_it(struct inode *dir, struct dentry *dentry, int mode,
531 +                        struct lookup_intent *it)
532  {
533         int error;
534  
535 @@ -982,12 +1109,15 @@
536                 goto exit_lock;
537  
538         error = -EACCES;        /* shouldn't it be ENOSYS? */
539 -       if (!dir->i_op || !dir->i_op->create)
540 +       if (!dir->i_op || (!dir->i_op->create && !dir->i_op->create_it))
541                 goto exit_lock;
542  
543         DQUOT_INIT(dir);
544         lock_kernel();
545 -       error = dir->i_op->create(dir, dentry, mode);
546 +       if (dir->i_op->create_it)
547 +               error = dir->i_op->create_it(dir, dentry, mode, it);
548 +       else
549 +               error = dir->i_op->create(dir, dentry, mode);
550         unlock_kernel();
551  exit_lock:
552         up(&dir->i_zombie);
553 @@ -996,6 +1126,11 @@
554         return error;
555  }
556  
557 +int vfs_create(struct inode *dir, struct dentry *dentry, int mode)
558 +{
559 +       return vfs_create_it(dir, dentry, mode, NULL);
560 +}
561 +
562  /*
563   *     open_namei()
564   *
565 @@ -1010,7 +1145,8 @@
566   * for symlinks (where the permissions are checked later).
567   * SMP-safe
568   */
569 -int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd)
570 +int open_namei_it(const char *pathname, int flag, int mode,
571 +                 struct nameidata *nd, struct lookup_intent *it)
572  {
573         int acc_mode, error = 0;
574         struct inode *inode;
575 @@ -1020,11 +1156,14 @@
576  
577         acc_mode = ACC_MODE(flag);
578  
579 +       if (it)
580 +               it->it_flags = flag;
581 +
582         /*
583          * The simplest case - just a plain lookup.
584          */
585         if (!(flag & O_CREAT)) {
586 -               error = path_lookup(pathname, lookup_flags(flag), nd);
587 +               error = path_lookup_it(pathname, lookup_flags(flag), nd, it);
588                 if (error)
589                         return error;
590                 dentry = nd->dentry;
591 @@ -1034,6 +1173,10 @@
592         /*
593          * Create - we need to know the parent.
594          */
595 +       if (it) {
596 +               it->it_create_mode = mode;
597 +               it->it_op |= IT_CREAT;
598 +       }
599         error = path_lookup(pathname, LOOKUP_PARENT, nd);
600         if (error)
601                 return error;
602 @@ -1049,7 +1192,7 @@
603  
604         dir = nd->dentry;
605         down(&dir->d_inode->i_sem);
606 -       dentry = lookup_hash(&nd->last, nd->dentry);
607 +       dentry = lookup_hash_it(&nd->last, nd->dentry, it);
608  
609  do_last:
610         error = PTR_ERR(dentry);
611 @@ -1058,10 +1201,11 @@
612                 goto exit;
613         }
614  
615 +       it->it_create_mode = mode;
616         /* Negative dentry, just create the file */
617         if (!dentry->d_inode) {
618 -               error = vfs_create(dir->d_inode, dentry,
619 -                                  mode & ~current->fs->umask);
620 +               error = vfs_create_it(dir->d_inode, dentry,
621 +                                  mode & ~current->fs->umask, it);
622                 up(&dir->d_inode->i_sem);
623                 dput(nd->dentry);
624                 nd->dentry = dentry;
625 @@ -1086,7 +1230,7 @@
626                 error = -ELOOP;
627                 if (flag & O_NOFOLLOW)
628                         goto exit_dput;
629 -               while (__follow_down(&nd->mnt,&dentry) && d_mountpoint(dentry));
630 +               while (__follow_down(&nd->mnt,&dentry,it) && d_mountpoint(dentry));
631         }
632         error = -ENOENT;
633         if (!dentry->d_inode)
634 @@ -1165,7 +1309,7 @@
635                 if (!error) {
636                         DQUOT_INIT(inode);
637                         
638 -                       error = do_truncate(dentry, 0);
639 +                       error = do_truncate(dentry, 0, 1);
640                 }
641                 put_write_access(inode);
642                 if (error)
643 @@ -1177,8 +1321,10 @@
644         return 0;
645  
646  exit_dput:
647 +       intent_release(it);
648         dput(dentry);
649  exit:
650 +       intent_release(it);
651         path_release(nd);
652         return error;
653  
654 @@ -1197,7 +1343,16 @@
655          * are done. Procfs-like symlinks just set LAST_BIND.
656          */
657         UPDATE_ATIME(dentry->d_inode);
658 +       nd->intent = it;
659         error = dentry->d_inode->i_op->follow_link(dentry, nd);
660 +       if (error) {
661 +               intent_release(it);
662 +       } else if (it != NULL && !(it->d.lustre.it_int_flags & IT_FL_FOLLOWED)) {
663 +               /* vfs_follow_link was never called */
664 +               intent_release(it);
665 +               path_release(nd);
666 +               error = -ENOLINK;
667 +       }
668         dput(dentry);
669         if (error)
670                 return error;
671 @@ -1219,13 +1374,20 @@
672         }
673         dir = nd->dentry;
674         down(&dir->d_inode->i_sem);
675 -       dentry = lookup_hash(&nd->last, nd->dentry);
676 +       dentry = lookup_hash_it(&nd->last, nd->dentry, it);
677         putname(nd->last.name);
678         goto do_last;
679  }
680  
681 +int open_namei(const char *pathname, int flag, int mode, struct nameidata *nd)
682 +{
683 +       return open_namei_it(pathname, flag, mode, nd, NULL);
684 +}
685 +
686 +
687  /* SMP-safe */
688 -static struct dentry *lookup_create(struct nameidata *nd, int is_dir)
689 +static struct dentry *lookup_create(struct nameidata *nd, int is_dir,
690 +                                   struct lookup_intent *it)
691  {
692         struct dentry *dentry;
693  
694 @@ -1233,7 +1395,7 @@
695         dentry = ERR_PTR(-EEXIST);
696         if (nd->last_type != LAST_NORM)
697                 goto fail;
698 -       dentry = lookup_hash(&nd->last, nd->dentry);
699 +       dentry = lookup_hash_it(&nd->last, nd->dentry, it);
700         if (IS_ERR(dentry))
701                 goto fail;
702         if (!is_dir && nd->last.name[nd->last.len] && !dentry->d_inode)
703 @@ -1289,7 +1451,20 @@
704         error = path_lookup(tmp, LOOKUP_PARENT, &nd);
705         if (error)
706                 goto out;
707 -       dentry = lookup_create(&nd, 0);
708 +
709 +       if (nd.last_type != LAST_NORM) {
710 +               error = -EEXIST;
711 +               goto out2;
712 +       }
713 +       if (nd.dentry->d_inode->i_op->mknod_raw) {
714 +               struct inode_operations *op = nd.dentry->d_inode->i_op;
715 +               error = op->mknod_raw(&nd, mode, dev);
716 +               /* the file system wants to use normal vfs path now */
717 +               if (error != -EOPNOTSUPP)
718 +                       goto out2;
719 +       }
720 +
721 +       dentry = lookup_create(&nd, 0, NULL);
722         error = PTR_ERR(dentry);
723  
724         mode &= ~current->fs->umask;
725 @@ -1310,6 +1485,7 @@
726                 dput(dentry);
727         }
728         up(&nd.dentry->d_inode->i_sem);
729 +out2:
730         path_release(&nd);
731  out:
732         putname(tmp);
733 @@ -1357,7 +1533,18 @@
734                 error = path_lookup(tmp, LOOKUP_PARENT, &nd);
735                 if (error)
736                         goto out;
737 -               dentry = lookup_create(&nd, 1);
738 +               if (nd.last_type != LAST_NORM) {
739 +                       error = -EEXIST;
740 +                       goto out2;
741 +               }
742 +               if (nd.dentry->d_inode->i_op->mkdir_raw) {
743 +                       struct inode_operations *op = nd.dentry->d_inode->i_op;
744 +                       error = op->mkdir_raw(&nd, mode);
745 +                       /* the file system wants to use normal vfs path now */
746 +                       if (error != -EOPNOTSUPP)
747 +                               goto out2;
748 +               }
749 +               dentry = lookup_create(&nd, 1, NULL);
750                 error = PTR_ERR(dentry);
751                 if (!IS_ERR(dentry)) {
752                         error = vfs_mkdir(nd.dentry->d_inode, dentry,
753 @@ -1365,6 +1552,7 @@
754                         dput(dentry);
755                 }
756                 up(&nd.dentry->d_inode->i_sem);
757 +out2:
758                 path_release(&nd);
759  out:
760                 putname(tmp);
761 @@ -1465,8 +1653,16 @@
762                         error = -EBUSY;
763                         goto exit1;
764         }
765 +       if (nd.dentry->d_inode->i_op->rmdir_raw) {
766 +               struct inode_operations *op = nd.dentry->d_inode->i_op;
767 +
768 +               error = op->rmdir_raw(&nd);
769 +               /* the file system wants to use normal vfs path now */
770 +               if (error != -EOPNOTSUPP)
771 +                       goto exit1;
772 +       }
773         down(&nd.dentry->d_inode->i_sem);
774 -       dentry = lookup_hash(&nd.last, nd.dentry);
775 +       dentry = lookup_hash_it(&nd.last, nd.dentry, NULL);
776         error = PTR_ERR(dentry);
777         if (!IS_ERR(dentry)) {
778                 error = vfs_rmdir(nd.dentry->d_inode, dentry);
779 @@ -1524,8 +1720,15 @@
780         error = -EISDIR;
781         if (nd.last_type != LAST_NORM)
782                 goto exit1;
783 +       if (nd.dentry->d_inode->i_op->unlink_raw) {
784 +               struct inode_operations *op = nd.dentry->d_inode->i_op;
785 +               error = op->unlink_raw(&nd);
786 +               /* the file system wants to use normal vfs path now */
787 +               if (error != -EOPNOTSUPP)
788 +                       goto exit1;
789 +       }
790         down(&nd.dentry->d_inode->i_sem);
791 -       dentry = lookup_hash(&nd.last, nd.dentry);
792 +       dentry = lookup_hash_it(&nd.last, nd.dentry, NULL);
793         error = PTR_ERR(dentry);
794         if (!IS_ERR(dentry)) {
795                 /* Why not before? Because we want correct error value */
796 @@ -1592,15 +1795,27 @@
797                 error = path_lookup(to, LOOKUP_PARENT, &nd);
798                 if (error)
799                         goto out;
800 -               dentry = lookup_create(&nd, 0);
801 +               if (nd.last_type != LAST_NORM) {
802 +                       error = -EEXIST;
803 +                       goto out2;
804 +               }
805 +               if (nd.dentry->d_inode->i_op->symlink_raw) {
806 +                       struct inode_operations *op = nd.dentry->d_inode->i_op;
807 +                       error = op->symlink_raw(&nd, from);
808 +                       /* the file system wants to use normal vfs path now */
809 +                       if (error != -EOPNOTSUPP)
810 +                               goto out2;
811 +               }
812 +               dentry = lookup_create(&nd, 0, NULL);
813                 error = PTR_ERR(dentry);
814                 if (!IS_ERR(dentry)) {
815                         error = vfs_symlink(nd.dentry->d_inode, dentry, from);
816                         dput(dentry);
817                 }
818                 up(&nd.dentry->d_inode->i_sem);
819 +       out2:
820                 path_release(&nd);
821 -out:
822 +       out:
823                 putname(to);
824         }
825         putname(from);
826 @@ -1676,7 +1891,18 @@
827                 error = -EXDEV;
828                 if (old_nd.mnt != nd.mnt)
829                         goto out_release;
830 -               new_dentry = lookup_create(&nd, 0);
831 +               if (nd.last_type != LAST_NORM) {
832 +                       error = -EEXIST;
833 +                       goto out_release;
834 +               }
835 +               if (nd.dentry->d_inode->i_op->link_raw) {
836 +                       struct inode_operations *op = nd.dentry->d_inode->i_op;
837 +                       error = op->link_raw(&old_nd, &nd);
838 +                       /* the file system wants to use normal vfs path now */
839 +                       if (error != -EOPNOTSUPP)
840 +                               goto out_release;
841 +               }
842 +               new_dentry = lookup_create(&nd, 0, NULL);
843                 error = PTR_ERR(new_dentry);
844                 if (!IS_ERR(new_dentry)) {
845                         error = vfs_link(old_nd.dentry, nd.dentry->d_inode, new_dentry);
846 @@ -1720,7 +1946,7 @@
847   *        locking].
848   */
849  int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
850 -              struct inode *new_dir, struct dentry *new_dentry)
851 +                  struct inode *new_dir, struct dentry *new_dentry)
852  {
853         int error;
854         struct inode *target;
855 @@ -1799,7 +2025,7 @@
856  }
857  
858  int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry,
859 -              struct inode *new_dir, struct dentry *new_dentry)
860 +                    struct inode *new_dir, struct dentry *new_dentry)
861  {
862         int error;
863  
864 @@ -1887,9 +2113,18 @@
865         if (newnd.last_type != LAST_NORM)
866                 goto exit2;
867  
868 +       if (old_dir->d_inode->i_op->rename_raw) {
869 +               lock_kernel();
870 +               error = old_dir->d_inode->i_op->rename_raw(&oldnd, &newnd);
871 +               unlock_kernel();
872 +               /* the file system wants to use normal vfs path now */
873 +               if (error != -EOPNOTSUPP)
874 +                       goto exit2;
875 +       }
876 +
877         double_lock(new_dir, old_dir);
878  
879 -       old_dentry = lookup_hash(&oldnd.last, old_dir);
880 +       old_dentry = lookup_hash_it(&oldnd.last, old_dir, NULL);
881         error = PTR_ERR(old_dentry);
882         if (IS_ERR(old_dentry))
883                 goto exit3;
884 @@ -1905,16 +2140,16 @@
885                 if (newnd.last.name[newnd.last.len])
886                         goto exit4;
887         }
888 -       new_dentry = lookup_hash(&newnd.last, new_dir);
889 +       new_dentry = lookup_hash_it(&newnd.last, new_dir, NULL);
890         error = PTR_ERR(new_dentry);
891         if (IS_ERR(new_dentry))
892                 goto exit4;
893  
894 +
895         lock_kernel();
896         error = vfs_rename(old_dir->d_inode, old_dentry,
897                                    new_dir->d_inode, new_dentry);
898         unlock_kernel();
899 -
900         dput(new_dentry);
901  exit4:
902         dput(old_dentry);
903 @@ -1965,20 +2200,28 @@
904  }
905  
906  static inline int
907 -__vfs_follow_link(struct nameidata *nd, const char *link)
908 +__vfs_follow_link(struct nameidata *nd, const char *link,
909 +                 struct lookup_intent *it)
910  {
911         int res = 0;
912         char *name;
913         if (IS_ERR(link))
914                 goto fail;
915  
916 +       if (it == NULL)
917 +               it = nd->intent;
918 +       else if (it != nd->intent)
919 +               printk("it != nd->intent: tell phil@clusterfs.com\n");
920 +       if (it != NULL)
921 +               it->d.lustre.it_int_flags |= IT_FL_FOLLOWED;
922 +
923         if (*link == '/') {
924                 path_release(nd);
925                 if (!walk_init_root(link, nd))
926                         /* weird __emul_prefix() stuff did it */
927                         goto out;
928         }
929 -       res = link_path_walk(link, nd);
930 +       res = link_path_walk_it(link, nd, it);
931  out:
932         if (current->link_count || res || nd->last_type!=LAST_NORM)
933                 return res;
934 @@ -2002,7 +2245,13 @@
935  
936  int vfs_follow_link(struct nameidata *nd, const char *link)
937  {
938 -       return __vfs_follow_link(nd, link);
939 +       return __vfs_follow_link(nd, link, NULL);
940 +}
941 +
942 +int vfs_follow_link_it(struct nameidata *nd, const char *link,
943 +                      struct lookup_intent *it)
944 +{
945 +       return __vfs_follow_link(nd, link, it);
946  }
947  
948  /* get the link contents into pagecache */
949 @@ -2044,7 +2293,7 @@
950  {
951         struct page *page = NULL;
952         char *s = page_getlink(dentry, &page);
953 -       int res = __vfs_follow_link(nd, s);
954 +       int res = __vfs_follow_link(nd, s, NULL);
955         if (page) {
956                 kunmap(page);
957                 page_cache_release(page);
958 Index: linux-2.4.20/fs/namespace.c
959 ===================================================================
960 --- linux-2.4.20.orig/fs/namespace.c    Wed Mar 17 13:57:05 2004
961 +++ linux-2.4.20/fs/namespace.c Wed Mar 17 13:57:11 2004
962 @@ -99,6 +99,7 @@
963  {
964         old_nd->dentry = mnt->mnt_mountpoint;
965         old_nd->mnt = mnt->mnt_parent;
966 +       UNPIN(old_nd->dentry, old_nd->mnt, 1);
967         mnt->mnt_parent = mnt;
968         mnt->mnt_mountpoint = mnt->mnt_root;
969         list_del_init(&mnt->mnt_child);
970 @@ -110,6 +111,7 @@
971  {
972         mnt->mnt_parent = mntget(nd->mnt);
973         mnt->mnt_mountpoint = dget(nd->dentry);
974 +       PIN(nd->dentry, nd->mnt, 1);
975         list_add(&mnt->mnt_hash, mount_hashtable+hash(nd->mnt, nd->dentry));
976         list_add(&mnt->mnt_child, &nd->mnt->mnt_mounts);
977         nd->dentry->d_mounted++;
978 @@ -485,14 +487,17 @@
979  {
980         struct nameidata old_nd;
981         struct vfsmount *mnt = NULL;
982 +       struct lookup_intent it = { .it_op = IT_GETATTR };
983         int err = mount_is_safe(nd);
984         if (err)
985                 return err;
986         if (!old_name || !*old_name)
987                 return -EINVAL;
988 -       err = path_lookup(old_name, LOOKUP_POSITIVE|LOOKUP_FOLLOW, &old_nd);
989 -       if (err)
990 +       err = path_lookup_it(old_name, LOOKUP_POSITIVE|LOOKUP_FOLLOW, &old_nd, &it);
991 +       if (err) {
992 +               intent_release(&it);
993                 return err;
994 +       }
995  
996         down_write(&current->namespace->sem);
997         err = -EINVAL;
998 @@ -515,6 +520,7 @@
999         }
1000  
1001         up_write(&current->namespace->sem);
1002 +       intent_release(&it);
1003         path_release(&old_nd);
1004         return err;
1005  }
1006 @@ -698,6 +704,7 @@
1007                   unsigned long flags, void *data_page)
1008  {
1009         struct nameidata nd;
1010 +       struct lookup_intent it = { .it_op = IT_GETATTR };
1011         int retval = 0;
1012         int mnt_flags = 0;
1013  
1014 @@ -722,10 +729,11 @@
1015         flags &= ~(MS_NOSUID|MS_NOEXEC|MS_NODEV);
1016  
1017         /* ... and get the mountpoint */
1018 -       retval = path_lookup(dir_name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd);
1019 -       if (retval)
1020 +       retval = path_lookup_it(dir_name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd, &it);
1021 +       if (retval) {
1022 +               intent_release(&it);
1023                 return retval;
1024 -
1025 +       }
1026         if (flags & MS_REMOUNT)
1027                 retval = do_remount(&nd, flags & ~MS_REMOUNT, mnt_flags,
1028                                     data_page);
1029 @@ -736,6 +744,8 @@
1030         else
1031                 retval = do_add_mount(&nd, type_page, flags, mnt_flags,
1032                                       dev_name, data_page);
1033 +
1034 +       intent_release(&it);
1035         path_release(&nd);
1036         return retval;
1037  }
1038 @@ -901,6 +911,8 @@
1039  {
1040         struct vfsmount *tmp;
1041         struct nameidata new_nd, old_nd, parent_nd, root_parent, user_nd;
1042 +       struct lookup_intent new_it = { .it_op = IT_GETATTR };
1043 +       struct lookup_intent old_it = { .it_op = IT_GETATTR };
1044         int error;
1045  
1046         if (!capable(CAP_SYS_ADMIN))
1047 @@ -908,14 +920,14 @@
1048  
1049         lock_kernel();
1050  
1051 -       error = __user_walk(new_root, LOOKUP_POSITIVE|LOOKUP_FOLLOW|LOOKUP_DIRECTORY, &new_nd);
1052 +       error = __user_walk_it(new_root, LOOKUP_POSITIVE|LOOKUP_FOLLOW|LOOKUP_DIRECTORY, &new_nd, &new_it);
1053         if (error)
1054                 goto out0;
1055         error = -EINVAL;
1056         if (!check_mnt(new_nd.mnt))
1057                 goto out1;
1058  
1059 -       error = __user_walk(put_old, LOOKUP_POSITIVE|LOOKUP_FOLLOW|LOOKUP_DIRECTORY, &old_nd);
1060 +       error = __user_walk_it(put_old, LOOKUP_POSITIVE|LOOKUP_FOLLOW|LOOKUP_DIRECTORY, &old_nd, &old_it);
1061         if (error)
1062                 goto out1;
1063  
1064 @@ -970,8 +982,10 @@
1065         up(&old_nd.dentry->d_inode->i_zombie);
1066         up_write(&current->namespace->sem);
1067         path_release(&user_nd);
1068 +       intent_release(&old_it);
1069         path_release(&old_nd);
1070  out1:
1071 +       intent_release(&new_it);
1072         path_release(&new_nd);
1073  out0:
1074         unlock_kernel();
1075 Index: linux-2.4.20/fs/open.c
1076 ===================================================================
1077 --- linux-2.4.20.orig/fs/open.c Wed Mar 17 13:57:03 2004
1078 +++ linux-2.4.20/fs/open.c      Wed Mar 17 13:57:11 2004
1079 @@ -19,6 +19,8 @@
1080  #include <asm/uaccess.h>
1081  
1082  #define special_file(m) (S_ISCHR(m)||S_ISBLK(m)||S_ISFIFO(m)||S_ISSOCK(m))
1083 +extern int path_walk_it(const char *name, struct nameidata *nd,
1084 +                       struct lookup_intent *it);
1085  
1086  int vfs_statfs(struct super_block *sb, struct statfs *buf)
1087  {
1088 @@ -95,9 +97,10 @@
1089         write_unlock(&files->file_lock);
1090  }
1091  
1092 -int do_truncate(struct dentry *dentry, loff_t length)
1093 +int do_truncate(struct dentry *dentry, loff_t length, int called_from_open)
1094  {
1095         struct inode *inode = dentry->d_inode;
1096 +       struct inode_operations *op = dentry->d_inode->i_op;
1097         int error;
1098         struct iattr newattrs;
1099  
1100 @@ -108,7 +111,13 @@
1101         down(&inode->i_sem);
1102         newattrs.ia_size = length;
1103         newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
1104 -       error = notify_change(dentry, &newattrs);
1105 +       if (called_from_open)
1106 +               newattrs.ia_valid |= ATTR_FROM_OPEN;
1107 +       if (op->setattr_raw) {
1108 +               newattrs.ia_valid |= ATTR_RAW;
1109 +               error = op->setattr_raw(inode, &newattrs);
1110 +       } else
1111 +               error = notify_change(dentry, &newattrs);
1112         up(&inode->i_sem);
1113         return error;
1114  }
1115 @@ -118,12 +127,13 @@
1116         struct nameidata nd;
1117         struct inode * inode;
1118         int error;
1119 +       struct lookup_intent it = { .it_op = IT_GETATTR };
1120  
1121         error = -EINVAL;
1122         if (length < 0) /* sorry, but loff_t says... */
1123                 goto out;
1124  
1125 -       error = user_path_walk(path, &nd);
1126 +       error = user_path_walk_it(path, &nd, &it);
1127         if (error)
1128                 goto out;
1129         inode = nd.dentry->d_inode;
1130 @@ -163,11 +173,13 @@
1131         error = locks_verify_truncate(inode, NULL, length);
1132         if (!error) {
1133                 DQUOT_INIT(inode);
1134 -               error = do_truncate(nd.dentry, length);
1135 +               intent_release(&it);
1136 +               error = do_truncate(nd.dentry, length, 0);
1137         }
1138         put_write_access(inode);
1139  
1140  dput_and_out:
1141 +       intent_release(&it);
1142         path_release(&nd);
1143  out:
1144         return error;
1145 @@ -215,7 +227,7 @@
1146  
1147         error = locks_verify_truncate(inode, file, length);
1148         if (!error)
1149 -               error = do_truncate(dentry, length);
1150 +               error = do_truncate(dentry, length, 0);
1151  out_putf:
1152         fput(file);
1153  out:
1154 @@ -260,11 +272,13 @@
1155         struct inode * inode;
1156         struct iattr newattrs;
1157  
1158 -       error = user_path_walk(filename, &nd);
1159 +       error = user_path_walk_it(filename, &nd, NULL);
1160         if (error)
1161                 goto out;
1162         inode = nd.dentry->d_inode;
1163  
1164 +       /* this is safe without a Lustre lock because it only depends
1165 +          on the super block */
1166         error = -EROFS;
1167         if (IS_RDONLY(inode))
1168                 goto dput_and_out;
1169 @@ -279,11 +293,25 @@
1170                         goto dput_and_out;
1171  
1172                 newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
1173 -       } else {
1174 +       }
1175 +
1176 +       if (inode->i_op->setattr_raw) {
1177 +               struct inode_operations *op = nd.dentry->d_inode->i_op;
1178 +
1179 +               newattrs.ia_valid |= ATTR_RAW;
1180 +               error = op->setattr_raw(inode, &newattrs);
1181 +               /* the file system wants to use normal vfs path now */
1182 +               if (error != -EOPNOTSUPP)
1183 +                       goto dput_and_out;
1184 +       }
1185 +
1186 +       error = -EPERM;
1187 +       if (!times) {
1188                 if (current->fsuid != inode->i_uid &&
1189                     (error = permission(inode,MAY_WRITE)) != 0)
1190                         goto dput_and_out;
1191         }
1192 +
1193         error = notify_change(nd.dentry, &newattrs);
1194  dput_and_out:
1195         path_release(&nd);
1196 @@ -304,12 +332,14 @@
1197         struct inode * inode;
1198         struct iattr newattrs;
1199  
1200 -       error = user_path_walk(filename, &nd);
1201 +       error = user_path_walk_it(filename, &nd, NULL);
1202  
1203         if (error)
1204                 goto out;
1205         inode = nd.dentry->d_inode;
1206  
1207 +       /* this is safe without a Lustre lock because it only depends
1208 +          on the super block */
1209         error = -EROFS;
1210         if (IS_RDONLY(inode))
1211                 goto dput_and_out;
1212 @@ -324,7 +354,20 @@
1213                 newattrs.ia_atime = times[0].tv_sec;
1214                 newattrs.ia_mtime = times[1].tv_sec;
1215                 newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
1216 -       } else {
1217 +       }
1218 +
1219 +       if (inode->i_op->setattr_raw) {
1220 +               struct inode_operations *op = nd.dentry->d_inode->i_op;
1221 +
1222 +               newattrs.ia_valid |= ATTR_RAW;
1223 +               error = op->setattr_raw(inode, &newattrs);
1224 +               /* the file system wants to use normal vfs path now */
1225 +               if (error != -EOPNOTSUPP)
1226 +                       goto dput_and_out;
1227 +       }
1228 +
1229 +       error = -EPERM;
1230 +       if (!utimes) {
1231                 if (current->fsuid != inode->i_uid &&
1232                     (error = permission(inode,MAY_WRITE)) != 0)
1233                         goto dput_and_out;
1234 @@ -347,6 +390,7 @@
1235         int old_fsuid, old_fsgid;
1236         kernel_cap_t old_cap;
1237         int res;
1238 +       struct lookup_intent it = { .it_op = IT_GETATTR };
1239  
1240         if (mode & ~S_IRWXO)    /* where's F_OK, X_OK, W_OK, R_OK? */
1241                 return -EINVAL;
1242 @@ -364,13 +408,14 @@
1243         else
1244                 current->cap_effective = current->cap_permitted;
1245  
1246 -       res = user_path_walk(filename, &nd);
1247 +       res = user_path_walk_it(filename, &nd, &it);
1248         if (!res) {
1249                 res = permission(nd.dentry->d_inode, mode);
1250                 /* SuS v2 requires we report a read only fs too */
1251                 if(!res && (mode & S_IWOTH) && IS_RDONLY(nd.dentry->d_inode)
1252                    && !special_file(nd.dentry->d_inode->i_mode))
1253                         res = -EROFS;
1254 +               intent_release(&it);
1255                 path_release(&nd);
1256         }
1257  
1258 @@ -385,8 +430,9 @@
1259  {
1260         int error;
1261         struct nameidata nd;
1262 +       struct lookup_intent it = { .it_op = IT_GETATTR };
1263  
1264 -       error = __user_walk(filename,LOOKUP_POSITIVE|LOOKUP_FOLLOW|LOOKUP_DIRECTORY,&nd);
1265 +       error = __user_walk_it(filename,LOOKUP_POSITIVE|LOOKUP_FOLLOW|LOOKUP_DIRECTORY,&nd, &it);
1266         if (error)
1267                 goto out;
1268  
1269 @@ -397,6 +443,7 @@
1270         set_fs_pwd(current->fs, nd.mnt, nd.dentry);
1271  
1272  dput_and_out:
1273 +       intent_release(&it);
1274         path_release(&nd);
1275  out:
1276         return error;
1277 @@ -436,9 +483,10 @@
1278  {
1279         int error;
1280         struct nameidata nd;
1281 +       struct lookup_intent it = { .it_op = IT_GETATTR };
1282  
1283 -       error = __user_walk(filename, LOOKUP_POSITIVE | LOOKUP_FOLLOW |
1284 -                     LOOKUP_DIRECTORY | LOOKUP_NOALT, &nd);
1285 +       error = __user_walk_it(filename, LOOKUP_POSITIVE | LOOKUP_FOLLOW |
1286 +                     LOOKUP_DIRECTORY | LOOKUP_NOALT, &nd, &it);
1287         if (error)
1288                 goto out;
1289  
1290 @@ -454,39 +502,56 @@
1291         set_fs_altroot();
1292         error = 0;
1293  dput_and_out:
1294 +       intent_release(&it);
1295         path_release(&nd);
1296  out:
1297         return error;
1298  }
1299  
1300 -asmlinkage long sys_fchmod(unsigned int fd, mode_t mode)
1301 +int chmod_common(struct dentry *dentry, mode_t mode)
1302  {
1303 -       struct inode * inode;
1304 -       struct dentry * dentry;
1305 -       struct file * file;
1306 -       int err = -EBADF;
1307 +       struct inode *inode = dentry->d_inode;
1308         struct iattr newattrs;
1309 +       int err = -EROFS;
1310  
1311 -       file = fget(fd);
1312 -       if (!file)
1313 +       if (IS_RDONLY(inode))
1314                 goto out;
1315  
1316 -       dentry = file->f_dentry;
1317 -       inode = dentry->d_inode;
1318 +       if (inode->i_op->setattr_raw) {
1319 +               newattrs.ia_mode = mode;
1320 +               newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
1321 +               newattrs.ia_valid |= ATTR_RAW;
1322 +               err = inode->i_op->setattr_raw(inode, &newattrs);
1323 +               /* the file system wants to use normal vfs path now */
1324 +               if (err != -EOPNOTSUPP)
1325 +                       goto out;
1326 +       }
1327  
1328 -       err = -EROFS;
1329 -       if (IS_RDONLY(inode))
1330 -               goto out_putf;
1331         err = -EPERM;
1332         if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
1333 -               goto out_putf;
1334 +               goto out;
1335 +
1336         if (mode == (mode_t) -1)
1337                 mode = inode->i_mode;
1338         newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
1339         newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
1340         err = notify_change(dentry, &newattrs);
1341  
1342 -out_putf:
1343 +out:
1344 +       return err;
1345 +}
1346 +
1347 +asmlinkage long sys_fchmod(unsigned int fd, mode_t mode)
1348 +{
1349 +       struct file * file;
1350 +       int err = -EBADF;
1351 +
1352 +       file = fget(fd);
1353 +       if (!file)
1354 +               goto out;
1355 +
1356 +       err = chmod_common(file->f_dentry, mode);
1357 +
1358         fput(file);
1359  out:
1360         return err;
1361 @@ -495,30 +560,14 @@
1362  asmlinkage long sys_chmod(const char * filename, mode_t mode)
1363  {
1364         struct nameidata nd;
1365 -       struct inode * inode;
1366         int error;
1367 -       struct iattr newattrs;
1368  
1369         error = user_path_walk(filename, &nd);
1370         if (error)
1371                 goto out;
1372 -       inode = nd.dentry->d_inode;
1373 -
1374 -       error = -EROFS;
1375 -       if (IS_RDONLY(inode))
1376 -               goto dput_and_out;
1377 -
1378 -       error = -EPERM;
1379 -       if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
1380 -               goto dput_and_out;
1381  
1382 -       if (mode == (mode_t) -1)
1383 -               mode = inode->i_mode;
1384 -       newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
1385 -       newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
1386 -       error = notify_change(nd.dentry, &newattrs);
1387 +       error = chmod_common(nd.dentry, mode);
1388  
1389 -dput_and_out:
1390         path_release(&nd);
1391  out:
1392         return error;
1393 @@ -538,6 +587,20 @@
1394         error = -EROFS;
1395         if (IS_RDONLY(inode))
1396                 goto out;
1397 +
1398 +       if (inode->i_op->setattr_raw) {
1399 +               struct inode_operations *op = dentry->d_inode->i_op;
1400 +
1401 +               newattrs.ia_uid = user;
1402 +               newattrs.ia_gid = group;
1403 +               newattrs.ia_valid = ATTR_UID | ATTR_GID | ATTR_CTIME;
1404 +               newattrs.ia_valid |= ATTR_RAW;
1405 +               error = op->setattr_raw(inode, &newattrs);
1406 +               /* the file system wants to use normal vfs path now */
1407 +               if (error != -EOPNOTSUPP)
1408 +                       return error;
1409 +       }
1410 +
1411         error = -EPERM;
1412         if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
1413                 goto out;
1414 @@ -642,8 +705,9 @@
1415  {
1416         int namei_flags, error;
1417         struct nameidata nd;
1418 -       
1419 -       flags &= ~O_DIRECT;
1420 +       struct lookup_intent it = { .it_op = IT_OPEN };
1421 +
1422 +       //flags &= ~O_DIRECT;
1423  
1424         namei_flags = flags;
1425         if ((namei_flags+1) & O_ACCMODE)
1426 @@ -651,14 +715,15 @@
1427         if (namei_flags & O_TRUNC)
1428                 namei_flags |= 2;
1429  
1430 -       error = open_namei(filename, namei_flags, mode, &nd);
1431 -       if (!error)
1432 -               return dentry_open(nd.dentry, nd.mnt, flags);
1433 +       error = open_namei_it(filename, namei_flags, mode, &nd, &it);
1434 +       if (error)
1435 +               return ERR_PTR(error);
1436  
1437 -       return ERR_PTR(error);
1438 +       return dentry_open_it(nd.dentry, nd.mnt, flags, &it);
1439  }
1440  
1441 -struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags)
1442 +struct file *dentry_open_it(struct dentry *dentry, struct vfsmount *mnt,
1443 +                           int flags, struct lookup_intent *it)
1444  {
1445         struct file * f;
1446         struct inode *inode;
1447 @@ -695,12 +760,15 @@
1448         }
1449  
1450         if (f->f_op && f->f_op->open) {
1451 +               f->f_it = it;
1452                 error = f->f_op->open(inode,f);
1453 +               f->f_it = NULL;
1454                 if (error)
1455                         goto cleanup_all;
1456         }
1457         f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
1458  
1459 +       intent_release(it);
1460         return f;
1461  
1462  cleanup_all:
1463 @@ -715,11 +783,17 @@
1464  cleanup_file:
1465         put_filp(f);
1466  cleanup_dentry:
1467 +       intent_release(it);
1468         dput(dentry);
1469         mntput(mnt);
1470         return ERR_PTR(error);
1471  }
1472  
1473 +struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags)
1474 +{
1475 +       return dentry_open_it(dentry, mnt, flags, NULL);
1476 +}
1477 +
1478  /*
1479   * Find an empty file descriptor entry, and mark it busy.
1480   */
1481 Index: linux-2.4.20/fs/proc/base.c
1482 ===================================================================
1483 --- linux-2.4.20.orig/fs/proc/base.c    Wed Mar 17 13:57:05 2004
1484 +++ linux-2.4.20/fs/proc/base.c Wed Mar 17 13:57:11 2004
1485 @@ -494,6 +494,9 @@
1486  
1487         error = inode->u.proc_i.op.proc_get_link(inode, &nd->dentry, &nd->mnt);
1488         nd->last_type = LAST_BIND;
1489 +
1490 +       if (nd->intent != NULL)
1491 +               nd->intent->d.lustre.it_int_flags |= IT_FL_FOLLOWED;
1492  out:
1493         return error;
1494  }
1495 Index: linux-2.4.20/fs/stat.c
1496 ===================================================================
1497 --- linux-2.4.20.orig/fs/stat.c Wed Mar 17 13:57:05 2004
1498 +++ linux-2.4.20/fs/stat.c      Wed Mar 17 13:58:01 2004
1499 @@ -17,10 +17,12 @@
1500   * Revalidate the inode. This is required for proper NFS attribute caching.
1501   */
1502  static __inline__ int
1503 -do_revalidate(struct dentry *dentry)
1504 +do_revalidate(struct dentry *dentry, struct lookup_intent *it)
1505  {
1506         struct inode * inode = dentry->d_inode;
1507 -       if (inode->i_op && inode->i_op->revalidate)
1508 +       if (inode->i_op && inode->i_op->revalidate_it)
1509 +               return inode->i_op->revalidate_it(dentry, it);
1510 +       else if (inode->i_op && inode->i_op->revalidate)
1511                 return inode->i_op->revalidate(dentry);
1512         return 0;
1513  }
1514 @@ -32,13 +34,13 @@
1515         return inode->i_nlink;
1516  }
1517  
1518 -static int do_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
1519 +static int do_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat, struct lookup_intent *it)
1520  {
1521         int res = 0;
1522         unsigned int blocks, indirect;
1523         struct inode *inode = dentry->d_inode;
1524  
1525 -       res = do_revalidate(dentry);
1526 +       res = do_revalidate(dentry, it);
1527         if (res)
1528                 return res;
1529  
1530 @@ -111,10 +113,12 @@
1531  {
1532         struct nameidata nd;
1533         int error;
1534 +       struct lookup_intent it = { .it_op = IT_GETATTR };
1535  
1536 -       error = user_path_walk(name, &nd);
1537 +       error = user_path_walk_it(name, &nd, &it);
1538         if (!error) {
1539 -               error = do_getattr(nd.mnt, nd.dentry, stat);
1540 +               error = do_getattr(nd.mnt, nd.dentry, stat, &it);
1541 +               intent_release(&it);
1542                 path_release(&nd);
1543         }
1544         return error;
1545 @@ -124,10 +128,12 @@
1546  {
1547         struct nameidata nd;
1548         int error;
1549 +       struct lookup_intent it = { .it_op = IT_GETATTR };
1550  
1551 -       error = user_path_walk_link(name, &nd);
1552 +       error = user_path_walk_link_it(name, &nd, &it);
1553         if (!error) {
1554 -               error = do_getattr(nd.mnt, nd.dentry, stat);
1555 +               error = do_getattr(nd.mnt, nd.dentry, stat, &it);
1556 +               intent_release(&it);
1557                 path_release(&nd);
1558         }
1559         return error;
1560 @@ -139,7 +145,7 @@
1561         int error = -EBADF;
1562  
1563         if (f) {
1564 -               error = do_getattr(f->f_vfsmnt, f->f_dentry, stat);
1565 +               error = do_getattr(f->f_vfsmnt, f->f_dentry, stat, NULL);
1566                 fput(f);
1567         }
1568         return error;
1569 @@ -286,7 +292,7 @@
1570  
1571                 error = -EINVAL;
1572                 if (inode->i_op && inode->i_op->readlink &&
1573 -                   !(error = do_revalidate(nd.dentry))) {
1574 +                   !(error = do_revalidate(nd.dentry, NULL))) {
1575                         UPDATE_ATIME(inode);
1576                         error = inode->i_op->readlink(nd.dentry, buf, bufsiz);
1577                 }
1578 Index: linux-2.4.20/include/linux/dcache.h
1579 ===================================================================
1580 --- linux-2.4.20.orig/include/linux/dcache.h    Wed Mar 17 13:57:04 2004
1581 +++ linux-2.4.20/include/linux/dcache.h Wed Mar 17 13:57:11 2004
1582 @@ -6,6 +6,51 @@
1583  #include <asm/atomic.h>
1584  #include <linux/mount.h>
1585  #include <linux/kernel.h>
1586 +#include <linux/string.h>
1587 +
1588 +#define IT_OPEN     0x0001
1589 +#define IT_CREAT    0x0002
1590 +#define IT_READDIR  0x0004
1591 +#define IT_GETATTR  0x0008
1592 +#define IT_LOOKUP   0x0010
1593 +#define IT_UNLINK   0x0020
1594 +#define IT_GETXATTR 0x0040
1595 +#define IT_EXEC     0x0080
1596 +#define IT_PIN      0x0100
1597 +
1598 +#define IT_FL_LOCKED   0x0001
1599 +#define IT_FL_FOLLOWED 0x0002 /* set by vfs_follow_link */
1600 +
1601 +#define INTENT_MAGIC 0x19620323
1602 +
1603 +
1604 +struct lustre_intent_data {
1605 +       int       it_disposition;
1606 +       int       it_status;
1607 +       __u64     it_lock_handle;
1608 +       void     *it_data;
1609 +       int       it_lock_mode;
1610 +       int it_int_flags;
1611 +};
1612 +struct lookup_intent {
1613 +       int     it_magic;
1614 +       void    (*it_op_release)(struct lookup_intent *);
1615 +       int     it_op;
1616 +       int     it_flags;
1617 +       int     it_create_mode;
1618 +       union {
1619 +               struct lustre_intent_data lustre;
1620 +       } d;
1621 +};
1622 +
1623 +static inline void intent_init(struct lookup_intent *it, int op, int flags)
1624 +{
1625 +       memset(it, 0, sizeof(*it));
1626 +       it->it_magic = INTENT_MAGIC;
1627 +       it->it_op = op;
1628 +       it->it_flags = flags;
1629 +}
1630 +
1631  
1632  /*
1633   * linux/include/linux/dcache.h
1634 @@ -96,8 +141,22 @@
1635         int (*d_delete)(struct dentry *);
1636         void (*d_release)(struct dentry *);
1637         void (*d_iput)(struct dentry *, struct inode *);
1638 +       int (*d_revalidate_it)(struct dentry *, int, struct lookup_intent *);
1639 +       void (*d_pin)(struct dentry *, struct vfsmount * , int);
1640 +       void (*d_unpin)(struct dentry *, struct vfsmount *, int);
1641  };
1642  
1643 +#define PIN(de,mnt,flag)  if (de && de->d_op && de->d_op->d_pin) \
1644 +                               de->d_op->d_pin(de, mnt, flag);
1645 +#define UNPIN(de,mnt,flag)  if (de && de->d_op && de->d_op->d_unpin) \
1646 +                               de->d_op->d_unpin(de, mnt, flag);
1647 +
1648 +
1649 +/* defined in fs/namei.c */
1650 +extern void intent_release(struct lookup_intent *it);
1651 +/* defined in fs/dcache.c */
1652 +extern void __d_rehash(struct dentry * entry, int lock);
1653 +
1654  /* the dentry parameter passed to d_hash and d_compare is the parent
1655   * directory of the entries to be compared. It is used in case these
1656   * functions need any directory specific information for determining
1657 @@ -129,6 +188,7 @@
1658                                          * s_nfsd_free_path semaphore will be down
1659                                          */
1660  #define DCACHE_REFERENCED      0x0008  /* Recently used, don't discard. */
1661 +#define DCACHE_LUSTRE_INVALID  0x0010  /* Lustre invalidated */
1662  
1663  extern spinlock_t dcache_lock;
1664  
1665 Index: linux-2.4.20/include/linux/fs.h
1666 ===================================================================
1667 --- linux-2.4.20.orig/include/linux/fs.h        Wed Mar 17 13:57:11 2004
1668 +++ linux-2.4.20/include/linux/fs.h     Wed Mar 17 13:57:11 2004
1669 @@ -73,6 +73,7 @@
1670  
1671  #define FMODE_READ 1
1672  #define FMODE_WRITE 2
1673 +#define FMODE_EXEC 4
1674  
1675  #define READ 0
1676  #define WRITE 1
1677 @@ -338,6 +339,9 @@
1678  #define ATTR_MTIME_SET 256
1679  #define ATTR_FORCE     512     /* Not a change, but a change it */
1680  #define ATTR_ATTR_FLAG 1024
1681 +#define ATTR_RAW       0x0800  /* file system, not vfs will massage attrs */
1682 +#define ATTR_FROM_OPEN 0x1000  /* called from open path, ie O_TRUNC */
1683 +#define ATTR_CTIME_SET 0x2000
1684  
1685  /*
1686   * This is the Inode Attributes structure, used for notify_change().  It
1687 @@ -473,6 +477,7 @@
1688         struct pipe_inode_info  *i_pipe;
1689         struct block_device     *i_bdev;
1690         struct char_device      *i_cdev;
1691 +       void                    *i_filterdata;
1692  
1693         unsigned long           i_dnotify_mask; /* Directory notify events */
1694         struct dnotify_struct   *i_dnotify; /* for directory notifications */
1695 @@ -575,6 +580,7 @@
1696  
1697         /* needed for tty driver, and maybe others */
1698         void                    *private_data;
1699 +       struct lookup_intent    *f_it;
1700  
1701         /* preallocated helper kiobuf to speedup O_DIRECT */
1702         struct kiobuf           *f_iobuf;
1703 @@ -702,6 +708,7 @@
1704         struct qstr last;
1705         unsigned int flags;
1706         int last_type;
1707 +       struct lookup_intent *intent;
1708  };
1709  
1710  /*
1711 @@ -822,7 +829,8 @@
1712  extern int vfs_link(struct dentry *, struct inode *, struct dentry *);
1713  extern int vfs_rmdir(struct inode *, struct dentry *);
1714  extern int vfs_unlink(struct inode *, struct dentry *);
1715 -extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *);
1716 +int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
1717 +              struct inode *new_dir, struct dentry *new_dentry);
1718  
1719  /*
1720   * File types
1721 @@ -882,21 +890,32 @@
1722  
1723  struct inode_operations {
1724         int (*create) (struct inode *,struct dentry *,int);
1725 +       int (*create_it) (struct inode *,struct dentry *,int, struct lookup_intent *);
1726         struct dentry * (*lookup) (struct inode *,struct dentry *);
1727 +       struct dentry * (*lookup_it) (struct inode *,struct dentry *, struct lookup_intent *, int flags);
1728         int (*link) (struct dentry *,struct inode *,struct dentry *);
1729 +       int (*link_raw) (struct nameidata *,struct nameidata *);
1730         int (*unlink) (struct inode *,struct dentry *);
1731 +       int (*unlink_raw) (struct nameidata *);
1732         int (*symlink) (struct inode *,struct dentry *,const char *);
1733 +       int (*symlink_raw) (struct nameidata *,const char *);
1734         int (*mkdir) (struct inode *,struct dentry *,int);
1735 +       int (*mkdir_raw) (struct nameidata *,int);
1736         int (*rmdir) (struct inode *,struct dentry *);
1737 +       int (*rmdir_raw) (struct nameidata *);
1738         int (*mknod) (struct inode *,struct dentry *,int,int);
1739 +       int (*mknod_raw) (struct nameidata *,int,dev_t);
1740         int (*rename) (struct inode *, struct dentry *,
1741                         struct inode *, struct dentry *);
1742 +       int (*rename_raw) (struct nameidata *, struct nameidata *);
1743         int (*readlink) (struct dentry *, char *,int);
1744         int (*follow_link) (struct dentry *, struct nameidata *);
1745         void (*truncate) (struct inode *);
1746         int (*permission) (struct inode *, int);
1747         int (*revalidate) (struct dentry *);
1748 +       int (*revalidate_it) (struct dentry *, struct lookup_intent *);
1749         int (*setattr) (struct dentry *, struct iattr *);
1750 +       int (*setattr_raw) (struct inode *, struct iattr *);
1751         int (*getattr) (struct dentry *, struct iattr *);
1752         int (*setxattr) (struct dentry *, const char *, void *, size_t, int);
1753         ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t);
1754 @@ -1092,10 +1111,14 @@
1755  
1756  asmlinkage long sys_open(const char *, int, int);
1757  asmlinkage long sys_close(unsigned int);       /* yes, it's really unsigned */
1758 -extern int do_truncate(struct dentry *, loff_t start);
1759 +extern int do_truncate(struct dentry *, loff_t start, int called_from_open);
1760  
1761  extern struct file *filp_open(const char *, int, int);
1762  extern struct file * dentry_open(struct dentry *, struct vfsmount *, int);
1763 +extern int open_namei_it(const char *filename, int namei_flags, int mode,
1764 +                        struct nameidata *nd, struct lookup_intent *it);
1765 +extern struct file *dentry_open_it(struct dentry *dentry, struct vfsmount *mnt,
1766 +                           int flags, struct lookup_intent *it);
1767  extern int filp_close(struct file *, fl_owner_t id);
1768  extern char * getname(const char *);
1769  
1770 @@ -1386,6 +1409,7 @@
1771  extern loff_t default_llseek(struct file *file, loff_t offset, int origin);
1772  
1773  extern int FASTCALL(__user_walk(const char *, unsigned, struct nameidata *));
1774 +extern int FASTCALL(__user_walk_it(const char *, unsigned, struct nameidata *, struct lookup_intent *it));
1775  extern int FASTCALL(path_init(const char *, unsigned, struct nameidata *));
1776  extern int FASTCALL(path_walk(const char *, struct nameidata *));
1777  extern int FASTCALL(path_lookup(const char *, unsigned, struct nameidata *));
1778 @@ -1397,6 +1421,8 @@
1779  extern struct dentry * lookup_hash(struct qstr *, struct dentry *);
1780  #define user_path_walk(name,nd)         __user_walk(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, nd)
1781  #define user_path_walk_link(name,nd) __user_walk(name, LOOKUP_POSITIVE, nd)
1782 +#define user_path_walk_it(name,nd,it)  __user_walk_it(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, nd, it)
1783 +#define user_path_walk_link_it(name,nd,it) __user_walk_it(name, LOOKUP_POSITIVE, nd, it)
1784  
1785  extern void inode_init_once(struct inode *);
1786  extern void iput(struct inode *);
1787 @@ -1504,6 +1530,8 @@
1788  
1789  extern int vfs_readlink(struct dentry *, char *, int, const char *);
1790  extern int vfs_follow_link(struct nameidata *, const char *);
1791 +extern int vfs_follow_link_it(struct nameidata *, const char *,
1792 +                             struct lookup_intent *it);
1793  extern int page_readlink(struct dentry *, char *, int);
1794  extern int page_follow_link(struct dentry *, struct nameidata *);
1795  extern struct inode_operations page_symlink_inode_operations;
1796 Index: linux-2.4.20/include/linux/fs_struct.h
1797 ===================================================================
1798 --- linux-2.4.20.orig/include/linux/fs_struct.h Wed Mar 17 13:57:02 2004
1799 +++ linux-2.4.20/include/linux/fs_struct.h      Wed Mar 17 13:57:11 2004
1800 @@ -37,10 +37,12 @@
1801         write_lock(&fs->lock);
1802         old_root = fs->root;
1803         old_rootmnt = fs->rootmnt;
1804 +       PIN(dentry, mnt, 1);
1805         fs->rootmnt = mntget(mnt);
1806         fs->root = dget(dentry);
1807         write_unlock(&fs->lock);
1808         if (old_root) {
1809 +               UNPIN(old_root, old_rootmnt, 1);
1810                 dput(old_root);
1811                 mntput(old_rootmnt);
1812         }
1813 @@ -60,10 +62,12 @@
1814         write_lock(&fs->lock);
1815         old_pwd = fs->pwd;
1816         old_pwdmnt = fs->pwdmnt;
1817 +       PIN(dentry, mnt, 0);
1818         fs->pwdmnt = mntget(mnt);
1819         fs->pwd = dget(dentry);
1820         write_unlock(&fs->lock);
1821         if (old_pwd) {
1822 +               UNPIN(old_pwd, old_pwdmnt, 0);
1823                 dput(old_pwd);
1824                 mntput(old_pwdmnt);
1825         }
1826 Index: linux-2.4.20/kernel/ksyms.c
1827 ===================================================================
1828 --- linux-2.4.20.orig/kernel/ksyms.c    Wed Mar 17 13:57:11 2004
1829 +++ linux-2.4.20/kernel/ksyms.c Wed Mar 17 13:57:11 2004
1830 @@ -297,6 +297,7 @@
1831  EXPORT_SYMBOL(set_page_dirty);
1832  EXPORT_SYMBOL(vfs_readlink);
1833  EXPORT_SYMBOL(vfs_follow_link);
1834 +EXPORT_SYMBOL(vfs_follow_link_it);
1835  EXPORT_SYMBOL(page_readlink);
1836  EXPORT_SYMBOL(page_follow_link);
1837  EXPORT_SYMBOL(page_symlink_inode_operations);
1838 Index: linux-2.4.20/kernel/fork.c
1839 ===================================================================
1840 --- linux-2.4.20.orig/kernel/fork.c     Wed Mar 17 13:57:05 2004
1841 +++ linux-2.4.20/kernel/fork.c  Wed Mar 17 13:57:11 2004
1842 @@ -440,10 +440,13 @@
1843                 fs->umask = old->umask;
1844                 read_lock(&old->lock);
1845                 fs->rootmnt = mntget(old->rootmnt);
1846 +               PIN(old->pwd, old->pwdmnt, 0);
1847 +               PIN(old->root, old->rootmnt, 1);
1848                 fs->root = dget(old->root);
1849                 fs->pwdmnt = mntget(old->pwdmnt);
1850                 fs->pwd = dget(old->pwd);
1851                 if (old->altroot) {
1852 +                       PIN(old->altroot, old->altrootmnt, 1);
1853                         fs->altrootmnt = mntget(old->altrootmnt);
1854                         fs->altroot = dget(old->altroot);
1855                 } else {
1856 Index: linux-2.4.20/kernel/exit.c
1857 ===================================================================
1858 --- linux-2.4.20.orig/kernel/exit.c     Wed Mar 17 13:57:05 2004
1859 +++ linux-2.4.20/kernel/exit.c  Wed Mar 17 13:57:11 2004
1860 @@ -345,11 +345,14 @@
1861  {
1862         /* No need to hold fs->lock if we are killing it */
1863         if (atomic_dec_and_test(&fs->count)) {
1864 +               UNPIN(fs->pwd, fs->pwdmnt, 0);
1865 +               UNPIN(fs->root, fs->rootmnt, 1);
1866                 dput(fs->root);
1867                 mntput(fs->rootmnt);
1868                 dput(fs->pwd);
1869                 mntput(fs->pwdmnt);
1870                 if (fs->altroot) {
1871 +                       UNPIN(fs->altroot, fs->altrootmnt, 1);
1872                         dput(fs->altroot);
1873                         mntput(fs->altrootmnt);
1874                 }