Whamcloud - gitweb
Branch HEAD
[fs/lustre-release.git] / lustre / kernel_patches / patches / nfs_export_kernel-2.4.29.patch
1 Index: linux-2.4.29/fs/Makefile
2 ===================================================================
3 --- linux-2.4.29.orig/fs/Makefile       2005-05-03 18:16:44.000000000 +0300
4 +++ linux-2.4.29/fs/Makefile    2005-05-03 18:46:09.301144016 +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.29/fs/file_table.c
16 ===================================================================
17 --- linux-2.4.29.orig/fs/file_table.c   2005-05-03 16:28:21.000000000 +0300
18 +++ linux-2.4.29/fs/file_table.c        2005-05-03 18:46:09.303143712 +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 fastcall fput(struct file * file)
49  {
50 Index: linux-2.4.29/fs/inode.c
51 ===================================================================
52 --- linux-2.4.29.orig/fs/inode.c        2005-05-03 18:16:44.000000000 +0300
53 +++ linux-2.4.29/fs/inode.c     2005-05-03 18:51:36.389419040 +0300
54 @@ -1139,9 +1139,10 @@
55         return inode;
56  }
57  
58 -struct inode *iget4_locked(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 @@ -1154,6 +1155,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_locked(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.29/fs/namei.c
93 ===================================================================
94 --- linux-2.4.29.orig/fs/namei.c        2005-05-03 18:16:43.000000000 +0300
95 +++ linux-2.4.29/fs/namei.c     2005-05-03 18:46:09.310142648 +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 @@ -910,7 +912,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 @@ -930,11 +933,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.29/fs/nfsd/export.c
141 ===================================================================
142 --- linux-2.4.29.orig/fs/nfsd/export.c  2005-05-03 16:28:21.000000000 +0300
143 +++ linux-2.4.29/fs/nfsd/export.c       2005-05-03 18:46:09.312142344 +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.29/fs/nfsd/nfsfh.c
157 ===================================================================
158 --- linux-2.4.29.orig/fs/nfsd/nfsfh.c   2005-05-03 16:28:21.000000000 +0300
159 +++ linux-2.4.29/fs/nfsd/nfsfh.c        2005-05-03 18:46:09.315141888 +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 +82,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 +94,37 @@
184         /*
185          * Open the directory ...
186          */
187 -       error = init_private_file(&file, dentry, FMODE_READ);
188 +       if (dentry->d_op && dentry->d_op->d_revalidate_it) {
189 +               if ((dentry->d_flags & DCACHE_NFSD_DISCONNECTED) &&
190 +                   (dentry->d_parent == dentry) ) {
191 +                       it.it_op_release = NULL;
192 +                       /*
193 +                        * XXX Temporary Hack: Simulate init_private_file without
194 +                        * f_op->open for disconnected dentry as we don't have
195 +                        * actual dentry->d_name to revalidate in revalidate_it()
196 +                        */
197 +                       filp = &file;
198 +                       memset(filp, 0, sizeof(*filp));
199 +                       filp->f_mode   = FMODE_READ;
200 +                       atomic_set(&filp->f_count, 1);
201 +                       filp->f_dentry = dentry;
202 +                       filp->f_uid = current->fsuid;
203 +                       filp->f_gid = current->fsgid;
204 +                       filp->f_op = dentry->d_inode->i_fop;
205 +                       error = 0;
206 +               } else {
207 +                       intent_init(&it, IT_OPEN, FMODE_READ);
208 +                       error = revalidate_it(dentry, &it);
209 +                       if (error)
210 +                               goto out;
211 +                       error = init_private_file_it(&file, dentry, FMODE_READ, &it);
212 +               }
213 +       } else {
214 +               error = init_private_file_it(&file, dentry, FMODE_READ, NULL);
215 +       }
216         if (error)
217                 goto out;
218 +
219         error = -EINVAL;
220         if (!file.f_op->readdir)
221                 goto out_close;
222 @@ -113,9 +150,12 @@
223         }
224  
225  out_close:
226 -       if (file.f_op->release)
227 +       if (file.f_op->release && !filp)
228                 file.f_op->release(dir, &file);
229  out:
230 +       if (dentry->d_op && dentry->d_op->d_revalidate_it &&
231 +           it.it_op_release && !filp)
232 +               intent_release(&it);
233         return error;
234  }
235  
236 @@ -274,7 +314,7 @@
237          * it is well connected.  But nobody returns different dentrys do they?
238          */
239         down(&child->d_inode->i_sem);
240 -       pdentry = child->d_inode->i_op->lookup(child->d_inode, tdentry);
241 +       pdentry = lookup_it(child->d_inode, tdentry);
242         up(&child->d_inode->i_sem);
243         d_drop(tdentry); /* we never want ".." hashed */
244         if (!pdentry && tdentry->d_inode == NULL) {
245 @@ -307,6 +347,8 @@
246                                 pdentry->d_flags |= DCACHE_NFSD_DISCONNECTED;
247                                 pdentry->d_op = child->d_op;
248                         }
249 +                       if (child->d_op && child->d_op->d_revalidate_it)
250 +                               pdentry->d_op = child->d_op;
251                 }
252                 if (pdentry == NULL)
253                         pdentry = ERR_PTR(-ENOMEM);
254 @@ -464,6 +506,8 @@
255                 struct dentry *pdentry;
256                 struct inode *parent;
257  
258 +               if (result->d_op && result->d_op->d_revalidate_it)
259 +                       dentry->d_op = result->d_op;
260                 pdentry = nfsd_findparent(dentry);
261                 err = PTR_ERR(pdentry);
262                 if (IS_ERR(pdentry))
263 @@ -670,6 +714,10 @@
264  
265         inode = dentry->d_inode;
266  
267 +       /* cache coherency for non-device filesystems */
268 +       if (inode->i_op && inode->i_op->revalidate_it)
269 +               inode->i_op->revalidate_it(dentry, NULL);
270 +
271         /* Type check. The correct error return for type mismatches
272          * does not seem to be generally agreed upon. SunOS seems to
273          * use EISDIR if file isn't S_IFREG; a comment in the NFSv3
274 @@ -903,8 +951,9 @@
275                 dentry->d_parent->d_name.name, dentry->d_name.name);
276         goto out;
277  out_uptodate:
278 -       printk(KERN_ERR "fh_update: %s/%s already up-to-date!\n",
279 -               dentry->d_parent->d_name.name, dentry->d_name.name);
280 +       if (!dentry->d_parent->d_inode->i_op->mkdir_raw)
281 +               printk(KERN_ERR "fh_update: %s/%s already up-to-date!\n",
282 +                     dentry->d_parent->d_name.name, dentry->d_name.name);
283         goto out;
284  }
285  
286 Index: linux-2.4.29/fs/nfsd/vfs.c
287 ===================================================================
288 --- linux-2.4.29.orig/fs/nfsd/vfs.c     2005-05-03 16:28:21.000000000 +0300
289 +++ linux-2.4.29/fs/nfsd/vfs.c  2005-05-03 18:46:09.372133224 +0300
290 @@ -77,6 +77,127 @@
291  static struct raparms *                raparml;
292  static struct raparms *                raparm_cache;
293  
294 +static int link_raw(struct dentry *dold, struct dentry *ddir,
295 +                   struct dentry *dnew)
296 +{
297 +       int err;
298 +
299 +       struct nameidata old_nd = { .dentry = dold };
300 +       struct nameidata nd = { .dentry = ddir, .last = dnew->d_name };
301 +       struct inode_operations *op = nd.dentry->d_inode->i_op;
302 +       err = op->link_raw(&old_nd, &nd);
303 +       igrab(dold->d_inode);
304 +       d_instantiate(dnew, dold->d_inode);
305 +       if (dold->d_inode->i_op && dold->d_inode->i_op->revalidate_it)
306 +               dold->d_inode->i_op->revalidate_it(dnew, NULL);
307 +
308 +       return err;
309 +}
310 +
311 +static int unlink_raw(struct dentry *dentry, char *fname, int flen,
312 +                     struct dentry *rdentry)
313 +{
314 +       int err;
315 +       struct qstr last = { .name = fname, .len = flen };
316 +       struct nameidata nd = { .dentry = dentry, .last = last };
317 +       struct inode_operations *op = nd.dentry->d_inode->i_op;
318 +       err = op->unlink_raw(&nd);
319 +       if (!err)
320 +               d_delete(rdentry);
321 +
322 +       return err;
323 +}
324 +
325 +static int rmdir_raw(struct dentry *dentry, char *fname, int flen,
326 +                    struct dentry *rdentry)
327 +{
328 +       int err;
329 +       struct qstr last = { .name = fname, .len = flen };
330 +       struct nameidata nd = { .dentry = dentry, .last = last };
331 +       struct inode_operations *op = nd.dentry->d_inode->i_op;
332 +       err = op->rmdir_raw(&nd);
333 +       if (!err) {
334 +               rdentry->d_inode->i_flags |= S_DEAD;
335 +               d_delete(rdentry);
336 +       }
337 +
338 +       return err;
339 +}
340 +
341 +static int symlink_raw(struct dentry *dentry, char *fname, int flen,
342 +                      char *path)
343 +{
344 +       int err;
345 +       struct qstr last = { .name = fname, .len = flen };
346 +       struct nameidata nd = { .dentry = dentry, .last = last };
347 +       struct inode_operations *op = nd.dentry->d_inode->i_op;
348 +       err = op->symlink_raw(&nd, path);
349 +
350 +       return err;
351 +}
352 +
353 +static int mkdir_raw(struct dentry *dentry, char *fname, int flen, int mode)
354 +{
355 +       int err;
356 +       struct qstr last = { .name = fname, .len = flen };
357 +       struct nameidata nd = { .dentry = dentry, .last = last };
358 +       struct inode_operations *op = nd.dentry->d_inode->i_op;
359 +       err = op->mkdir_raw(&nd, mode);
360 +
361 +       return err;
362 +}
363 +
364 +static int mknod_raw(struct dentry *dentry, char *fname, int flen, int mode,
365 +                    dev_t dev)
366 +{
367 +       int err;
368 +       struct qstr last = { .name = fname, .len = flen };
369 +       struct nameidata nd = { .dentry = dentry, .last = last };
370 +       struct inode_operations *op = nd.dentry->d_inode->i_op;
371 +       err = op->mknod_raw(&nd, mode, dev);
372 +
373 +       return err;
374 +}
375 +
376 +static int rename_raw(struct dentry *fdentry, struct dentry *tdentry,
377 +                     struct dentry *odentry, struct dentry *ndentry)
378 +{
379 +       int err;
380 +
381 +       struct nameidata old_nd = { .dentry = fdentry, .last = odentry->d_name};
382 +       struct nameidata new_nd = { .dentry = tdentry, .last = ndentry->d_name};
383 +       struct inode_operations *op = old_nd.dentry->d_inode->i_op;
384 +       err = op->rename_raw(&old_nd, &new_nd);
385 +       d_move(odentry, ndentry);
386 +
387 +       return err;
388 +}
389 +
390 +static int setattr_raw(struct inode *inode, struct iattr *iap)
391 +{
392 +       int err;
393 +
394 +       iap->ia_valid |= ATTR_RAW;
395 +       err = inode->i_op->setattr_raw(inode, iap);
396 +
397 +       return err;
398 +}
399 +
400 +int revalidate_it(struct dentry *dentry, struct lookup_intent *it)
401 +{
402 +       int err = 0;
403 +
404 +       if (dentry && dentry->d_op && dentry->d_op->d_revalidate_it) {
405 +               if (!dentry->d_op->d_revalidate_it(dentry, 0, it) &&
406 +                       !d_invalidate(dentry)) {
407 +                       err = -EINVAL;
408 +                       return err;
409 +               }
410 +       }
411 +
412 +       return err;
413 +}
414 +
415  /*
416   * Look up one component of a pathname.
417   * N.B. After this call _both_ fhp and resfh need an fh_put
418 @@ -302,7 +422,10 @@
419         }
420         err = nfserr_notsync;
421         if (!check_guard || guardtime == inode->i_ctime) {
422 -               err = notify_change(dentry, iap);
423 +               if (dentry->d_inode->i_op && dentry->d_inode->i_op->setattr_raw)
424 +                       err = setattr_raw(dentry->d_inode, iap);
425 +               else
426 +                       err = notify_change(dentry, iap);
427                 err = nfserrno(err);
428         }
429         if (size_change) {
430 @@ -429,6 +552,7 @@
431  {
432         struct dentry   *dentry;
433         struct inode    *inode;
434 +       struct lookup_intent it;
435         int             err;
436  
437         /* If we get here, then the client has already done an "open", and (hopefully)
438 @@ -475,6 +599,18 @@
439                 filp->f_mode  = FMODE_READ;
440         }
441  
442 +#ifndef O_OWNER_OVERRIDE
443 +#define O_OWNER_OVERRIDE 0200000000
444 +#endif
445 +       intent_init(&it, IT_OPEN, (filp->f_flags & ~O_ACCMODE) | filp->f_mode |
446 +                   O_OWNER_OVERRIDE);
447 +
448 +       err = revalidate_it(dentry, &it);
449 +       if (err)
450 +               goto out_nfserr;
451 +
452 +       filp->f_it = &it;
453 +
454         err = 0;
455         if (filp->f_op && filp->f_op->open) {
456                 err = filp->f_op->open(inode, filp);
457 @@ -490,6 +626,9 @@
458                 }
459         }
460  out_nfserr:
461 +       if (it.it_op_release)
462 +               intent_release(&it);
463 +
464         if (err)
465                 err = nfserrno(err);
466  out:
467 @@ -837,7 +976,7 @@
468  {
469         struct dentry   *dentry, *dchild;
470         struct inode    *dirp;
471 -       int             err;
472 +       int             err, error = -EOPNOTSUPP;
473  
474         err = nfserr_perm;
475         if (!flen)
476 @@ -853,20 +992,47 @@
477         dentry = fhp->fh_dentry;
478         dirp = dentry->d_inode;
479  
480 +       switch (type) {
481 +       case S_IFDIR:
482 +               if (dirp->i_op->mkdir_raw)
483 +                       error = mkdir_raw(dentry, fname, flen, iap->ia_mode);
484 +               break;
485 +       case S_IFCHR:
486 +       case S_IFBLK:
487 +       case S_IFIFO:
488 +       case S_IFSOCK:
489 +       case S_IFREG:
490 +               if (dirp->i_op->mknod_raw) {
491 +                       if (type == S_IFREG)
492 +                               rdev = 0;
493 +                       error = mknod_raw(dentry, fname,flen,iap->ia_mode,rdev);
494 +               }
495 +               break;
496 +       default:
497 +               printk("nfsd: bad file type %o in nfsd_create\n", type);
498 +       }
499 +       if (error && error != -EOPNOTSUPP) {
500 +               err = error;
501 +               goto out_nfserr;
502 +       }
503 +
504         err = nfserr_notdir;
505 -       if(!dirp->i_op || !dirp->i_op->lookup)
506 +       if (!dirp->i_op || !(dirp->i_op->lookup || dirp->i_op->lookup_it))
507                 goto out;
508         /*
509          * Check whether the response file handle has been verified yet.
510          * If it has, the parent directory should already be locked.
511          */
512 -       if (!resfhp->fh_dentry) {
513 -               /* called from nfsd_proc_mkdir, or possibly nfsd3_proc_create */
514 -               fh_lock(fhp);
515 +       if (!resfhp->fh_dentry || dirp->i_op->lookup_it) {
516 +               /* called from nfsd_proc_mkdir, or possibly nfsd3_proc_create
517 +                * and nfsd_proc_create in case of lustre */
518 +               if (!resfhp->fh_dentry)
519 +                       fh_lock(fhp);
520                 dchild = lookup_one_len(fname, dentry, flen);
521                 err = PTR_ERR(dchild);
522                 if (IS_ERR(dchild))
523                         goto out_nfserr;
524 +               resfhp->fh_dentry = NULL;
525                 err = fh_compose(resfhp, fhp->fh_export, dchild, fhp);
526                 if (err)
527                         goto out;
528 @@ -887,10 +1053,12 @@
529          * Make sure the child dentry is still negative ...
530          */
531         err = nfserr_exist;
532 -       if (dchild->d_inode) {
533 -               dprintk("nfsd_create: dentry %s/%s not negative!\n",
534 -                       dentry->d_name.name, dchild->d_name.name);
535 -               goto out; 
536 +       if (error == -EOPNOTSUPP) {
537 +               if (dchild->d_inode) {
538 +                       dprintk("nfsd_create: dentry %s/%s not negative!\n",
539 +                               dentry->d_name.name, dchild->d_name.name);
540 +                       goto out;
541 +               }
542         }
543  
544         if (!(iap->ia_valid & ATTR_MODE))
545 @@ -903,16 +1071,19 @@
546         err = nfserr_perm;
547         switch (type) {
548         case S_IFREG:
549 -               err = vfs_create(dirp, dchild, iap->ia_mode);
550 +               if (error == -EOPNOTSUPP)
551 +                       err = vfs_create(dirp, dchild, iap->ia_mode);
552                 break;
553         case S_IFDIR:
554 -               err = vfs_mkdir(dirp, dchild, iap->ia_mode);
555 +               if (error == -EOPNOTSUPP)
556 +                       err = vfs_mkdir(dirp, dchild, iap->ia_mode);
557                 break;
558         case S_IFCHR:
559         case S_IFBLK:
560         case S_IFIFO:
561         case S_IFSOCK:
562 -               err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev);
563 +               if (error == -EOPNOTSUPP)
564 +                       err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev);
565                 break;
566         default:
567                 printk("nfsd: bad file type %o in nfsd_create\n", type);
568 @@ -981,7 +1152,13 @@
569         /* Get all the sanity checks out of the way before
570          * we lock the parent. */
571         err = nfserr_notdir;
572 -       if(!dirp->i_op || !dirp->i_op->lookup)
573 +       if (dirp->i_op->mknod_raw) {
574 +               err = mknod_raw(dentry, fname, flen, iap->ia_mode, 0);
575 +               if (err && err != -EOPNOTSUPP)
576 +                       goto out_nfserr;
577 +       }
578 +
579 +       if (!dirp->i_op || !(dirp->i_op->lookup || dirp->i_op->lookup_it))
580                 goto out;
581         fh_lock(fhp);
582  
583 @@ -1032,6 +1209,8 @@
584                 case NFS3_CREATE_GUARDED:
585                         err = nfserr_exist;
586                 }
587 +               if (dirp->i_op->mknod_raw)
588 +                       err = 0;
589                 goto out;
590         }
591  
592 @@ -1138,7 +1317,7 @@
593                                 struct iattr *iap)
594  {
595         struct dentry   *dentry, *dnew;
596 -       int             err, cerr;
597 +       int             err, cerr, error = -EOPNOTSUPP;
598  
599         err = nfserr_noent;
600         if (!flen || !plen)
601 @@ -1152,12 +1331,18 @@
602                 goto out;
603         fh_lock(fhp);
604         dentry = fhp->fh_dentry;
605 +
606 +       if (dentry->d_inode->i_op->symlink_raw)
607 +               error = symlink_raw(dentry, fname, flen, path);
608 +
609         dnew = lookup_one_len(fname, dentry, flen);
610         err = PTR_ERR(dnew);
611         if (IS_ERR(dnew))
612                 goto out_nfserr;
613  
614 -       err = vfs_symlink(dentry->d_inode, dnew, path);
615 +       err = error;
616 +       if (err == -EOPNOTSUPP || !dentry->d_inode->i_op->symlink_raw)
617 +               err = vfs_symlink(dentry->d_inode, dnew, path);
618         if (!err) {
619                 if (EX_ISSYNC(fhp->fh_export))
620                         nfsd_sync_dir(dentry);
621 @@ -1167,7 +1352,10 @@
622                                 iap->ia_valid |= ATTR_CTIME;
623                                 iap->ia_mode = (iap->ia_mode&S_IALLUGO)
624                                         | S_IFLNK;
625 -                               err = notify_change(dnew, iap);
626 +                               if (dnew->d_inode->i_op && dnew->d_inode->i_op->setattr_raw)
627 +                                       err = setattr_raw(dnew->d_inode, iap);
628 +                               else
629 +                                       err = notify_change(dnew, iap);
630                                 if (err)
631                                         err = nfserrno(err);
632                                 else if (EX_ISSYNC(fhp->fh_export))
633 @@ -1227,7 +1415,10 @@
634         dold = tfhp->fh_dentry;
635         dest = dold->d_inode;
636  
637 -       err = vfs_link(dold, dirp, dnew);
638 +       if (dirp->i_op->link_raw)
639 +               err = link_raw(dold, ddir, dnew);
640 +       else
641 +               err = vfs_link(dold, dirp, dnew);
642         if (!err) {
643                 if (EX_ISSYNC(ffhp->fh_export)) {
644                         nfsd_sync_dir(ddir);
645 @@ -1312,7 +1503,10 @@
646                         err = nfserr_perm;
647         } else
648  #endif
649 -       err = vfs_rename(fdir, odentry, tdir, ndentry);
650 +       if (fdir->i_op->rename_raw)
651 +               err = rename_raw(fdentry, tdentry, odentry, ndentry);
652 +       else
653 +               err = vfs_rename(fdir, odentry, tdir, ndentry);
654         if (!err && EX_ISSYNC(tfhp->fh_export)) {
655                 nfsd_sync_dir(tdentry);
656                 nfsd_sync_dir(fdentry);
657 @@ -1333,7 +1527,7 @@
658         fill_post_wcc(tfhp);
659         double_up(&tdir->i_sem, &fdir->i_sem);
660         ffhp->fh_locked = tfhp->fh_locked = 0;
661 -       
662 +
663  out:
664         return err;
665  }
666 @@ -1379,9 +1573,15 @@
667                         err = nfserr_perm;
668                 } else
669  #endif
670 -               err = vfs_unlink(dirp, rdentry);
671 +               if (dirp->i_op->unlink_raw)
672 +                       err = unlink_raw(dentry, fname, flen, rdentry);
673 +               else
674 +                       err = vfs_unlink(dirp, rdentry);
675         } else { /* It's RMDIR */
676 -               err = vfs_rmdir(dirp, rdentry);
677 +               if (dirp->i_op->rmdir_raw)
678 +                       err = rmdir_raw(dentry, fname, flen, rdentry);
679 +               else
680 +                       err = vfs_rmdir(dirp, rdentry);
681         }
682  
683         dput(rdentry);
684 Index: linux-2.4.29/include/linux/fs.h
685 ===================================================================
686 --- linux-2.4.29.orig/include/linux/fs.h        2005-05-03 18:16:44.000000000 +0300
687 +++ linux-2.4.29/include/linux/fs.h     2005-05-03 18:52:56.016313912 +0300
688 @@ -93,6 +93,8 @@
689  #define FS_SINGLE      8 /* Filesystem that can have only one superblock */
690  #define FS_NOMOUNT     16 /* Never mount from userland */
691  #define FS_LITTER      32 /* Keeps the tree in dcache */
692 +#define FS_NFSEXP_FSID 64 /* Use file system specific fsid for
693 +                           * exporting non device filesystems. */
694  #define FS_ODD_RENAME  32768   /* Temporary stuff; will go away as soon
695                                   * as nfs_rename() will be cleaned up
696                                   */
697 @@ -1124,6 +1126,9 @@
698                          struct nameidata *nd, struct lookup_intent *it);
699  extern struct file *dentry_open_it(struct dentry *dentry, struct vfsmount *mnt,
700                             int flags, struct lookup_intent *it);
701 +extern int revalidate_it(struct dentry *dentry, struct lookup_intent *it);
702 +extern int init_private_file_it(struct file *, struct dentry *dentry, int mode,
703 +                               struct lookup_intent *it);
704  extern int filp_close(struct file *, fl_owner_t id);
705  extern char * getname(const char *);
706  
707 @@ -1423,6 +1428,8 @@
708  extern int follow_down(struct vfsmount **, struct dentry **);
709  extern int follow_up(struct vfsmount **, struct dentry **);
710  extern struct dentry * lookup_one_len(const char *, struct dentry *, int);
711 +extern struct dentry * lookup_one_len_it(const char *, struct dentry *, int,
712 +                                        struct lookup_intent *);
713  extern struct dentry * lookup_hash(struct qstr *, struct dentry *);
714  #define user_path_walk(name,nd)         __user_walk(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, nd)
715  #define user_path_walk_link(name,nd) __user_walk(name, LOOKUP_POSITIVE, nd)
716 @@ -1443,6 +1450,8 @@
717  
718  extern struct inode * iget4_locked(struct super_block *, unsigned long,
719                                    find_inode_t, void *);
720 + extern struct inode * ilookup4(struct super_block *, unsigned long,
721 +                               find_inode_t, void *);
722  
723  static inline struct inode *iget4(struct super_block *sb, unsigned long ino,
724                                   find_inode_t find_actor, void *opaque)
725 Index: linux-2.4.29/kernel/ksyms.c
726 ===================================================================
727 --- linux-2.4.29.orig/kernel/ksyms.c    2005-05-03 18:16:44.000000000 +0300
728 +++ linux-2.4.29/kernel/ksyms.c 2005-05-03 18:52:05.377012256 +0300
729 @@ -150,6 +150,7 @@
730  EXPORT_SYMBOL(iunique);
731  EXPORT_SYMBOL(ilookup);
732  EXPORT_SYMBOL(iget4_locked);
733 +EXPORT_SYMBOL(ilookup4);
734  EXPORT_SYMBOL(unlock_new_inode);
735  EXPORT_SYMBOL(iput);
736  EXPORT_SYMBOL(inode_init_once);
737 @@ -164,6 +165,7 @@
738  EXPORT_SYMBOL(path_release);
739  EXPORT_SYMBOL(__user_walk);
740  EXPORT_SYMBOL(lookup_one_len);
741 +EXPORT_SYMBOL(lookup_one_len_it);
742  EXPORT_SYMBOL(lookup_hash);
743  EXPORT_SYMBOL(sys_close);
744  EXPORT_SYMBOL(dcache_lock);