Whamcloud - gitweb
land v0.9.1 on HEAD, in preparation for a 1.0.x branch
[fs/lustre-release.git] / lustre / kernel_patches / patches / nfs_export_kernel-2.4.18.patch
1  fs/Makefile        |    3 
2  fs/file_table.c    |   11 ++
3  fs/inode.c         |   23 ++++-
4  fs/namei.c         |   12 ++
5  fs/nfsd/export.c   |    5 +
6  fs/nfsd/nfsfh.c    |   65 +++++++++++++-
7  fs/nfsd/vfs.c      |  240 ++++++++++++++++++++++++++++++++++++++++++++++++-----
8  include/linux/fs.h |   10 ++
9  kernel/ksyms.c     |    2 
10  9 files changed, 337 insertions(+), 34 deletions(-)
11
12 --- linux-2.4.18-chaos/fs/file_table.c~nfs_export_kernel-2.4.18 2003-07-28 17:52:04.000000000 +0400
13 +++ linux-2.4.18-chaos-alexey/fs/file_table.c   2003-10-08 01:10:58.000000000 +0400
14 @@ -82,7 +82,8 @@ struct file * get_empty_filp(void)
15   * and call the open function (if any).  The caller must verify that
16   * inode->i_fop is not NULL.
17   */
18 -int init_private_file(struct file *filp, struct dentry *dentry, int mode)
19 +int init_private_file_it(struct file *filp, struct dentry *dentry, int mode,
20 +                         struct lookup_intent *it)
21  {
22         memset(filp, 0, sizeof(*filp));
23         filp->f_mode   = mode;
24 @@ -90,12 +91,20 @@ int init_private_file(struct file *filp,
25         filp->f_dentry = dentry;
26         filp->f_uid    = current->fsuid;
27         filp->f_gid    = current->fsgid;
28 +       if (it)
29 +               filp->f_it = it;
30         filp->f_op     = dentry->d_inode->i_fop;
31         if (filp->f_op->open)
32                 return filp->f_op->open(dentry->d_inode, filp);
33         else
34                 return 0;
35  }
36 +EXPORT_SYMBOL(init_private_file_it);
37 +
38 +int init_private_file(struct file *filp, struct dentry *dentry, int mode)
39 +{
40 +       return init_private_file_it(filp, dentry, mode, NULL);
41 +}
42  
43  void fput(struct file * file)
44  {
45 --- linux-2.4.18-chaos/fs/inode.c~nfs_export_kernel-2.4.18      2003-10-08 00:58:35.000000000 +0400
46 +++ linux-2.4.18-chaos-alexey/fs/inode.c        2003-10-08 01:10:58.000000000 +0400
47 @@ -987,9 +987,10 @@ struct inode *igrab(struct inode *inode)
48  }
49  
50  
51 -struct inode *iget4(struct super_block *sb, unsigned long ino, find_inode_t find_actor, void *opaque)
52 +static inline struct inode *ifind(struct super_block *sb, unsigned long ino,
53 +                                  struct list_head *head,
54 +                                  find_inode_t find_actor, void *opaque)
55  {
56 -       struct list_head * head = inode_hashtable + hash(sb,ino);
57         struct inode * inode;
58  
59         spin_lock(&inode_lock);
60 @@ -1002,6 +1003,24 @@ struct inode *iget4(struct super_block *
61         }
62         spin_unlock(&inode_lock);
63  
64 +       return NULL;
65 +}
66 +
67 +struct inode *ilookup4(struct super_block *sb, unsigned long ino,
68 +                       find_inode_t find_actor, void *opaque)
69 +{
70 +       struct list_head * head = inode_hashtable + hash(sb,ino);
71 +       return ifind(sb, ino, head, find_actor, opaque);
72 +}
73 +
74 +struct inode *iget4(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 +       struct inode *inode = ifind(sb, ino, head, find_actor, opaque);
79 +       if (inode)
80 +               return inode;
81 +
82         /*
83          * get_new_inode() will do the right thing, re-trying the search
84          * in case it had to block at any point.
85 --- linux-2.4.18-chaos/fs/Makefile~nfs_export_kernel-2.4.18     2003-10-08 00:58:35.000000000 +0400
86 +++ linux-2.4.18-chaos-alexey/fs/Makefile       2003-10-08 01:10:58.000000000 +0400
87 @@ -9,7 +9,8 @@
88  
89  O_TARGET := fs.o
90  
91 -export-objs := filesystems.o open.o dcache.o buffer.o inode.o
92 +export-objs := filesystems.o open.o dcache.o buffer.o inode.o namei.o \
93 +               file_table.o
94  mod-subdirs := nls
95  
96  obj-y :=       open.o read_write.o devices.o file_table.o buffer.o \
97 --- linux-2.4.18-chaos/fs/namei.c~nfs_export_kernel-2.4.18      2003-10-08 00:58:34.000000000 +0400
98 +++ linux-2.4.18-chaos-alexey/fs/namei.c        2003-10-08 01:10:58.000000000 +0400
99 @@ -22,6 +22,7 @@
100  #include <linux/dnotify.h>
101  #include <linux/smp_lock.h>
102  #include <linux/personality.h>
103 +#include <linux/module.h>
104  
105  #include <asm/namei.h>
106  #include <asm/uaccess.h>
107 @@ -100,6 +101,7 @@ void intent_release(struct lookup_intent
108                 it->it_op_release(it);
109  
110  }
111 +EXPORT_SYMBOL(intent_release);
112  
113  /* In order to reduce some races, while at the same time doing additional
114   * checking and hopefully speeding things up, we copy filenames to the
115 @@ -914,7 +916,8 @@ struct dentry * lookup_hash(struct qstr 
116  
117  
118  /* SMP-safe */
119 -struct dentry * lookup_one_len(const char * name, struct dentry * base, int len)
120 +struct dentry * lookup_one_len_it(const char * name, struct dentry * base,
121 +                                  int len, struct lookup_intent *it)
122  {
123         unsigned long hash;
124         struct qstr this;
125 @@ -934,11 +937,16 @@ struct dentry * lookup_one_len(const cha
126         }
127         this.hash = end_name_hash(hash);
128  
129 -       return lookup_hash_it(&this, base, NULL);
130 +       return lookup_hash_it(&this, base, it);
131  access:
132         return ERR_PTR(-EACCES);
133  }
134  
135 +struct dentry * lookup_one_len(const char * name, struct dentry * base, int len)
136 +{
137 +       return lookup_one_len_it(name, base, len, NULL);
138 +}
139 +
140  /*
141   *     namei()
142   *
143 --- linux-2.4.18-chaos/fs/nfsd/export.c~nfs_export_kernel-2.4.18        2003-07-28 17:52:06.000000000 +0400
144 +++ linux-2.4.18-chaos-alexey/fs/nfsd/export.c  2003-10-08 01:10:58.000000000 +0400
145 @@ -250,6 +250,11 @@ exp_export(struct nfsctl_export *nxp)
146         inode = nd.dentry->d_inode;
147         dev = inode->i_dev;
148         ino = inode->i_ino;
149 +       if ((inode->i_sb->s_type->fs_flags & FS_NFSEXP_FSID) &&
150 +           !(nxp->ex_flags & NFSEXP_FSID)) {
151 +           nxp->ex_dev = inode->i_sb->s_dev;
152 +           nxp->ex_flags |= NFSEXP_FSID;
153 +       }
154         err = -EINVAL;
155  
156         exp = exp_get(clp, dev, ino);
157 --- linux-2.4.18-chaos/fs/nfsd/nfsfh.c~nfs_export_kernel-2.4.18 2003-07-28 17:52:06.000000000 +0400
158 +++ linux-2.4.18-chaos-alexey/fs/nfsd/nfsfh.c   2003-10-08 01:10:58.000000000 +0400
159 @@ -37,6 +37,15 @@ struct nfsd_getdents_callback {
160         int sequence;           /* sequence counter */
161  };
162  
163 +static struct dentry *lookup_it(struct inode *inode, struct dentry * dentry)
164 +{
165 +       if (inode->i_op->lookup_it)
166 +           return inode->i_op->lookup_it(inode, dentry, NULL, 0);
167 +       else
168 +           return inode->i_op->lookup(inode, dentry);
169 +               
170 +}
171 +
172  /*
173   * A rather strange filldir function to capture
174   * the name matching the specified inode number.
175 @@ -76,6 +85,8 @@ static int nfsd_get_name(struct dentry *
176         int error;
177         struct file file;
178         struct nfsd_getdents_callback buffer;
179 +       struct lookup_intent it;
180 +       struct file *filp = NULL;
181  
182         error = -ENOTDIR;
183         if (!dir || !S_ISDIR(dir->i_mode))
184 @@ -86,9 +97,37 @@ static int nfsd_get_name(struct dentry *
185         /*
186          * Open the directory ...
187          */
188 -       error = init_private_file(&file, dentry, FMODE_READ);
189 -       if (error)
190 +       if (dentry->d_op && dentry->d_op->d_revalidate_it) {
191 +               if ((dentry->d_flags & DCACHE_NFSD_DISCONNECTED) &&
192 +                   (dentry->d_parent == dentry) ) {
193 +                       it.it_op_release = NULL;
194 +                       /* 
195 +                        * XXX Temporary Hack: Simulating init_private_file without
196 +                        * f_op->open for disconnected dentry Since we don't have actual
197 +                        * dentry->d_name to revalidate in revalidate_it()
198 +                        */
199 +                       filp = &file;
200 +                       memset(filp, 0, sizeof(*filp));
201 +                       filp->f_mode   = FMODE_READ;
202 +                       atomic_set(&filp->f_count, 1);
203 +                       filp->f_dentry = dentry;
204 +                       filp->f_uid = current->fsuid;
205 +                       filp->f_gid = current->fsgid;
206 +                       filp->f_op = dentry->d_inode->i_fop;
207 +                       error = 0;
208 +               } else {
209 +                       intent_init(&it, IT_OPEN, 0);
210 +                       error = revalidate_it(dentry, &it);
211 +                       if (error)
212 +                               goto out;
213 +                       error = init_private_file_it(&file, dentry, FMODE_READ, &it);
214 +               }
215 +       } else {
216 +               error = init_private_file_it(&file, dentry, FMODE_READ, NULL);
217 +       }
218 +       if (error) 
219                 goto out;
220 +
221         error = -EINVAL;
222         if (!file.f_op->readdir)
223                 goto out_close;
224 @@ -114,9 +153,13 @@ static int nfsd_get_name(struct dentry *
225         }
226  
227  out_close:
228 -       if (file.f_op->release)
229 +       if (file.f_op->release && !filp)
230                 file.f_op->release(dir, &file);
231  out:
232 +       if (dentry->d_op &&
233 +           dentry->d_op->d_revalidate_it &&
234 +           it.it_op_release && !filp)
235 +               intent_release(&it);
236         return error;
237  }
238  
239 @@ -275,7 +318,7 @@ struct dentry *nfsd_findparent(struct de
240          * it is well connected.  But nobody returns different dentrys do they?
241          */
242         down(&child->d_inode->i_sem);
243 -       pdentry = child->d_inode->i_op->lookup(child->d_inode, tdentry);
244 +       pdentry = lookup_it(child->d_inode, tdentry);
245         up(&child->d_inode->i_sem);
246         d_drop(tdentry); /* we never want ".." hashed */
247         if (!pdentry && tdentry->d_inode == NULL) {
248 @@ -307,6 +350,8 @@ struct dentry *nfsd_findparent(struct de
249                                 igrab(tdentry->d_inode);
250                                 pdentry->d_flags |= DCACHE_NFSD_DISCONNECTED;
251                         }
252 +                       if (child->d_op && child->d_op->d_revalidate_it)
253 +                               pdentry->d_op = child->d_op;
254                 }
255                 if (pdentry == NULL)
256                         pdentry = ERR_PTR(-ENOMEM);
257 @@ -465,6 +510,8 @@ find_fh_dentry(struct super_block *sb, _
258                 struct dentry *pdentry;
259                 struct inode *parent;
260  
261 +               if (result->d_op && result->d_op->d_revalidate_it)
262 +                       dentry->d_op = result->d_op;
263                 pdentry = nfsd_findparent(dentry);
264                 err = PTR_ERR(pdentry);
265                 if (IS_ERR(pdentry))
266 @@ -667,6 +714,11 @@ fh_verify(struct svc_rqst *rqstp, struct
267  
268         inode = dentry->d_inode;
269  
270 +       /* cache coherency for non-device filesystems */
271 +       if (inode->i_op && inode->i_op->revalidate_it) {
272 +           inode->i_op->revalidate_it(dentry, NULL);
273 +       }
274 +
275         /* Type check. The correct error return for type mismatches
276          * does not seem to be generally agreed upon. SunOS seems to
277          * use EISDIR if file isn't S_IFREG; a comment in the NFSv3
278 @@ -905,8 +957,9 @@ out_negative:
279                 dentry->d_parent->d_name.name, dentry->d_name.name);
280         goto out;
281  out_uptodate:
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 +       if(!dentry->d_parent->d_inode->i_op->mkdir_raw)
285 +               printk(KERN_ERR "fh_update: %s/%s already up-to-date!\n",
286 +                       dentry->d_parent->d_name.name, dentry->d_name.name);
287         goto out;
288  }
289  
290 --- linux-2.4.18-chaos/fs/nfsd/vfs.c~nfs_export_kernel-2.4.18   2003-07-28 17:52:06.000000000 +0400
291 +++ linux-2.4.18-chaos-alexey/fs/nfsd/vfs.c     2003-10-08 01:11:59.000000000 +0400
292 @@ -77,6 +77,128 @@ struct raparms {
293  static struct raparms *                raparml;
294  static struct raparms *                raparm_cache;
295  
296 +static int link_raw(struct dentry *dold, struct dentry *ddir,
297 +                    struct dentry *dnew)
298 +{
299 +       int err;
300 +
301 +       struct nameidata old_nd = { .dentry = dold };
302 +       struct nameidata nd = { .dentry = ddir, .last = dnew->d_name };
303 +       struct inode_operations *op = nd.dentry->d_inode->i_op;
304 +       err = op->link_raw(&old_nd, &nd);
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 +                       dput(dentry);
409 +                       err = -EINVAL;
410 +                       dentry = NULL;
411 +                       return err;
412 +               }
413 +       }
414 +
415 +       return err;
416 +}
417 +
418  /*
419   * Look up one component of a pathname.
420   * N.B. After this call _both_ fhp and resfh need an fh_put
421 @@ -300,7 +422,10 @@ nfsd_setattr(struct svc_rqst *rqstp, str
422         }
423         err = nfserr_notsync;
424         if (!check_guard || guardtime == inode->i_ctime) {
425 -               err = notify_change(dentry, iap);
426 +               if ( dentry->d_inode->i_op && dentry->d_inode->i_op->setattr_raw)
427 +                       err = setattr_raw(dentry->d_inode, iap);
428 +               else
429 +                       err = notify_change(dentry, iap);
430                 err = nfserrno(err);
431         }
432         if (size_change) {
433 @@ -427,6 +552,7 @@ nfsd_open(struct svc_rqst *rqstp, struct
434  {
435         struct dentry   *dentry;
436         struct inode    *inode;
437 +       struct lookup_intent it;
438         int             err;
439  
440         /* If we get here, then the client has already done an "open", and (hopefully)
441 @@ -473,6 +599,14 @@ nfsd_open(struct svc_rqst *rqstp, struct
442                 filp->f_mode  = FMODE_READ;
443         }
444  
445 +       intent_init(&it, IT_OPEN, (filp->f_flags & ~O_ACCMODE) | filp->f_mode);
446 +
447 +       err = revalidate_it(dentry, &it);
448 +       if (err)
449 +               goto out_nfserr;
450 +       
451 +       filp->f_it = &it;
452 +       
453         err = 0;
454         if (filp->f_op && filp->f_op->open) {
455                 err = filp->f_op->open(inode, filp);
456 @@ -487,7 +621,11 @@ nfsd_open(struct svc_rqst *rqstp, struct
457                         atomic_dec(&filp->f_count);
458                 }
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 @@ -824,7 +962,7 @@ nfsd_create(struct svc_rqst *rqstp, stru
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 @@ -840,20 +978,44 @@ nfsd_create(struct svc_rqst *rqstp, stru
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 +
501         err = nfserr_notdir;
502 -       if(!dirp->i_op || !dirp->i_op->lookup)
503 +       if(!dirp->i_op || !(dirp->i_op->lookup || dirp->i_op->lookup_it))
504                 goto out;
505         /*
506          * Check whether the response file handle has been verified yet.
507          * If it has, the parent directory should already be locked.
508          */
509 -       if (!resfhp->fh_dentry) {
510 -               /* called from nfsd_proc_mkdir, or possibly nfsd3_proc_create */
511 -               fh_lock(fhp);
512 +       if (!resfhp->fh_dentry || dirp->i_op->lookup_it) {
513 +               /* called from nfsd_proc_mkdir, or possibly nfsd3_proc_create
514 +                  and nfsd_proc_create in case of lustre
515 +               */
516 +               if (!resfhp->fh_dentry)
517 +                       fh_lock(fhp);
518                 dchild = lookup_one_len(fname, dentry, flen);
519                 err = PTR_ERR(dchild);
520                 if (IS_ERR(dchild))
521                         goto out_nfserr;
522 +               resfhp->fh_dentry = NULL;
523                 err = fh_compose(resfhp, fhp->fh_export, dchild, fhp);
524                 if (err)
525                         goto out;
526 @@ -874,10 +1036,12 @@ nfsd_create(struct svc_rqst *rqstp, stru
527          * Make sure the child dentry is still negative ...
528          */
529         err = nfserr_exist;
530 -       if (dchild->d_inode) {
531 -               dprintk("nfsd_create: dentry %s/%s not negative!\n",
532 -                       dentry->d_name.name, dchild->d_name.name);
533 -               goto out; 
534 +       if ( error == -EOPNOTSUPP) {
535 +               if (dchild->d_inode) {
536 +                       dprintk("nfsd_create: dentry %s/%s not negative!\n",
537 +                               dentry->d_name.name, dchild->d_name.name);
538 +                       goto out; 
539 +               }
540         }
541  
542         if (!(iap->ia_valid & ATTR_MODE))
543 @@ -890,16 +1054,19 @@ nfsd_create(struct svc_rqst *rqstp, stru
544         err = nfserr_perm;
545         switch (type) {
546         case S_IFREG:
547 -               err = vfs_create(dirp, dchild, iap->ia_mode);
548 +               if (error == -EOPNOTSUPP)
549 +                       err = vfs_create(dirp, dchild, iap->ia_mode);
550                 break;
551         case S_IFDIR:
552 -               err = vfs_mkdir(dirp, dchild, iap->ia_mode);
553 +               if (error == -EOPNOTSUPP)
554 +                       err = vfs_mkdir(dirp, dchild, iap->ia_mode);
555                 break;
556         case S_IFCHR:
557         case S_IFBLK:
558         case S_IFIFO:
559         case S_IFSOCK:
560 -               err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev);
561 +               if (error == -EOPNOTSUPP)       
562 +                       err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev);
563                 break;
564         default:
565                 printk("nfsd: bad file type %o in nfsd_create\n", type);
566 @@ -968,7 +1135,13 @@ nfsd_create_v3(struct svc_rqst *rqstp, s
567         /* Get all the sanity checks out of the way before
568          * we lock the parent. */
569         err = nfserr_notdir;
570 -       if(!dirp->i_op || !dirp->i_op->lookup)
571 +       if (dirp->i_op->mknod_raw) {
572 +               err = mknod_raw(dentry, fname, flen, iap->ia_mode, 0);
573 +               if (err && err != -EOPNOTSUPP)
574 +                       goto out;
575 +       }
576 +
577 +       if(!dirp->i_op ||  !(dirp->i_op->lookup || dirp->i_op->lookup_it))
578                 goto out;
579         fh_lock(fhp);
580  
581 @@ -1019,6 +1192,8 @@ nfsd_create_v3(struct svc_rqst *rqstp, s
582                 case NFS3_CREATE_GUARDED:
583                         err = nfserr_exist;
584                 }
585 +               if(dirp->i_op->mknod_raw)
586 +                       err = 0;
587                 goto out;
588         }
589  
590 @@ -1125,7 +1300,7 @@ nfsd_symlink(struct svc_rqst *rqstp, str
591                                 struct iattr *iap)
592  {
593         struct dentry   *dentry, *dnew;
594 -       int             err, cerr;
595 +       int             err, cerr, error = -EOPNOTSUPP;
596  
597         err = nfserr_noent;
598         if (!flen || !plen)
599 @@ -1139,12 +1314,18 @@ nfsd_symlink(struct svc_rqst *rqstp, str
600                 goto out;
601         fh_lock(fhp);
602         dentry = fhp->fh_dentry;
603 +       
604 +       if (dentry->d_inode->i_op->symlink_raw)
605 +               error = symlink_raw(dentry, fname, flen, path);
606 +
607         dnew = lookup_one_len(fname, dentry, flen);
608         err = PTR_ERR(dnew);
609         if (IS_ERR(dnew))
610                 goto out_nfserr;
611  
612 -       err = vfs_symlink(dentry->d_inode, dnew, path);
613 +       err = error;
614 +       if (err == -EOPNOTSUPP || !dentry->d_inode->i_op->symlink_raw)
615 +               err = vfs_symlink(dentry->d_inode, dnew, path);
616         if (!err) {
617                 if (EX_ISSYNC(fhp->fh_export))
618                         nfsd_sync_dir(dentry);
619 @@ -1154,7 +1335,10 @@ nfsd_symlink(struct svc_rqst *rqstp, str
620                                 iap->ia_valid |= ATTR_CTIME;
621                                 iap->ia_mode = (iap->ia_mode&S_IALLUGO)
622                                         | S_IFLNK;
623 -                               err = notify_change(dnew, iap);
624 +                               if (dnew->d_inode->i_op && dnew->d_inode->i_op->setattr_raw)
625 +                                       err = setattr_raw(dnew->d_inode, iap);
626 +                               else
627 +                                       err = notify_change(dnew, iap);
628                                 if (!err && EX_ISSYNC(fhp->fh_export))
629                                         write_inode_now(dentry->d_inode, 1);
630                        }
631 @@ -1212,7 +1396,10 @@ nfsd_link(struct svc_rqst *rqstp, struct
632         dold = tfhp->fh_dentry;
633         dest = dold->d_inode;
634  
635 -       err = vfs_link(dold, dirp, dnew);
636 +       if (dirp->i_op->link_raw)
637 +               err = link_raw(dold, ddir, dnew);
638 +       else
639 +               err = vfs_link(dold, dirp, dnew);
640         if (!err) {
641                 if (EX_ISSYNC(ffhp->fh_export)) {
642                         nfsd_sync_dir(ddir);
643 @@ -1298,7 +1485,10 @@ nfsd_rename(struct svc_rqst *rqstp, stru
644                         err = nfserr_perm;
645         } else
646  #endif
647 -       err = vfs_rename(fdir, odentry, tdir, ndentry);
648 +       if(fdir->i_op->rename_raw)
649 +               err = rename_raw(fdentry, tdentry, odentry, ndentry);
650 +       else
651 +               err = vfs_rename(fdir, odentry, tdir, ndentry);
652         unlock_kernel();
653         if (!err && EX_ISSYNC(tfhp->fh_export)) {
654                 nfsd_sync_dir(tdentry);
655 @@ -1320,7 +1510,7 @@ nfsd_rename(struct svc_rqst *rqstp, stru
656         fill_post_wcc(tfhp);
657         double_up(&tdir->i_sem, &fdir->i_sem);
658         ffhp->fh_locked = tfhp->fh_locked = 0;
659 -       
660 +
661  out:
662         return err;
663  }
664 @@ -1366,9 +1556,15 @@ nfsd_unlink(struct svc_rqst *rqstp, stru
665                         err = nfserr_perm;
666                 } else
667  #endif
668 -               err = vfs_unlink(dirp, rdentry);
669 +               if (dirp->i_op->unlink_raw)
670 +                       err = unlink_raw(dentry, fname, flen, rdentry);
671 +               else
672 +                       err = vfs_unlink(dirp, rdentry);
673         } else { /* It's RMDIR */
674 -               err = vfs_rmdir(dirp, rdentry);
675 +               if (dirp->i_op->rmdir_raw)
676 +                       err = rmdir_raw(dentry, fname, flen, rdentry);
677 +               else
678 +                       err = vfs_rmdir(dirp, rdentry);
679         }
680  
681         dput(rdentry);
682 --- linux-2.4.18-chaos/include/linux/fs.h~nfs_export_kernel-2.4.18      2003-10-08 01:09:51.000000000 +0400
683 +++ linux-2.4.18-chaos-alexey/include/linux/fs.h        2003-10-08 01:10:58.000000000 +0400
684 @@ -93,6 +93,9 @@ extern int leases_enable, dir_notify_ena
685  #define FS_SINGLE      8 /* Filesystem that can have only one superblock */
686  #define FS_NOMOUNT     16 /* Never mount from userland */
687  #define FS_LITTER      32 /* Keeps the tree in dcache */
688 +#define FS_NFSEXP_FSID 64 /* Use file system specific fsid for
689 +                          * exporting non device filesystems.
690 +                          */
691  #define FS_ODD_RENAME  32768   /* Temporary stuff; will go away as soon
692                                   * as nfs_rename() will be cleaned up
693                                   */
694 @@ -1147,6 +1150,9 @@ extern struct file *filp_open(const char
695  extern struct file * dentry_open(struct dentry *, struct vfsmount *, int);
696  extern struct file *dentry_open_it(struct dentry *dentry, struct vfsmount *mnt,
697                             int flags, struct lookup_intent *it);
698 +extern int revalidate_it(struct dentry *dentry, struct lookup_intent *it);
699 +extern int init_private_file_it(struct file *, struct dentry *dentry, int mode,
700 +                                struct lookup_intent *it);
701  extern int filp_close(struct file *, fl_owner_t id);
702  extern char * getname(const char *);
703  
704 @@ -1423,6 +1429,8 @@ extern void path_release(struct nameidat
705  extern int follow_down(struct vfsmount **, struct dentry **);
706  extern int follow_up(struct vfsmount **, struct dentry **);
707  extern struct dentry * lookup_one_len(const char *, struct dentry *, int);
708 +extern struct dentry * lookup_one_len_it(const char *, struct dentry *, int,
709 +                                         struct lookup_intent *);
710  extern struct dentry * lookup_hash(struct qstr *, struct dentry *);
711  #define user_path_walk(name,nd)         __user_walk(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, nd)
712  #define user_path_walk_link(name,nd) __user_walk(name, LOOKUP_POSITIVE, nd)
713 @@ -1437,6 +1445,8 @@ extern ino_t iunique(struct super_block 
714  
715  typedef int (*find_inode_t)(struct inode *, unsigned long, void *);
716  extern struct inode * iget4(struct super_block *, unsigned long, find_inode_t, void *);
717 +extern struct inode * ilookup4(struct super_block *, unsigned long,
718 +                               find_inode_t, void *);
719  static inline struct inode *iget(struct super_block *sb, unsigned long ino)
720  {
721         return iget4(sb, ino, NULL, NULL);
722 --- linux-2.4.18-chaos/kernel/ksyms.c~nfs_export_kernel-2.4.18  2003-10-08 00:58:34.000000000 +0400
723 +++ linux-2.4.18-chaos-alexey/kernel/ksyms.c    2003-10-08 01:10:58.000000000 +0400
724 @@ -156,6 +156,7 @@ EXPORT_SYMBOL(fget);
725  EXPORT_SYMBOL(igrab);
726  EXPORT_SYMBOL(iunique);
727  EXPORT_SYMBOL(iget4);
728 +EXPORT_SYMBOL(ilookup4);
729  EXPORT_SYMBOL(iput);
730  EXPORT_SYMBOL(inode_init_once);
731  EXPORT_SYMBOL(force_delete);
732 @@ -167,6 +168,7 @@ EXPORT_SYMBOL(path_walk);
733  EXPORT_SYMBOL(path_release);
734  EXPORT_SYMBOL(__user_walk);
735  EXPORT_SYMBOL(lookup_one_len);
736 +EXPORT_SYMBOL(lookup_one_len_it);
737  EXPORT_SYMBOL(lookup_hash);
738  EXPORT_SYMBOL(sys_close);
739  EXPORT_SYMBOL(sys_read);
740
741 _