Whamcloud - gitweb
land b1_5 onto HEAD
[fs/lustre-release.git] / lustre / kernel_patches / patches / nfs_export_kernel-2.4.22.patch
1 Index: linux-2.4.22-vanilla/fs/Makefile
2 ===================================================================
3 --- linux-2.4.22-vanilla.orig/fs/Makefile       2003-11-03 23:41:40.000000000 +0300
4 +++ linux-2.4.22-vanilla/fs/Makefile    2003-11-03 23:45:07.000000000 +0300
5 @@ -7,7 +7,8 @@
6  
7  O_TARGET := fs.o
8  
9 -export-objs := filesystems.o open.o dcache.o buffer.o dquot.o inode.o
10 +export-objs := filesystems.o open.o dcache.o buffer.o dquot.o inode.o \
11 +               namei.o file_table.o
12  mod-subdirs := nls
13  
14  obj-y :=       open.o read_write.o devices.o file_table.o buffer.o \
15 Index: linux-2.4.22-vanilla/fs/file_table.c
16 ===================================================================
17 --- linux-2.4.22-vanilla.orig/fs/file_table.c   2003-05-16 05:29:12.000000000 +0400
18 +++ linux-2.4.22-vanilla/fs/file_table.c        2003-11-03 23:44:38.000000000 +0300
19 @@ -82,7 +82,8 @@
20   * and call the open function (if any).  The caller must verify that
21   * inode->i_fop is not NULL.
22   */
23 -int init_private_file(struct file *filp, struct dentry *dentry, int mode)
24 +int init_private_file_it(struct file *filp, struct dentry *dentry, int mode,
25 +                        struct lookup_intent *it)
26  {
27         memset(filp, 0, sizeof(*filp));
28         filp->f_mode   = mode;
29 @@ -90,12 +91,20 @@
30         filp->f_dentry = dentry;
31         filp->f_uid    = current->fsuid;
32         filp->f_gid    = current->fsgid;
33 +       if (it)
34 +               filp->f_it = it;
35         filp->f_op     = dentry->d_inode->i_fop;
36         if (filp->f_op->open)
37                 return filp->f_op->open(dentry->d_inode, filp);
38         else
39                 return 0;
40  }
41 +EXPORT_SYMBOL(init_private_file_it);
42 +
43 +int init_private_file(struct file *filp, struct dentry *dentry, int mode)
44 +{
45 +       return init_private_file_it(filp, dentry, mode, NULL);
46 +}
47  
48  void fput(struct file * file)
49  {
50 Index: linux-2.4.22-vanilla/fs/inode.c
51 ===================================================================
52 --- linux-2.4.22-vanilla.orig/fs/inode.c        2003-11-03 23:25:33.000000000 +0300
53 +++ linux-2.4.22-vanilla/fs/inode.c     2003-11-03 23:44:38.000000000 +0300
54 @@ -970,9 +970,10 @@
55  }
56  
57  
58 -struct inode *iget4(struct super_block *sb, unsigned long ino, find_inode_t find_actor, void *opaque)
59 +static inline struct inode *ifind(struct super_block *sb, unsigned long ino,
60 +                                 struct list_head *head,
61 +                                 find_inode_t find_actor, void *opaque)
62  {
63 -       struct list_head * head = inode_hashtable + hash(sb,ino);
64         struct inode * inode;
65  
66         spin_lock(&inode_lock);
67 @@ -985,6 +986,24 @@
68         }
69         spin_unlock(&inode_lock);
70  
71 +       return NULL;
72 +}
73 +
74 +struct inode *ilookup4(struct super_block *sb, unsigned long ino,
75 +                      find_inode_t find_actor, void *opaque)
76 +{
77 +       struct list_head * head = inode_hashtable + hash(sb,ino);
78 +       return ifind(sb, ino, head, find_actor, opaque);
79 +}
80 +
81 +struct inode *iget4(struct super_block *sb, unsigned long ino,
82 +                   find_inode_t find_actor, void *opaque)
83 +{
84 +       struct list_head * head = inode_hashtable + hash(sb,ino);
85 +       struct inode *inode = ifind(sb, ino, head, find_actor, opaque);
86 +       if (inode)
87 +               return inode;
88 +
89         /*
90          * get_new_inode() will do the right thing, re-trying the search
91          * in case it had to block at any point.
92 Index: linux-2.4.22-vanilla/fs/namei.c
93 ===================================================================
94 --- linux-2.4.22-vanilla.orig/fs/namei.c        2003-11-03 23:22:22.000000000 +0300
95 +++ linux-2.4.22-vanilla/fs/namei.c     2003-11-03 23:44:38.000000000 +0300
96 @@ -22,6 +22,7 @@
97  #include <linux/dnotify.h>
98  #include <linux/smp_lock.h>
99  #include <linux/personality.h>
100 +#include <linux/module.h>
101  
102  #include <asm/namei.h>
103  #include <asm/uaccess.h>
104 @@ -100,6 +101,7 @@
105                 it->it_op_release(it);
106  
107  }
108 +EXPORT_SYMBOL(intent_release);
109  
110  /* In order to reduce some races, while at the same time doing additional
111   * checking and hopefully speeding things up, we copy filenames to the
112 @@ -902,7 +904,8 @@
113  
114  
115  /* SMP-safe */
116 -struct dentry * lookup_one_len(const char * name, struct dentry * base, int len)
117 +struct dentry * lookup_one_len_it(const char * name, struct dentry * base,
118 +                                 int len, struct lookup_intent *it)
119  {
120         unsigned long hash;
121         struct qstr this;
122 @@ -922,11 +925,16 @@
123         }
124         this.hash = end_name_hash(hash);
125  
126 -       return lookup_hash_it(&this, base, NULL);
127 +       return lookup_hash_it(&this, base, it);
128  access:
129         return ERR_PTR(-EACCES);
130  }
131  
132 +struct dentry * lookup_one_len(const char * name, struct dentry * base, int len)
133 +{
134 +       return lookup_one_len_it(name, base, len, NULL);
135 +}
136 +
137  /*
138   *     namei()
139   *
140 Index: linux-2.4.22-vanilla/fs/nfsd/export.c
141 ===================================================================
142 --- linux-2.4.22-vanilla.orig/fs/nfsd/export.c  2003-11-03 23:22:11.000000000 +0300
143 +++ linux-2.4.22-vanilla/fs/nfsd/export.c       2003-11-03 23:44:38.000000000 +0300
144 @@ -223,6 +223,11 @@
145         inode = nd.dentry->d_inode;
146         dev = inode->i_dev;
147         ino = inode->i_ino;
148 +       if ((inode->i_sb->s_type->fs_flags & FS_NFSEXP_FSID) &&
149 +           !(nxp->ex_flags & NFSEXP_FSID)) {
150 +               nxp->ex_dev = inode->i_sb->s_dev;
151 +               nxp->ex_flags |= NFSEXP_FSID;
152 +       }
153         err = -EINVAL;
154  
155         exp = exp_get(clp, dev, ino);
156 Index: linux-2.4.22-vanilla/fs/nfsd/nfsfh.c
157 ===================================================================
158 --- linux-2.4.22-vanilla.orig/fs/nfsd/nfsfh.c   2003-11-03 23:22:11.000000000 +0300
159 +++ linux-2.4.22-vanilla/fs/nfsd/nfsfh.c        2003-11-03 23:44:38.000000000 +0300
160 @@ -36,6 +36,13 @@
161         int sequence;           /* sequence counter */
162  };
163  
164 +static struct dentry *lookup_it(struct inode *inode, struct dentry * dentry)
165 +{
166 +       if (inode->i_op->lookup_it)
167 +               return inode->i_op->lookup_it(inode, dentry, NULL, 0);
168 +       return inode->i_op->lookup(inode, dentry);
169 +}
170 +
171  /*
172   * A rather strange filldir function to capture
173   * the name matching the specified inode number.
174 @@ -75,6 +84,8 @@
175         int error;
176         struct file file;
177         struct nfsd_getdents_callback buffer;
178 +       struct lookup_intent it;
179 +       struct file *filp = NULL;
180  
181         error = -ENOTDIR;
182         if (!dir || !S_ISDIR(dir->i_mode))
183 @@ -85,9 +96,37 @@
184         /*
185          * Open the directory ...
186          */
187 -       error = init_private_file(&file, dentry, FMODE_READ);
188 -       if (error)
189 +       if (dentry->d_op && dentry->d_op->d_revalidate_it) {
190 +               if ((dentry->d_flags & DCACHE_NFSD_DISCONNECTED) &&
191 +                   (dentry->d_parent == dentry) ) {
192 +                       it.it_op_release = NULL;
193 +                       /*
194 +                        * XXX Temporary Hack: Simulate init_private_file without
195 +                        * f_op->open for disconnected dentry as we don't have
196 +                        * actual dentry->d_name to revalidate in revalidate_it()
197 +                        */
198 +                       filp = &file;
199 +                       memset(filp, 0, sizeof(*filp));
200 +                       filp->f_mode   = FMODE_READ;
201 +                       atomic_set(&filp->f_count, 1);
202 +                       filp->f_dentry = dentry;
203 +                       filp->f_uid = current->fsuid;
204 +                       filp->f_gid = current->fsgid;
205 +                       filp->f_op = dentry->d_inode->i_fop;
206 +                       error = 0;
207 +               } else {
208 +                       intent_init(&it, IT_OPEN, FMODE_READ);
209 +                       error = revalidate_it(dentry, &it);
210 +                       if (error)
211 +                               goto out;
212 +                       error = init_private_file_it(&file, dentry, FMODE_READ, &it);
213 +               }
214 +       } else {
215 +               error = init_private_file_it(&file, dentry, FMODE_READ, NULL);
216 +       }
217 +       if (error)
218                 goto out;
219 +
220         error = -EINVAL;
221         if (!file.f_op->readdir)
222                 goto out_close;
223 @@ -113,9 +152,12 @@
224         }
225  
226  out_close:
227 -       if (file.f_op->release)
228 +       if (file.f_op->release && !filp)
229                 file.f_op->release(dir, &file);
230  out:
231 +       if (dentry->d_op && dentry->d_op->d_revalidate_it &&
232 +           it.it_op_release && !filp)
233 +               intent_release(&it);
234         return error;
235  }
236  
237 @@ -274,7 +317,7 @@
238          * it is well connected.  But nobody returns different dentrys do they?
239          */
240         down(&child->d_inode->i_sem);
241 -       pdentry = child->d_inode->i_op->lookup(child->d_inode, tdentry);
242 +       pdentry = lookup_it(child->d_inode, tdentry);
243         up(&child->d_inode->i_sem);
244         d_drop(tdentry); /* we never want ".." hashed */
245         if (!pdentry && tdentry->d_inode == NULL) {
246 @@ -306,6 +349,8 @@
247                                 igrab(tdentry->d_inode);
248                                 pdentry->d_flags |= DCACHE_NFSD_DISCONNECTED;
249                         }
250 +                       if (child->d_op && child->d_op->d_revalidate_it)
251 +                               pdentry->d_op = child->d_op;
252                 }
253                 if (pdentry == NULL)
254                         pdentry = ERR_PTR(-ENOMEM);
255 @@ -463,6 +508,8 @@
256                 struct dentry *pdentry;
257                 struct inode *parent;
258  
259 +               if (result->d_op && result->d_op->d_revalidate_it)
260 +                       dentry->d_op = result->d_op;
261                 pdentry = nfsd_findparent(dentry);
262                 err = PTR_ERR(pdentry);
263                 if (IS_ERR(pdentry))
264 @@ -669,6 +716,10 @@
265  
266         inode = dentry->d_inode;
267  
268 +       /* cache coherency for non-device filesystems */
269 +       if (inode->i_op && inode->i_op->revalidate_it)
270 +               inode->i_op->revalidate_it(dentry, NULL);
271 +
272         /* Type check. The correct error return for type mismatches
273          * does not seem to be generally agreed upon. SunOS seems to
274          * use EISDIR if file isn't S_IFREG; a comment in the NFSv3
275 @@ -902,8 +954,9 @@
276                 dentry->d_parent->d_name.name, dentry->d_name.name);
277         goto out;
278  out_uptodate:
279 -       printk(KERN_ERR "fh_update: %s/%s already up-to-date!\n",
280 -               dentry->d_parent->d_name.name, dentry->d_name.name);
281 +       if (!dentry->d_parent->d_inode->i_op->mkdir_raw)
282 +               printk(KERN_ERR "fh_update: %s/%s already up-to-date!\n",
283 +                     dentry->d_parent->d_name.name, dentry->d_name.name);
284         goto out;
285  }
286  
287 Index: linux-2.4.22-vanilla/fs/nfsd/vfs.c
288 ===================================================================
289 --- linux-2.4.22-vanilla.orig/fs/nfsd/vfs.c     2003-11-03 23:22:11.000000000 +0300
290 +++ linux-2.4.22-vanilla/fs/nfsd/vfs.c  2003-11-03 23:47:41.000000000 +0300
291 @@ -77,6 +77,127 @@
292  static struct raparms *                raparml;
293  static struct raparms *                raparm_cache;
294  
295 +static int link_raw(struct dentry *dold, struct dentry *ddir,
296 +                   struct dentry *dnew)
297 +{
298 +       int err;
299 +
300 +       struct nameidata old_nd = { .dentry = dold };
301 +       struct nameidata nd = { .dentry = ddir, .last = dnew->d_name };
302 +       struct inode_operations *op = nd.dentry->d_inode->i_op;
303 +       err = op->link_raw(&old_nd, &nd);
304 +       igrab(dold->d_inode);
305 +       d_instantiate(dnew, dold->d_inode);
306 +       if (dold->d_inode->i_op && dold->d_inode->i_op->revalidate_it)
307 +               dold->d_inode->i_op->revalidate_it(dnew, NULL);
308 +
309 +       return err;
310 +}
311 +
312 +static int unlink_raw(struct dentry *dentry, char *fname, int flen,
313 +                     struct dentry *rdentry)
314 +{
315 +       int err;
316 +       struct qstr last = { .name = fname, .len = flen };
317 +       struct nameidata nd = { .dentry = dentry, .last = last };
318 +       struct inode_operations *op = nd.dentry->d_inode->i_op;
319 +       err = op->unlink_raw(&nd);
320 +       if (!err)
321 +               d_delete(rdentry);
322 +
323 +       return err;
324 +}
325 +
326 +static int rmdir_raw(struct dentry *dentry, char *fname, int flen,
327 +                    struct dentry *rdentry)
328 +{
329 +       int err;
330 +       struct qstr last = { .name = fname, .len = flen };
331 +       struct nameidata nd = { .dentry = dentry, .last = last };
332 +       struct inode_operations *op = nd.dentry->d_inode->i_op;
333 +       err = op->rmdir_raw(&nd);
334 +       if (!err) {
335 +               rdentry->d_inode->i_flags |= S_DEAD;
336 +               d_delete(rdentry);
337 +       }
338 +
339 +       return err;
340 +}
341 +
342 +static int symlink_raw(struct dentry *dentry, char *fname, int flen,
343 +                      char *path)
344 +{
345 +       int err;
346 +       struct qstr last = { .name = fname, .len = flen };
347 +       struct nameidata nd = { .dentry = dentry, .last = last };
348 +       struct inode_operations *op = nd.dentry->d_inode->i_op;
349 +       err = op->symlink_raw(&nd, path);
350 +
351 +       return err;
352 +}
353 +
354 +static int mkdir_raw(struct dentry *dentry, char *fname, int flen, int mode)
355 +{
356 +       int err;
357 +       struct qstr last = { .name = fname, .len = flen };
358 +       struct nameidata nd = { .dentry = dentry, .last = last };
359 +       struct inode_operations *op = nd.dentry->d_inode->i_op;
360 +       err = op->mkdir_raw(&nd, mode);
361 +
362 +       return err;
363 +}
364 +
365 +static int mknod_raw(struct dentry *dentry, char *fname, int flen, int mode,
366 +                    dev_t dev)
367 +{
368 +       int err;
369 +       struct qstr last = { .name = fname, .len = flen };
370 +       struct nameidata nd = { .dentry = dentry, .last = last };
371 +       struct inode_operations *op = nd.dentry->d_inode->i_op;
372 +       err = op->mknod_raw(&nd, mode, dev);
373 +
374 +       return err;
375 +}
376 +
377 +static int rename_raw(struct dentry *fdentry, struct dentry *tdentry,
378 +                     struct dentry *odentry, struct dentry *ndentry)
379 +{
380 +       int err;
381 +
382 +       struct nameidata old_nd = { .dentry = fdentry, .last = odentry->d_name};
383 +       struct nameidata new_nd = { .dentry = tdentry, .last = ndentry->d_name};
384 +       struct inode_operations *op = old_nd.dentry->d_inode->i_op;
385 +       err = op->rename_raw(&old_nd, &new_nd);
386 +       d_move(odentry, ndentry);
387 +
388 +       return err;
389 +}
390 +
391 +static int setattr_raw(struct inode *inode, struct iattr *iap)
392 +{
393 +       int err;
394 +
395 +       iap->ia_valid |= ATTR_RAW;
396 +       err = inode->i_op->setattr_raw(inode, iap);
397 +
398 +       return err;
399 +}
400 +
401 +int revalidate_it(struct dentry *dentry, struct lookup_intent *it)
402 +{
403 +       int err = 0;
404 +
405 +       if (dentry && dentry->d_op && dentry->d_op->d_revalidate_it) {
406 +               if (!dentry->d_op->d_revalidate_it(dentry, 0, it) &&
407 +                       !d_invalidate(dentry)) {
408 +                       err = -EINVAL;
409 +                       return err;
410 +               }
411 +       }
412 +
413 +       return err;
414 +}
415 +
416  /*
417   * Look up one component of a pathname.
418   * N.B. After this call _both_ fhp and resfh need an fh_put
419 @@ -302,7 +424,10 @@
420         }
421         err = nfserr_notsync;
422         if (!check_guard || guardtime == inode->i_ctime) {
423 -               err = notify_change(dentry, iap);
424 +               if (dentry->d_inode->i_op && dentry->d_inode->i_op->setattr_raw)
425 +                       err = setattr_raw(dentry->d_inode, iap);
426 +               else
427 +                       err = notify_change(dentry, iap);
428                 err = nfserrno(err);
429         }
430         if (size_change) {
431 @@ -429,6 +554,7 @@
432  {
433         struct dentry   *dentry;
434         struct inode    *inode;
435 +       struct lookup_intent it;
436         int             err;
437  
438         /* If we get here, then the client has already done an "open", and (hopefully)
439 @@ -475,6 +601,18 @@
440                 filp->f_mode  = FMODE_READ;
441         }
442  
443 +#ifndef O_OWNER_OVERRIDE
444 +#define O_OWNER_OVERRIDE 0200000000
445 +#endif
446 +       intent_init(&it, IT_OPEN, (filp->f_flags & ~O_ACCMODE) | filp->f_mode |
447 +                   O_OWNER_OVERRIDE);
448 +
449 +       err = revalidate_it(dentry, &it);
450 +       if (err)
451 +               goto out_nfserr;
452 +
453 +       filp->f_it = &it;
454 +
455         err = 0;
456         if (filp->f_op && filp->f_op->open) {
457                 err = filp->f_op->open(inode, filp);
458 @@ -489,6 +623,9 @@
459                 }
460         }
461  out_nfserr:
462 +       if (it.it_op_release)
463 +               intent_release(&it);
464 +
465         if (err)
466                 err = nfserrno(err);
467  out:
468 @@ -820,7 +958,7 @@
469  {
470         struct dentry   *dentry, *dchild;
471         struct inode    *dirp;
472 -       int             err;
473 +       int             err, error = -EOPNOTSUPP;
474  
475         err = nfserr_perm;
476         if (!flen)
477 @@ -836,20 +974,47 @@
478         dentry = fhp->fh_dentry;
479         dirp = dentry->d_inode;
480  
481 +       switch (type) {
482 +       case S_IFDIR:
483 +               if (dirp->i_op->mkdir_raw)
484 +                       error = mkdir_raw(dentry, fname, flen, iap->ia_mode);
485 +               break;
486 +       case S_IFCHR:
487 +       case S_IFBLK:
488 +       case S_IFIFO:
489 +       case S_IFSOCK:
490 +       case S_IFREG:
491 +               if (dirp->i_op->mknod_raw) {
492 +                       if (type == S_IFREG)
493 +                               rdev = 0;
494 +                       error = mknod_raw(dentry, fname,flen,iap->ia_mode,rdev);
495 +               }
496 +               break;
497 +       default:
498 +               printk("nfsd: bad file type %o in nfsd_create\n", type);
499 +       }
500 +       if (error && error != -EOPNOTSUPP) {
501 +               err = error;
502 +               goto out_nfserr;
503 +       }
504 +
505         err = nfserr_notdir;
506 -       if(!dirp->i_op || !dirp->i_op->lookup)
507 +       if (!dirp->i_op || !(dirp->i_op->lookup || dirp->i_op->lookup_it))
508                 goto out;
509         /*
510          * Check whether the response file handle has been verified yet.
511          * If it has, the parent directory should already be locked.
512          */
513 -       if (!resfhp->fh_dentry) {
514 -               /* called from nfsd_proc_mkdir, or possibly nfsd3_proc_create */
515 -               fh_lock(fhp);
516 +       if (!resfhp->fh_dentry || dirp->i_op->lookup_it) {
517 +               /* called from nfsd_proc_mkdir, or possibly nfsd3_proc_create
518 +                * and nfsd_proc_create in case of lustre */
519 +               if (!resfhp->fh_dentry)
520 +                       fh_lock(fhp);
521                 dchild = lookup_one_len(fname, dentry, flen);
522                 err = PTR_ERR(dchild);
523                 if (IS_ERR(dchild))
524                         goto out_nfserr;
525 +               resfhp->fh_dentry = NULL;
526                 err = fh_compose(resfhp, fhp->fh_export, dchild, fhp);
527                 if (err)
528                         goto out;
529 @@ -870,10 +1032,12 @@
530          * Make sure the child dentry is still negative ...
531          */
532         err = nfserr_exist;
533 -       if (dchild->d_inode) {
534 -               dprintk("nfsd_create: dentry %s/%s not negative!\n",
535 -                       dentry->d_name.name, dchild->d_name.name);
536 -               goto out; 
537 +       if (error == -EOPNOTSUPP) {
538 +               if (dchild->d_inode) {
539 +                       dprintk("nfsd_create: dentry %s/%s not negative!\n",
540 +                               dentry->d_name.name, dchild->d_name.name);
541 +                       goto out;
542 +               }
543         }
544  
545         if (!(iap->ia_valid & ATTR_MODE))
546 @@ -886,16 +1050,19 @@
547         err = nfserr_perm;
548         switch (type) {
549         case S_IFREG:
550 -               err = vfs_create(dirp, dchild, iap->ia_mode);
551 +               if (error == -EOPNOTSUPP)
552 +                       err = vfs_create(dirp, dchild, iap->ia_mode);
553                 break;
554         case S_IFDIR:
555 -               err = vfs_mkdir(dirp, dchild, iap->ia_mode);
556 +               if (error == -EOPNOTSUPP)
557 +                       err = vfs_mkdir(dirp, dchild, iap->ia_mode);
558                 break;
559         case S_IFCHR:
560         case S_IFBLK:
561         case S_IFIFO:
562         case S_IFSOCK:
563 -               err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev);
564 +               if (error == -EOPNOTSUPP)
565 +                       err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev);
566                 break;
567         default:
568                 printk("nfsd: bad file type %o in nfsd_create\n", type);
569 @@ -964,7 +1131,13 @@
570         /* Get all the sanity checks out of the way before
571          * we lock the parent. */
572         err = nfserr_notdir;
573 -       if(!dirp->i_op || !dirp->i_op->lookup)
574 +       if (dirp->i_op->mknod_raw) {
575 +               err = mknod_raw(dentry, fname, flen, iap->ia_mode, 0);
576 +               if (err && err != -EOPNOTSUPP)
577 +                       goto out_nfserr;
578 +       }
579 +
580 +       if (!dirp->i_op || !(dirp->i_op->lookup || dirp->i_op->lookup_it))
581                 goto out;
582         fh_lock(fhp);
583  
584 @@ -1015,6 +1188,8 @@
585                 case NFS3_CREATE_GUARDED:
586                         err = nfserr_exist;
587                 }
588 +               if (dirp->i_op->mknod_raw)
589 +                       err = 0;
590                 goto out;
591         }
592  
593 @@ -1121,7 +1296,7 @@
594                                 struct iattr *iap)
595  {
596         struct dentry   *dentry, *dnew;
597 -       int             err, cerr;
598 +       int             err, cerr, error = -EOPNOTSUPP;
599  
600         err = nfserr_noent;
601         if (!flen || !plen)
602 @@ -1135,12 +1310,18 @@
603                 goto out;
604         fh_lock(fhp);
605         dentry = fhp->fh_dentry;
606 +
607 +       if (dentry->d_inode->i_op->symlink_raw)
608 +               error = symlink_raw(dentry, fname, flen, path);
609 +
610         dnew = lookup_one_len(fname, dentry, flen);
611         err = PTR_ERR(dnew);
612         if (IS_ERR(dnew))
613                 goto out_nfserr;
614  
615 -       err = vfs_symlink(dentry->d_inode, dnew, path);
616 +       err = error;
617 +       if (err == -EOPNOTSUPP || !dentry->d_inode->i_op->symlink_raw)
618 +               err = vfs_symlink(dentry->d_inode, dnew, path);
619         if (!err) {
620                 if (EX_ISSYNC(fhp->fh_export))
621                         nfsd_sync_dir(dentry);
622 @@ -1150,7 +1331,10 @@
623                                 iap->ia_valid |= ATTR_CTIME;
624                                 iap->ia_mode = (iap->ia_mode&S_IALLUGO)
625                                         | S_IFLNK;
626 -                               err = notify_change(dnew, iap);
627 +                               if (dnew->d_inode->i_op && dnew->d_inode->i_op->setattr_raw)
628 +                                       err = setattr_raw(dnew->d_inode, iap);
629 +                               else
630 +                                       err = notify_change(dnew, iap);
631                                 if (err)
632                                         err = nfserrno(err);
633                                 else if (EX_ISSYNC(fhp->fh_export))
634 @@ -1210,7 +1394,10 @@
635         dold = tfhp->fh_dentry;
636         dest = dold->d_inode;
637  
638 -       err = vfs_link(dold, dirp, dnew);
639 +       if (dirp->i_op->link_raw)
640 +               err = link_raw(dold, ddir, dnew);
641 +       else
642 +               err = vfs_link(dold, dirp, dnew);
643         if (!err) {
644                 if (EX_ISSYNC(ffhp->fh_export)) {
645                         nfsd_sync_dir(ddir);
646 @@ -1295,7 +1482,10 @@
647                         err = nfserr_perm;
648         } else
649  #endif
650 -       err = vfs_rename(fdir, odentry, tdir, ndentry);
651 +       if (fdir->i_op->rename_raw)
652 +               err = rename_raw(fdentry, tdentry, odentry, ndentry);
653 +       else
654 +               err = vfs_rename(fdir, odentry, tdir, ndentry);
655         if (!err && EX_ISSYNC(tfhp->fh_export)) {
656                 nfsd_sync_dir(tdentry);
657                 nfsd_sync_dir(fdentry);
658 @@ -1316,7 +1506,7 @@
659         fill_post_wcc(tfhp);
660         double_up(&tdir->i_sem, &fdir->i_sem);
661         ffhp->fh_locked = tfhp->fh_locked = 0;
662 -       
663 +
664  out:
665         return err;
666  }
667 @@ -1362,9 +1552,15 @@
668                         err = nfserr_perm;
669                 } else
670  #endif
671 -               err = vfs_unlink(dirp, rdentry);
672 +               if (dirp->i_op->unlink_raw)
673 +                       err = unlink_raw(dentry, fname, flen, rdentry);
674 +               else
675 +                       err = vfs_unlink(dirp, rdentry);
676         } else { /* It's RMDIR */
677 -               err = vfs_rmdir(dirp, rdentry);
678 +               if (dirp->i_op->rmdir_raw)
679 +                       err = rmdir_raw(dentry, fname, flen, rdentry);
680 +               else
681 +                       err = vfs_rmdir(dirp, rdentry);
682         }
683  
684         dput(rdentry);
685 Index: linux-2.4.22-vanilla/include/linux/fs.h
686 ===================================================================
687 --- linux-2.4.22-vanilla.orig/include/linux/fs.h        2003-11-03 23:41:40.000000000 +0300
688 +++ linux-2.4.22-vanilla/include/linux/fs.h     2003-11-03 23:44:38.000000000 +0300
689 @@ -93,6 +93,8 @@
690  #define FS_SINGLE      8 /* Filesystem that can have only one superblock */
691  #define FS_NOMOUNT     16 /* Never mount from userland */
692  #define FS_LITTER      32 /* Keeps the tree in dcache */
693 +#define FS_NFSEXP_FSID 64 /* Use file system specific fsid for
694 +                           * exporting non device filesystems. */
695  #define FS_ODD_RENAME  32768   /* Temporary stuff; will go away as soon
696                                   * as nfs_rename() will be cleaned up
697                                   */
698 @@ -1115,6 +1118,9 @@
699                          struct nameidata *nd, struct lookup_intent *it);
700  extern struct file *dentry_open_it(struct dentry *dentry, struct vfsmount *mnt,
701                             int flags, struct lookup_intent *it);
702 +extern int revalidate_it(struct dentry *dentry, struct lookup_intent *it);
703 +extern int init_private_file_it(struct file *, struct dentry *dentry, int mode,
704 +                               struct lookup_intent *it);
705  extern int filp_close(struct file *, fl_owner_t id);
706  extern char * getname(const char *);
707  
708 @@ -1411,6 +1417,8 @@
709  extern int follow_down(struct vfsmount **, struct dentry **);
710  extern int follow_up(struct vfsmount **, struct dentry **);
711  extern struct dentry * lookup_one_len(const char *, struct dentry *, int);
712 +extern struct dentry * lookup_one_len_it(const char *, struct dentry *, int,
713 +                                        struct lookup_intent *);
714  extern struct dentry * lookup_hash(struct qstr *, struct dentry *);
715  #define user_path_walk(name,nd)         __user_walk(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, nd)
716  #define user_path_walk_link(name,nd) __user_walk(name, LOOKUP_POSITIVE, nd)
717 @@ -1425,6 +1433,8 @@
718  
719  typedef int (*find_inode_t)(struct inode *, unsigned long, void *);
720  extern struct inode * iget4(struct super_block *, unsigned long, find_inode_t, void *);
721 +extern struct inode * ilookup4(struct super_block *, unsigned long,
722 +                              find_inode_t, void *);
723  static inline struct inode *iget(struct super_block *sb, unsigned long ino)
724  {
725         return iget4(sb, ino, NULL, NULL);
726 Index: linux-2.4.22-vanilla/kernel/ksyms.c
727 ===================================================================
728 --- linux-2.4.22-vanilla.orig/kernel/ksyms.c    2003-11-03 23:41:40.000000000 +0300
729 +++ linux-2.4.22-vanilla/kernel/ksyms.c 2003-11-03 23:44:38.000000000 +0300
730 @@ -149,6 +149,7 @@
731  EXPORT_SYMBOL(igrab);
732  EXPORT_SYMBOL(iunique);
733  EXPORT_SYMBOL(iget4);
734 +EXPORT_SYMBOL(ilookup4);
735  EXPORT_SYMBOL(iput);
736  EXPORT_SYMBOL(inode_init_once);
737  EXPORT_SYMBOL(force_delete);
738 @@ -160,6 +161,7 @@
739  EXPORT_SYMBOL(path_release);
740  EXPORT_SYMBOL(__user_walk);
741  EXPORT_SYMBOL(lookup_one_len);
742 +EXPORT_SYMBOL(lookup_one_len_it);
743  EXPORT_SYMBOL(lookup_hash);
744  EXPORT_SYMBOL(sys_close);
745  EXPORT_SYMBOL(dcache_lock);