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