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