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