Whamcloud - gitweb
- last nfs_export patch
authoralex <alex>
Wed, 8 Oct 2003 09:26:30 +0000 (09:26 +0000)
committeralex <alex>
Wed, 8 Oct 2003 09:26:30 +0000 (09:26 +0000)
- FS_NFSEXP_FSID flag is put into lustre_lite_fs_type as proposed
- patch ported against hp-pnnl-2.4.20 and rh-2.4.20 series

NOTE: please, don't forget to re-apply nfs_export_kernel* patch

lustre/kernel_patches/patches/nfs_export_kernel-2.4.20-hp.patch [new file with mode: 0644]
lustre/kernel_patches/patches/nfs_export_kernel-2.4.20-rh.patch [new file with mode: 0644]
lustre/kernel_patches/pc/nfs_export_kernel-2.4.20-hp.pc [new file with mode: 0644]
lustre/kernel_patches/pc/nfs_export_kernel-2.4.20-rh.pc [new file with mode: 0644]
lustre/kernel_patches/series/hp-pnnl-2.4.20
lustre/kernel_patches/series/rh-2.4.20

diff --git a/lustre/kernel_patches/patches/nfs_export_kernel-2.4.20-hp.patch b/lustre/kernel_patches/patches/nfs_export_kernel-2.4.20-hp.patch
new file mode 100644 (file)
index 0000000..ea4734e
--- /dev/null
@@ -0,0 +1,741 @@
+ fs/Makefile        |    3 
+ fs/file_table.c    |   11 ++
+ fs/inode.c         |   23 ++++-
+ fs/namei.c         |   12 ++
+ fs/nfsd/export.c   |    5 +
+ fs/nfsd/nfsfh.c    |   65 +++++++++++++-
+ fs/nfsd/vfs.c      |  240 ++++++++++++++++++++++++++++++++++++++++++++++++-----
+ include/linux/fs.h |   10 ++
+ kernel/ksyms.c     |    2 
+ 9 files changed, 337 insertions(+), 34 deletions(-)
+
+--- linux-2.4.20-hp4-pnnl13/fs/file_table.c~nfs_export_kernel-2.4.20-hp        2002-11-29 02:53:15.000000000 +0300
++++ linux-2.4.20-hp4-pnnl13-alexey/fs/file_table.c     2003-10-08 10:54:08.000000000 +0400
+@@ -82,7 +82,8 @@ struct file * get_empty_filp(void)
+  * and call the open function (if any).  The caller must verify that
+  * inode->i_fop is not NULL.
+  */
+-int init_private_file(struct file *filp, struct dentry *dentry, int mode)
++int init_private_file_it(struct file *filp, struct dentry *dentry, int mode,
++                         struct lookup_intent *it)
+ {
+       memset(filp, 0, sizeof(*filp));
+       filp->f_mode   = mode;
+@@ -90,12 +91,20 @@ int init_private_file(struct file *filp,
+       filp->f_dentry = dentry;
+       filp->f_uid    = current->fsuid;
+       filp->f_gid    = current->fsgid;
++      if (it)
++              filp->f_it = it;
+       filp->f_op     = dentry->d_inode->i_fop;
+       if (filp->f_op->open)
+               return filp->f_op->open(dentry->d_inode, filp);
+       else
+               return 0;
+ }
++EXPORT_SYMBOL(init_private_file_it);
++
++int init_private_file(struct file *filp, struct dentry *dentry, int mode)
++{
++      return init_private_file_it(filp, dentry, mode, NULL);
++}
+ void fput(struct file * file)
+ {
+--- linux-2.4.20-hp4-pnnl13/fs/inode.c~nfs_export_kernel-2.4.20-hp     2003-09-14 17:34:20.000000000 +0400
++++ linux-2.4.20-hp4-pnnl13-alexey/fs/inode.c  2003-10-08 11:38:11.000000000 +0400
+@@ -964,9 +964,10 @@ struct inode *igrab(struct inode *inode)
+       return inode;
+ }
+-struct inode *iget4_locked(struct super_block *sb, unsigned long ino, find_inode_t find_actor, void *opaque)
++struct inode *ifind(struct super_block *sb, unsigned long ino,
++                              struct list_head *head,
++                              find_inode_t find_actor, void *opaque)
+ {
+-      struct list_head * head = inode_hashtable + hash(sb,ino);
+       struct inode * inode;
+       spin_lock(&inode_lock);
+@@ -979,6 +980,24 @@ struct inode *iget4_locked(struct super_
+       }
+       spin_unlock(&inode_lock);
++      return NULL;
++}
++
++struct inode *ilookup4(struct super_block *sb, unsigned long ino,
++                       find_inode_t find_actor, void *opaque)
++{
++      struct list_head * head = inode_hashtable + hash(sb,ino);
++      return ifind(sb, ino, head, find_actor, opaque);
++}
++
++struct inode *iget4_locked(struct super_block *sb, unsigned long ino,
++                    find_inode_t find_actor, void *opaque)
++{
++      struct list_head * head = inode_hashtable + hash(sb,ino);
++      struct inode *inode = ifind(sb, ino, head, find_actor, opaque);
++      if (inode)
++              return inode;
++
+       /*
+        * get_new_inode() will do the right thing, re-trying the search
+        * in case it had to block at any point.
+--- linux-2.4.20-hp4-pnnl13/fs/Makefile~nfs_export_kernel-2.4.20-hp    2003-09-14 17:34:22.000000000 +0400
++++ linux-2.4.20-hp4-pnnl13-alexey/fs/Makefile 2003-10-08 10:54:37.000000000 +0400
+@@ -7,7 +7,8 @@
+ O_TARGET := fs.o
+-export-objs :=        filesystems.o open.o dcache.o buffer.o dquot.o inode.o
++export-objs :=        filesystems.o open.o dcache.o buffer.o dquot.o inode.o \
++              namei.o file_table.o
+ mod-subdirs :=        nls xfs
+ obj-y :=      open.o read_write.o devices.o file_table.o buffer.o \
+--- linux-2.4.20-hp4-pnnl13/fs/namei.c~nfs_export_kernel-2.4.20-hp     2003-09-14 17:34:20.000000000 +0400
++++ linux-2.4.20-hp4-pnnl13-alexey/fs/namei.c  2003-10-08 10:54:08.000000000 +0400
+@@ -22,6 +22,7 @@
+ #include <linux/dnotify.h>
+ #include <linux/smp_lock.h>
+ #include <linux/personality.h>
++#include <linux/module.h>
+ #include <asm/namei.h>
+ #include <asm/uaccess.h>
+@@ -100,6 +101,7 @@ void intent_release(struct lookup_intent
+               it->it_op_release(it);
+ }
++EXPORT_SYMBOL(intent_release);
+ /* In order to reduce some races, while at the same time doing additional
+  * checking and hopefully speeding things up, we copy filenames to the
+@@ -917,7 +919,8 @@ struct dentry * lookup_hash(struct qstr 
+ /* SMP-safe */
+-struct dentry * lookup_one_len(const char * name, struct dentry * base, int len)
++struct dentry * lookup_one_len_it(const char * name, struct dentry * base,
++                                  int len, struct lookup_intent *it)
+ {
+       unsigned long hash;
+       struct qstr this;
+@@ -937,11 +940,16 @@ struct dentry * lookup_one_len(const cha
+       }
+       this.hash = end_name_hash(hash);
+-      return lookup_hash_it(&this, base, NULL);
++      return lookup_hash_it(&this, base, it);
+ access:
+       return ERR_PTR(-EACCES);
+ }
++struct dentry * lookup_one_len(const char * name, struct dentry * base, int len)
++{
++      return lookup_one_len_it(name, base, len, NULL);
++}
++
+ /*
+  *    namei()
+  *
+--- linux-2.4.20-hp4-pnnl13/fs/nfsd/export.c~nfs_export_kernel-2.4.20-hp       2002-11-29 02:53:15.000000000 +0300
++++ linux-2.4.20-hp4-pnnl13-alexey/fs/nfsd/export.c    2003-10-08 10:54:08.000000000 +0400
+@@ -222,6 +222,11 @@ exp_export(struct nfsctl_export *nxp)
+       inode = nd.dentry->d_inode;
+       dev = inode->i_dev;
+       ino = inode->i_ino;
++      if ((inode->i_sb->s_type->fs_flags & FS_NFSEXP_FSID) &&
++          !(nxp->ex_flags & NFSEXP_FSID)) {
++          nxp->ex_dev = inode->i_sb->s_dev;
++          nxp->ex_flags |= NFSEXP_FSID;
++      }
+       err = -EINVAL;
+       exp = exp_get(clp, dev, ino);
+--- linux-2.4.20-hp4-pnnl13/fs/nfsd/nfsfh.c~nfs_export_kernel-2.4.20-hp        2002-11-29 02:53:15.000000000 +0300
++++ linux-2.4.20-hp4-pnnl13-alexey/fs/nfsd/nfsfh.c     2003-10-08 10:54:08.000000000 +0400
+@@ -36,6 +36,15 @@ struct nfsd_getdents_callback {
+       int sequence;           /* sequence counter */
+ };
++static struct dentry *lookup_it(struct inode *inode, struct dentry * dentry)
++{
++      if (inode->i_op->lookup_it)
++          return inode->i_op->lookup_it(inode, dentry, NULL, 0);
++      else
++          return inode->i_op->lookup(inode, dentry);
++              
++}
++
+ /*
+  * A rather strange filldir function to capture
+  * the name matching the specified inode number.
+@@ -75,6 +84,8 @@ static int nfsd_get_name(struct dentry *
+       int error;
+       struct file file;
+       struct nfsd_getdents_callback buffer;
++      struct lookup_intent it;
++      struct file *filp = NULL;
+       error = -ENOTDIR;
+       if (!dir || !S_ISDIR(dir->i_mode))
+@@ -85,9 +96,37 @@ static int nfsd_get_name(struct dentry *
+       /*
+        * Open the directory ...
+        */
+-      error = init_private_file(&file, dentry, FMODE_READ);
+-      if (error)
++      if (dentry->d_op && dentry->d_op->d_revalidate_it) {
++              if ((dentry->d_flags & DCACHE_NFSD_DISCONNECTED) &&
++                  (dentry->d_parent == dentry) ) {
++                      it.it_op_release = NULL;
++                      /* 
++                       * XXX Temporary Hack: Simulating init_private_file without
++                       * f_op->open for disconnected dentry Since we don't have actual
++                       * dentry->d_name to revalidate in revalidate_it()
++                       */
++                      filp = &file;
++                      memset(filp, 0, sizeof(*filp));
++                      filp->f_mode   = FMODE_READ;
++                      atomic_set(&filp->f_count, 1);
++                      filp->f_dentry = dentry;
++                      filp->f_uid = current->fsuid;
++                      filp->f_gid = current->fsgid;
++                      filp->f_op = dentry->d_inode->i_fop;
++                      error = 0;
++              } else {
++                      intent_init(&it, IT_OPEN, 0);
++                      error = revalidate_it(dentry, &it);
++                      if (error)
++                              goto out;
++                      error = init_private_file_it(&file, dentry, FMODE_READ, &it);
++              }
++      } else {
++              error = init_private_file_it(&file, dentry, FMODE_READ, NULL);
++      }
++      if (error) 
+               goto out;
++
+       error = -EINVAL;
+       if (!file.f_op->readdir)
+               goto out_close;
+@@ -113,9 +152,13 @@ static int nfsd_get_name(struct dentry *
+       }
+ out_close:
+-      if (file.f_op->release)
++      if (file.f_op->release && !filp)
+               file.f_op->release(dir, &file);
+ out:
++      if (dentry->d_op &&
++          dentry->d_op->d_revalidate_it &&
++          it.it_op_release && !filp)
++              intent_release(&it);
+       return error;
+ }
+@@ -274,7 +317,7 @@ struct dentry *nfsd_findparent(struct de
+        * it is well connected.  But nobody returns different dentrys do they?
+        */
+       down(&child->d_inode->i_sem);
+-      pdentry = child->d_inode->i_op->lookup(child->d_inode, tdentry);
++      pdentry = lookup_it(child->d_inode, tdentry);
+       up(&child->d_inode->i_sem);
+       d_drop(tdentry); /* we never want ".." hashed */
+       if (!pdentry && tdentry->d_inode == NULL) {
+@@ -306,6 +349,8 @@ struct dentry *nfsd_findparent(struct de
+                               igrab(tdentry->d_inode);
+                               pdentry->d_flags |= DCACHE_NFSD_DISCONNECTED;
+                       }
++                      if (child->d_op && child->d_op->d_revalidate_it)
++                              pdentry->d_op = child->d_op;
+               }
+               if (pdentry == NULL)
+                       pdentry = ERR_PTR(-ENOMEM);
+@@ -463,6 +508,8 @@ find_fh_dentry(struct super_block *sb, _
+               struct dentry *pdentry;
+               struct inode *parent;
++              if (result->d_op && result->d_op->d_revalidate_it)
++                      dentry->d_op = result->d_op;
+               pdentry = nfsd_findparent(dentry);
+               err = PTR_ERR(pdentry);
+               if (IS_ERR(pdentry))
+@@ -662,6 +709,11 @@ fh_verify(struct svc_rqst *rqstp, struct
+       inode = dentry->d_inode;
++      /* cache coherency for non-device filesystems */
++      if (inode->i_op && inode->i_op->revalidate_it) {
++          inode->i_op->revalidate_it(dentry, NULL);
++      }
++
+       /* Type check. The correct error return for type mismatches
+        * does not seem to be generally agreed upon. SunOS seems to
+        * use EISDIR if file isn't S_IFREG; a comment in the NFSv3
+@@ -900,8 +952,9 @@ out_negative:
+               dentry->d_parent->d_name.name, dentry->d_name.name);
+       goto out;
+ out_uptodate:
+-      printk(KERN_ERR "fh_update: %s/%s already up-to-date!\n",
+-              dentry->d_parent->d_name.name, dentry->d_name.name);
++      if(!dentry->d_parent->d_inode->i_op->mkdir_raw)
++              printk(KERN_ERR "fh_update: %s/%s already up-to-date!\n",
++                      dentry->d_parent->d_name.name, dentry->d_name.name);
+       goto out;
+ }
+--- linux-2.4.20-hp4-pnnl13/fs/nfsd/vfs.c~nfs_export_kernel-2.4.20-hp  2002-11-29 02:53:15.000000000 +0300
++++ linux-2.4.20-hp4-pnnl13-alexey/fs/nfsd/vfs.c       2003-10-08 10:54:08.000000000 +0400
+@@ -77,6 +77,128 @@ struct raparms {
+ static struct raparms *               raparml;
+ static struct raparms *               raparm_cache;
++static int link_raw(struct dentry *dold, struct dentry *ddir,
++                    struct dentry *dnew)
++{
++      int err;
++
++      struct nameidata old_nd = { .dentry = dold };
++      struct nameidata nd = { .dentry = ddir, .last = dnew->d_name };
++      struct inode_operations *op = nd.dentry->d_inode->i_op;
++      err = op->link_raw(&old_nd, &nd);
++      d_instantiate(dnew, dold->d_inode);
++      if(dold->d_inode->i_op && dold->d_inode->i_op->revalidate_it)
++              dold->d_inode->i_op->revalidate_it(dnew, NULL);
++
++      return err;
++}
++
++static int unlink_raw(struct dentry *dentry, char *fname, int flen,
++                      struct dentry *rdentry)
++{
++      int err;
++        struct qstr last = { .name = fname, .len = flen };
++      struct nameidata nd = { .dentry = dentry, .last = last };
++      struct inode_operations *op = nd.dentry->d_inode->i_op;
++      err = op->unlink_raw(&nd);
++      if (!err)
++              d_delete(rdentry);
++
++      return err;
++}
++
++static int rmdir_raw(struct dentry *dentry, char *fname, int flen,
++                     struct dentry *rdentry)
++{
++      int err;
++        struct qstr last = { .name = fname, .len = flen };
++      struct nameidata nd = { .dentry = dentry, .last = last };
++      struct inode_operations *op = nd.dentry->d_inode->i_op;
++      err = op->rmdir_raw(&nd);
++      if(!err) {
++              rdentry->d_inode->i_flags |= S_DEAD;
++              d_delete(rdentry);
++      }
++
++      return err;
++}
++
++static int symlink_raw(struct dentry *dentry,  char *fname, int flen,
++                       char *path)
++{
++      int err;
++        struct qstr last = { .name = fname, .len = flen };
++      struct nameidata nd = { .dentry = dentry, .last = last };
++      struct inode_operations *op = nd.dentry->d_inode->i_op;
++      err = op->symlink_raw(&nd, path);
++
++      return err;
++}
++
++static int mkdir_raw(struct dentry *dentry, char *fname, int flen, int mode)
++{
++      int err;
++        struct qstr last = { .name = fname, .len = flen };
++      struct nameidata nd = { .dentry = dentry, .last = last };
++      struct inode_operations *op = nd.dentry->d_inode->i_op;
++      err = op->mkdir_raw(&nd, mode);
++
++      return err;
++}
++
++static int mknod_raw(struct dentry *dentry, char *fname, int flen, int mode,
++                     dev_t dev)
++{
++      int err;
++        struct qstr last = { .name = fname, .len = flen };
++      struct nameidata nd = { .dentry = dentry, .last = last };
++      struct inode_operations *op = nd.dentry->d_inode->i_op;
++      err = op->mknod_raw(&nd, mode, dev);
++
++      return err;
++}     
++
++static int rename_raw(struct dentry *fdentry, struct dentry *tdentry,
++                      struct dentry *odentry, struct dentry *ndentry)
++{
++      int err;
++
++      struct nameidata old_nd = { .dentry = fdentry, .last = odentry->d_name};
++      struct nameidata new_nd = { .dentry = tdentry, .last = ndentry->d_name};
++      struct inode_operations *op = old_nd.dentry->d_inode->i_op;
++      err = op->rename_raw(&old_nd, &new_nd);
++      d_move(odentry, ndentry);
++
++      return err;
++}
++
++static int setattr_raw(struct inode *inode, struct iattr *iap)
++{
++      int err;
++
++      iap->ia_valid |= ATTR_RAW;
++      err = inode->i_op->setattr_raw(inode, iap);
++
++      return err;
++}
++
++int revalidate_it(struct dentry *dentry, struct lookup_intent *it)
++{
++      int err = 0;
++
++      if (dentry && dentry->d_op && dentry->d_op->d_revalidate_it) {
++              if (!dentry->d_op->d_revalidate_it(dentry, 0, it) &&
++                      !d_invalidate(dentry)) {
++                      dput(dentry);
++                      err = -EINVAL;
++                      dentry = NULL;
++                      return err;
++              }
++      }
++
++      return err;
++}
++
+ /*
+  * Look up one component of a pathname.
+  * N.B. After this call _both_ fhp and resfh need an fh_put
+@@ -300,7 +422,10 @@ nfsd_setattr(struct svc_rqst *rqstp, str
+       }
+       err = nfserr_notsync;
+       if (!check_guard || guardtime == inode->i_ctime) {
+-              err = notify_change(dentry, iap);
++              if ( dentry->d_inode->i_op && dentry->d_inode->i_op->setattr_raw)
++                      err = setattr_raw(dentry->d_inode, iap);
++              else
++                      err = notify_change(dentry, iap);
+               err = nfserrno(err);
+       }
+       if (size_change) {
+@@ -427,6 +552,7 @@ nfsd_open(struct svc_rqst *rqstp, struct
+ {
+       struct dentry   *dentry;
+       struct inode    *inode;
++      struct lookup_intent it;
+       int             err;
+       /* If we get here, then the client has already done an "open", and (hopefully)
+@@ -473,6 +599,14 @@ nfsd_open(struct svc_rqst *rqstp, struct
+               filp->f_mode  = FMODE_READ;
+       }
++      intent_init(&it, IT_OPEN, (filp->f_flags & ~O_ACCMODE) | filp->f_mode);
++
++      err = revalidate_it(dentry, &it);
++      if (err)
++              goto out_nfserr;
++      
++      filp->f_it = &it;
++      
+       err = 0;
+       if (filp->f_op && filp->f_op->open) {
+               err = filp->f_op->open(inode, filp);
+@@ -487,7 +621,11 @@ nfsd_open(struct svc_rqst *rqstp, struct
+                       atomic_dec(&filp->f_count);
+               }
+       }
++
+ out_nfserr:
++      if (it.it_op_release)
++              intent_release(&it);
++
+       if (err)
+               err = nfserrno(err);
+ out:
+@@ -818,7 +956,7 @@ nfsd_create(struct svc_rqst *rqstp, stru
+ {
+       struct dentry   *dentry, *dchild;
+       struct inode    *dirp;
+-      int             err;
++      int             err, error = -EOPNOTSUPP;
+       err = nfserr_perm;
+       if (!flen)
+@@ -834,20 +972,44 @@ nfsd_create(struct svc_rqst *rqstp, stru
+       dentry = fhp->fh_dentry;
+       dirp = dentry->d_inode;
++      switch (type) {
++                      case S_IFDIR:
++                              if (dirp->i_op->mkdir_raw)
++                          error = mkdir_raw(dentry, fname, flen, iap->ia_mode);
++                              break;
++                      case S_IFCHR:
++                      case S_IFBLK:
++                      case S_IFIFO:
++                      case S_IFSOCK:
++                      case S_IFREG:
++                          if (dirp->i_op->mknod_raw) {
++                                      if (type == S_IFREG)
++                                              rdev = 0;
++                                      error = mknod_raw(dentry, fname, flen, iap->ia_mode, rdev);
++                              }
++                              break;
++                              default:
++                      printk("nfsd: bad file type %o in nfsd_create\n", type);
++      }
++
+       err = nfserr_notdir;
+-      if(!dirp->i_op || !dirp->i_op->lookup)
++      if(!dirp->i_op || !(dirp->i_op->lookup || dirp->i_op->lookup_it))
+               goto out;
+       /*
+        * Check whether the response file handle has been verified yet.
+        * If it has, the parent directory should already be locked.
+        */
+-      if (!resfhp->fh_dentry) {
+-              /* called from nfsd_proc_mkdir, or possibly nfsd3_proc_create */
+-              fh_lock(fhp);
++      if (!resfhp->fh_dentry || dirp->i_op->lookup_it) {
++              /* called from nfsd_proc_mkdir, or possibly nfsd3_proc_create
++                 and nfsd_proc_create in case of lustre
++              */
++              if (!resfhp->fh_dentry)
++                      fh_lock(fhp);
+               dchild = lookup_one_len(fname, dentry, flen);
+               err = PTR_ERR(dchild);
+               if (IS_ERR(dchild))
+                       goto out_nfserr;
++              resfhp->fh_dentry = NULL;
+               err = fh_compose(resfhp, fhp->fh_export, dchild, fhp);
+               if (err)
+                       goto out;
+@@ -868,10 +1030,12 @@ nfsd_create(struct svc_rqst *rqstp, stru
+        * Make sure the child dentry is still negative ...
+        */
+       err = nfserr_exist;
+-      if (dchild->d_inode) {
+-              dprintk("nfsd_create: dentry %s/%s not negative!\n",
+-                      dentry->d_name.name, dchild->d_name.name);
+-              goto out; 
++      if ( error == -EOPNOTSUPP) {
++              if (dchild->d_inode) {
++                      dprintk("nfsd_create: dentry %s/%s not negative!\n",
++                              dentry->d_name.name, dchild->d_name.name);
++                      goto out; 
++              }
+       }
+       if (!(iap->ia_valid & ATTR_MODE))
+@@ -884,16 +1048,19 @@ nfsd_create(struct svc_rqst *rqstp, stru
+       err = nfserr_perm;
+       switch (type) {
+       case S_IFREG:
+-              err = vfs_create(dirp, dchild, iap->ia_mode);
++              if (error == -EOPNOTSUPP)
++                      err = vfs_create(dirp, dchild, iap->ia_mode);
+               break;
+       case S_IFDIR:
+-              err = vfs_mkdir(dirp, dchild, iap->ia_mode);
++              if (error == -EOPNOTSUPP)
++                      err = vfs_mkdir(dirp, dchild, iap->ia_mode);
+               break;
+       case S_IFCHR:
+       case S_IFBLK:
+       case S_IFIFO:
+       case S_IFSOCK:
+-              err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev);
++              if (error == -EOPNOTSUPP)       
++                      err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev);
+               break;
+       default:
+               printk("nfsd: bad file type %o in nfsd_create\n", type);
+@@ -962,7 +1129,13 @@ nfsd_create_v3(struct svc_rqst *rqstp, s
+       /* Get all the sanity checks out of the way before
+        * we lock the parent. */
+       err = nfserr_notdir;
+-      if(!dirp->i_op || !dirp->i_op->lookup)
++      if (dirp->i_op->mknod_raw) {
++              err = mknod_raw(dentry, fname, flen, iap->ia_mode, 0);
++              if (err && err != -EOPNOTSUPP)
++                      goto out;
++      }
++
++      if(!dirp->i_op ||  !(dirp->i_op->lookup || dirp->i_op->lookup_it))
+               goto out;
+       fh_lock(fhp);
+@@ -1013,6 +1186,8 @@ nfsd_create_v3(struct svc_rqst *rqstp, s
+               case NFS3_CREATE_GUARDED:
+                       err = nfserr_exist;
+               }
++              if(dirp->i_op->mknod_raw)
++                      err = 0;
+               goto out;
+       }
+@@ -1119,7 +1294,7 @@ nfsd_symlink(struct svc_rqst *rqstp, str
+                               struct iattr *iap)
+ {
+       struct dentry   *dentry, *dnew;
+-      int             err, cerr;
++      int             err, cerr, error = -EOPNOTSUPP;
+       err = nfserr_noent;
+       if (!flen || !plen)
+@@ -1133,12 +1308,18 @@ nfsd_symlink(struct svc_rqst *rqstp, str
+               goto out;
+       fh_lock(fhp);
+       dentry = fhp->fh_dentry;
++      
++      if (dentry->d_inode->i_op->symlink_raw)
++              error = symlink_raw(dentry, fname, flen, path);
++
+       dnew = lookup_one_len(fname, dentry, flen);
+       err = PTR_ERR(dnew);
+       if (IS_ERR(dnew))
+               goto out_nfserr;
+-      err = vfs_symlink(dentry->d_inode, dnew, path);
++      err = error;
++      if (err == -EOPNOTSUPP || !dentry->d_inode->i_op->symlink_raw)
++              err = vfs_symlink(dentry->d_inode, dnew, path);
+       if (!err) {
+               if (EX_ISSYNC(fhp->fh_export))
+                       nfsd_sync_dir(dentry);
+@@ -1148,7 +1329,10 @@ nfsd_symlink(struct svc_rqst *rqstp, str
+                               iap->ia_valid |= ATTR_CTIME;
+                               iap->ia_mode = (iap->ia_mode&S_IALLUGO)
+                                       | S_IFLNK;
+-                              err = notify_change(dnew, iap);
++                              if (dnew->d_inode->i_op && dnew->d_inode->i_op->setattr_raw)
++                                      err = setattr_raw(dnew->d_inode, iap);
++                              else
++                                      err = notify_change(dnew, iap);
+                               if (!err && EX_ISSYNC(fhp->fh_export))
+                                       write_inode_now(dentry->d_inode, 1);
+                      }
+@@ -1206,7 +1390,10 @@ nfsd_link(struct svc_rqst *rqstp, struct
+       dold = tfhp->fh_dentry;
+       dest = dold->d_inode;
+-      err = vfs_link(dold, dirp, dnew);
++      if (dirp->i_op->link_raw)
++              err = link_raw(dold, ddir, dnew);
++      else
++              err = vfs_link(dold, dirp, dnew);
+       if (!err) {
+               if (EX_ISSYNC(ffhp->fh_export)) {
+                       nfsd_sync_dir(ddir);
+@@ -1291,7 +1478,10 @@ nfsd_rename(struct svc_rqst *rqstp, stru
+                       err = nfserr_perm;
+       } else
+ #endif
+-      err = vfs_rename(fdir, odentry, tdir, ndentry);
++      if(fdir->i_op->rename_raw)
++              err = rename_raw(fdentry, tdentry, odentry, ndentry);
++      else
++              err = vfs_rename(fdir, odentry, tdir, ndentry);
+       if (!err && EX_ISSYNC(tfhp->fh_export)) {
+               nfsd_sync_dir(tdentry);
+               nfsd_sync_dir(fdentry);
+@@ -1312,7 +1502,7 @@ nfsd_rename(struct svc_rqst *rqstp, stru
+       fill_post_wcc(tfhp);
+       double_up(&tdir->i_sem, &fdir->i_sem);
+       ffhp->fh_locked = tfhp->fh_locked = 0;
+-      
++
+ out:
+       return err;
+ }
+@@ -1358,9 +1548,15 @@ nfsd_unlink(struct svc_rqst *rqstp, stru
+                       err = nfserr_perm;
+               } else
+ #endif
+-              err = vfs_unlink(dirp, rdentry);
++              if (dirp->i_op->unlink_raw)
++                      err = unlink_raw(dentry, fname, flen, rdentry);
++              else
++                      err = vfs_unlink(dirp, rdentry);
+       } else { /* It's RMDIR */
+-              err = vfs_rmdir(dirp, rdentry);
++              if (dirp->i_op->rmdir_raw)
++                      err = rmdir_raw(dentry, fname, flen, rdentry);
++              else
++                      err = vfs_rmdir(dirp, rdentry);
+       }
+       dput(rdentry);
+--- linux-2.4.20-hp4-pnnl13/include/linux/fs.h~nfs_export_kernel-2.4.20-hp     2003-09-14 17:34:24.000000000 +0400
++++ linux-2.4.20-hp4-pnnl13-alexey/include/linux/fs.h  2003-10-08 11:39:07.000000000 +0400
+@@ -93,6 +93,9 @@ extern int leases_enable, dir_notify_ena
+ #define FS_SINGLE     8 /* Filesystem that can have only one superblock */
+ #define FS_NOMOUNT    16 /* Never mount from userland */
+ #define FS_LITTER     32 /* Keeps the tree in dcache */
++#define FS_NFSEXP_FSID 64 /* Use file system specific fsid for
++                         * exporting non device filesystems.
++                         */
+ #define FS_ODD_RENAME 32768   /* Temporary stuff; will go away as soon
+                                 * as nfs_rename() will be cleaned up
+                                 */
+@@ -1116,6 +1119,9 @@ extern int open_namei_it(const char *fil
+                        struct nameidata *nd, struct lookup_intent *it);
+ extern struct file *dentry_open_it(struct dentry *dentry, struct vfsmount *mnt,
+                           int flags, struct lookup_intent *it);
++extern int revalidate_it(struct dentry *dentry, struct lookup_intent *it);
++extern int init_private_file_it(struct file *, struct dentry *dentry, int mode,
++                                struct lookup_intent *it);
+ extern int filp_close(struct file *, fl_owner_t id);
+ extern char * getname(const char *);
+@@ -1386,6 +1392,8 @@ extern void path_release(struct nameidat
+ extern int follow_down(struct vfsmount **, struct dentry **);
+ extern int follow_up(struct vfsmount **, struct dentry **);
+ extern struct dentry * lookup_one_len(const char *, struct dentry *, int);
++extern struct dentry * lookup_one_len_it(const char *, struct dentry *, int,
++                                         struct lookup_intent *);
+ extern struct dentry * lookup_hash(struct qstr *, struct dentry *);
+ #define user_path_walk(name,nd)        __user_walk(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, nd)
+ #define user_path_walk_link(name,nd) __user_walk(name, LOOKUP_POSITIVE, nd)
+@@ -1403,6 +1411,8 @@ typedef int (*find_inode_t)(struct inode
+ extern struct inode * iget4_locked(struct super_block *, unsigned long,
+                                  find_inode_t, void *);
++extern struct inode * ilookup4(struct super_block *, unsigned long,
++                               find_inode_t, void *);
+ static inline struct inode *iget4(struct super_block *sb, unsigned long ino,
+                                 find_inode_t find_actor, void *opaque)
+--- linux-2.4.20-hp4-pnnl13/kernel/ksyms.c~nfs_export_kernel-2.4.20-hp 2003-09-14 17:34:22.000000000 +0400
++++ linux-2.4.20-hp4-pnnl13-alexey/kernel/ksyms.c      2003-10-08 11:39:42.000000000 +0400
+@@ -169,6 +169,7 @@ EXPORT_SYMBOL(fget);
+ EXPORT_SYMBOL(igrab);
+ EXPORT_SYMBOL(iunique);
+ EXPORT_SYMBOL(iget4_locked);
++EXPORT_SYMBOL(ilookup4);
+ EXPORT_SYMBOL(unlock_new_inode);
+ EXPORT_SYMBOL(iput);
+ EXPORT_SYMBOL(inode_init_once);
+@@ -181,6 +182,7 @@ EXPORT_SYMBOL(path_walk);
+ EXPORT_SYMBOL(path_release);
+ EXPORT_SYMBOL(__user_walk);
+ EXPORT_SYMBOL(lookup_one_len);
++EXPORT_SYMBOL(lookup_one_len_it);
+ EXPORT_SYMBOL(lookup_hash);
+ EXPORT_SYMBOL(sys_close);
+ EXPORT_SYMBOL(dcache_lock);
+
+_
diff --git a/lustre/kernel_patches/patches/nfs_export_kernel-2.4.20-rh.patch b/lustre/kernel_patches/patches/nfs_export_kernel-2.4.20-rh.patch
new file mode 100644 (file)
index 0000000..8ae5b78
--- /dev/null
@@ -0,0 +1,741 @@
+ fs/Makefile        |    3 
+ fs/file_table.c    |   11 ++
+ fs/inode.c         |   23 ++++-
+ fs/namei.c         |   12 ++
+ fs/nfsd/export.c   |    5 +
+ fs/nfsd/nfsfh.c    |   65 +++++++++++++-
+ fs/nfsd/vfs.c      |  240 ++++++++++++++++++++++++++++++++++++++++++++++++-----
+ include/linux/fs.h |   10 ++
+ kernel/ksyms.c     |    2 
+ 9 files changed, 337 insertions(+), 34 deletions(-)
+
+--- linux-2.4.20-rh-20.9/fs/file_table.c~nfs_export_kernel-2.4.20-rh   2002-11-29 02:53:15.000000000 +0300
++++ linux-2.4.20-rh-20.9-alexey/fs/file_table.c        2003-10-08 10:48:38.000000000 +0400
+@@ -82,7 +82,8 @@ struct file * get_empty_filp(void)
+  * and call the open function (if any).  The caller must verify that
+  * inode->i_fop is not NULL.
+  */
+-int init_private_file(struct file *filp, struct dentry *dentry, int mode)
++int init_private_file_it(struct file *filp, struct dentry *dentry, int mode,
++                         struct lookup_intent *it)
+ {
+       memset(filp, 0, sizeof(*filp));
+       filp->f_mode   = mode;
+@@ -90,12 +91,20 @@ int init_private_file(struct file *filp,
+       filp->f_dentry = dentry;
+       filp->f_uid    = current->fsuid;
+       filp->f_gid    = current->fsgid;
++      if (it)
++              filp->f_it = it;
+       filp->f_op     = dentry->d_inode->i_fop;
+       if (filp->f_op->open)
+               return filp->f_op->open(dentry->d_inode, filp);
+       else
+               return 0;
+ }
++EXPORT_SYMBOL(init_private_file_it);
++
++int init_private_file(struct file *filp, struct dentry *dentry, int mode)
++{
++      return init_private_file_it(filp, dentry, mode, NULL);
++}
+ void fput(struct file * file)
+ {
+--- linux-2.4.20-rh-20.9/fs/inode.c~nfs_export_kernel-2.4.20-rh        2003-09-14 17:35:22.000000000 +0400
++++ linux-2.4.20-rh-20.9-alexey/fs/inode.c     2003-10-08 10:48:38.000000000 +0400
+@@ -1063,9 +1063,10 @@ struct inode *igrab(struct inode *inode)
+ }
+-struct inode *iget4(struct super_block *sb, unsigned long ino, find_inode_t find_actor, void *opaque)
++static inline struct inode *ifind(struct super_block *sb, unsigned long ino,
++                                  struct list_head *head,
++                                  find_inode_t find_actor, void *opaque)
+ {
+-      struct list_head * head = inode_hashtable + hash(sb,ino);
+       struct inode * inode;
+       spin_lock(&inode_lock);
+@@ -1078,6 +1079,24 @@ struct inode *iget4(struct super_block *
+       }
+       spin_unlock(&inode_lock);
++      return NULL;
++}
++
++struct inode *ilookup4(struct super_block *sb, unsigned long ino,
++                       find_inode_t find_actor, void *opaque)
++{
++      struct list_head * head = inode_hashtable + hash(sb,ino);
++      return ifind(sb, ino, head, find_actor, opaque);
++}
++
++struct inode *iget4(struct super_block *sb, unsigned long ino,
++                    find_inode_t find_actor, void *opaque)
++{
++      struct list_head * head = inode_hashtable + hash(sb,ino);
++      struct inode *inode = ifind(sb, ino, head, find_actor, opaque);
++      if (inode)
++              return inode;
++
+       /*
+        * get_new_inode() will do the right thing, re-trying the search
+        * in case it had to block at any point.
+--- linux-2.4.20-rh-20.9/fs/Makefile~nfs_export_kernel-2.4.20-rh       2003-09-14 17:35:20.000000000 +0400
++++ linux-2.4.20-rh-20.9-alexey/fs/Makefile    2003-10-08 10:49:33.000000000 +0400
+@@ -9,7 +9,8 @@
+ O_TARGET := fs.o
+-export-objs :=        filesystems.o open.o dcache.o buffer.o dquot.o dcookies.o inode.o
++export-objs :=        filesystems.o open.o dcache.o buffer.o dquot.o dcookies.o inode.o \
++              namei.o file_table.o
+ mod-subdirs :=        nls
+ obj-y :=      open.o read_write.o devices.o file_table.o buffer.o \
+--- linux-2.4.20-rh-20.9/fs/namei.c~nfs_export_kernel-2.4.20-rh        2003-09-14 17:35:22.000000000 +0400
++++ linux-2.4.20-rh-20.9-alexey/fs/namei.c     2003-10-08 10:48:38.000000000 +0400
+@@ -22,6 +22,7 @@
+ #include <linux/dnotify.h>
+ #include <linux/smp_lock.h>
+ #include <linux/personality.h>
++#include <linux/module.h>
+ #include <asm/namei.h>
+ #include <asm/uaccess.h>
+@@ -100,6 +101,7 @@ void intent_release(struct lookup_intent
+               it->it_op_release(it);
+ }
++EXPORT_SYMBOL(intent_release);
+ static void *lock_dir(struct inode *dir, struct qstr *name)
+ {
+@@ -959,7 +961,8 @@ struct dentry * lookup_hash(struct qstr 
+ /* SMP-safe */
+-struct dentry * lookup_one_len(const char * name, struct dentry * base, int len)
++struct dentry * lookup_one_len_it(const char * name, struct dentry * base,
++                                  int len, struct lookup_intent *it)
+ {
+       unsigned long hash;
+       struct qstr this;
+@@ -979,11 +982,16 @@ struct dentry * lookup_one_len(const cha
+       }
+       this.hash = end_name_hash(hash);
+-      return lookup_hash_it(&this, base, NULL);
++      return lookup_hash_it(&this, base, it);
+ access:
+       return ERR_PTR(-EACCES);
+ }
++struct dentry * lookup_one_len(const char * name, struct dentry * base, int len)
++{
++      return lookup_one_len_it(name, base, len, NULL);
++}
++
+ /*
+  *    namei()
+  *
+--- linux-2.4.20-rh-20.9/fs/nfsd/export.c~nfs_export_kernel-2.4.20-rh  2003-09-13 19:34:35.000000000 +0400
++++ linux-2.4.20-rh-20.9-alexey/fs/nfsd/export.c       2003-10-08 10:48:38.000000000 +0400
+@@ -222,6 +222,11 @@ exp_export(struct nfsctl_export *nxp)
+       inode = nd.dentry->d_inode;
+       dev = inode->i_dev;
+       ino = inode->i_ino;
++      if ((inode->i_sb->s_type->fs_flags & FS_NFSEXP_FSID) &&
++          !(nxp->ex_flags & NFSEXP_FSID)) {
++          nxp->ex_dev = inode->i_sb->s_dev;
++          nxp->ex_flags |= NFSEXP_FSID;
++      }
+       err = -EINVAL;
+       exp = exp_get(clp, dev, ino);
+--- linux-2.4.20-rh-20.9/fs/nfsd/nfsfh.c~nfs_export_kernel-2.4.20-rh   2003-09-13 19:34:15.000000000 +0400
++++ linux-2.4.20-rh-20.9-alexey/fs/nfsd/nfsfh.c        2003-10-08 10:48:38.000000000 +0400
+@@ -36,6 +36,15 @@ struct nfsd_getdents_callback {
+       int sequence;           /* sequence counter */
+ };
++static struct dentry *lookup_it(struct inode *inode, struct dentry * dentry)
++{
++      if (inode->i_op->lookup_it)
++          return inode->i_op->lookup_it(inode, dentry, NULL, 0);
++      else
++          return inode->i_op->lookup(inode, dentry);
++              
++}
++
+ /*
+  * A rather strange filldir function to capture
+  * the name matching the specified inode number.
+@@ -75,6 +84,8 @@ static int nfsd_get_name(struct dentry *
+       int error;
+       struct file file;
+       struct nfsd_getdents_callback buffer;
++      struct lookup_intent it;
++      struct file *filp = NULL;
+       error = -ENOTDIR;
+       if (!dir || !S_ISDIR(dir->i_mode))
+@@ -85,9 +96,37 @@ static int nfsd_get_name(struct dentry *
+       /*
+        * Open the directory ...
+        */
+-      error = init_private_file(&file, dentry, FMODE_READ);
+-      if (error)
++      if (dentry->d_op && dentry->d_op->d_revalidate_it) {
++              if ((dentry->d_flags & DCACHE_NFSD_DISCONNECTED) &&
++                  (dentry->d_parent == dentry) ) {
++                      it.it_op_release = NULL;
++                      /* 
++                       * XXX Temporary Hack: Simulating init_private_file without
++                       * f_op->open for disconnected dentry Since we don't have actual
++                       * dentry->d_name to revalidate in revalidate_it()
++                       */
++                      filp = &file;
++                      memset(filp, 0, sizeof(*filp));
++                      filp->f_mode   = FMODE_READ;
++                      atomic_set(&filp->f_count, 1);
++                      filp->f_dentry = dentry;
++                      filp->f_uid = current->fsuid;
++                      filp->f_gid = current->fsgid;
++                      filp->f_op = dentry->d_inode->i_fop;
++                      error = 0;
++              } else {
++                      intent_init(&it, IT_OPEN, 0);
++                      error = revalidate_it(dentry, &it);
++                      if (error)
++                              goto out;
++                      error = init_private_file_it(&file, dentry, FMODE_READ, &it);
++              }
++      } else {
++              error = init_private_file_it(&file, dentry, FMODE_READ, NULL);
++      }
++      if (error) 
+               goto out;
++
+       error = -EINVAL;
+       if (!file.f_op->readdir)
+               goto out_close;
+@@ -113,9 +152,13 @@ static int nfsd_get_name(struct dentry *
+       }
+ out_close:
+-      if (file.f_op->release)
++      if (file.f_op->release && !filp)
+               file.f_op->release(dir, &file);
+ out:
++      if (dentry->d_op &&
++          dentry->d_op->d_revalidate_it &&
++          it.it_op_release && !filp)
++              intent_release(&it);
+       return error;
+ }
+@@ -274,7 +317,7 @@ struct dentry *nfsd_findparent(struct de
+        * it is well connected.  But nobody returns different dentrys do they?
+        */
+       down(&child->d_inode->i_sem);
+-      pdentry = child->d_inode->i_op->lookup(child->d_inode, tdentry);
++      pdentry = lookup_it(child->d_inode, tdentry);
+       up(&child->d_inode->i_sem);
+       d_drop(tdentry); /* we never want ".." hashed */
+       if (!pdentry && tdentry->d_inode == NULL) {
+@@ -306,6 +349,8 @@ struct dentry *nfsd_findparent(struct de
+                               igrab(tdentry->d_inode);
+                               pdentry->d_flags |= DCACHE_NFSD_DISCONNECTED;
+                       }
++                      if (child->d_op && child->d_op->d_revalidate_it)
++                              pdentry->d_op = child->d_op;
+               }
+               if (pdentry == NULL)
+                       pdentry = ERR_PTR(-ENOMEM);
+@@ -463,6 +508,8 @@ find_fh_dentry(struct super_block *sb, _
+               struct dentry *pdentry;
+               struct inode *parent;
++              if (result->d_op && result->d_op->d_revalidate_it)
++                      dentry->d_op = result->d_op;
+               pdentry = nfsd_findparent(dentry);
+               err = PTR_ERR(pdentry);
+               if (IS_ERR(pdentry))
+@@ -669,6 +716,11 @@ fh_verify(struct svc_rqst *rqstp, struct
+       inode = dentry->d_inode;
++      /* cache coherency for non-device filesystems */
++      if (inode->i_op && inode->i_op->revalidate_it) {
++          inode->i_op->revalidate_it(dentry, NULL);
++      }
++
+       /* Type check. The correct error return for type mismatches
+        * does not seem to be generally agreed upon. SunOS seems to
+        * use EISDIR if file isn't S_IFREG; a comment in the NFSv3
+@@ -912,8 +964,9 @@ out_negative:
+               dentry->d_parent->d_name.name, dentry->d_name.name);
+       goto out;
+ out_uptodate:
+-      printk(KERN_ERR "fh_update: %s/%s already up-to-date!\n",
+-              dentry->d_parent->d_name.name, dentry->d_name.name);
++      if(!dentry->d_parent->d_inode->i_op->mkdir_raw)
++              printk(KERN_ERR "fh_update: %s/%s already up-to-date!\n",
++                      dentry->d_parent->d_name.name, dentry->d_name.name);
+       goto out;
+ }
+--- linux-2.4.20-rh-20.9/fs/nfsd/vfs.c~nfs_export_kernel-2.4.20-rh     2003-09-13 19:34:15.000000000 +0400
++++ linux-2.4.20-rh-20.9-alexey/fs/nfsd/vfs.c  2003-10-08 10:48:38.000000000 +0400
+@@ -77,6 +77,128 @@ struct raparms {
+ static struct raparms *               raparml;
+ static struct raparms *               raparm_cache;
++static int link_raw(struct dentry *dold, struct dentry *ddir,
++                    struct dentry *dnew)
++{
++      int err;
++
++      struct nameidata old_nd = { .dentry = dold };
++      struct nameidata nd = { .dentry = ddir, .last = dnew->d_name };
++      struct inode_operations *op = nd.dentry->d_inode->i_op;
++      err = op->link_raw(&old_nd, &nd);
++      d_instantiate(dnew, dold->d_inode);
++      if(dold->d_inode->i_op && dold->d_inode->i_op->revalidate_it)
++              dold->d_inode->i_op->revalidate_it(dnew, NULL);
++
++      return err;
++}
++
++static int unlink_raw(struct dentry *dentry, char *fname, int flen,
++                      struct dentry *rdentry)
++{
++      int err;
++        struct qstr last = { .name = fname, .len = flen };
++      struct nameidata nd = { .dentry = dentry, .last = last };
++      struct inode_operations *op = nd.dentry->d_inode->i_op;
++      err = op->unlink_raw(&nd);
++      if (!err)
++              d_delete(rdentry);
++
++      return err;
++}
++
++static int rmdir_raw(struct dentry *dentry, char *fname, int flen,
++                     struct dentry *rdentry)
++{
++      int err;
++        struct qstr last = { .name = fname, .len = flen };
++      struct nameidata nd = { .dentry = dentry, .last = last };
++      struct inode_operations *op = nd.dentry->d_inode->i_op;
++      err = op->rmdir_raw(&nd);
++      if(!err) {
++              rdentry->d_inode->i_flags |= S_DEAD;
++              d_delete(rdentry);
++      }
++
++      return err;
++}
++
++static int symlink_raw(struct dentry *dentry,  char *fname, int flen,
++                       char *path)
++{
++      int err;
++        struct qstr last = { .name = fname, .len = flen };
++      struct nameidata nd = { .dentry = dentry, .last = last };
++      struct inode_operations *op = nd.dentry->d_inode->i_op;
++      err = op->symlink_raw(&nd, path);
++
++      return err;
++}
++
++static int mkdir_raw(struct dentry *dentry, char *fname, int flen, int mode)
++{
++      int err;
++        struct qstr last = { .name = fname, .len = flen };
++      struct nameidata nd = { .dentry = dentry, .last = last };
++      struct inode_operations *op = nd.dentry->d_inode->i_op;
++      err = op->mkdir_raw(&nd, mode);
++
++      return err;
++}
++
++static int mknod_raw(struct dentry *dentry, char *fname, int flen, int mode,
++                     dev_t dev)
++{
++      int err;
++        struct qstr last = { .name = fname, .len = flen };
++      struct nameidata nd = { .dentry = dentry, .last = last };
++      struct inode_operations *op = nd.dentry->d_inode->i_op;
++      err = op->mknod_raw(&nd, mode, dev);
++
++      return err;
++}     
++
++static int rename_raw(struct dentry *fdentry, struct dentry *tdentry,
++                      struct dentry *odentry, struct dentry *ndentry)
++{
++      int err;
++
++      struct nameidata old_nd = { .dentry = fdentry, .last = odentry->d_name};
++      struct nameidata new_nd = { .dentry = tdentry, .last = ndentry->d_name};
++      struct inode_operations *op = old_nd.dentry->d_inode->i_op;
++      err = op->rename_raw(&old_nd, &new_nd);
++      d_move(odentry, ndentry);
++
++      return err;
++}
++
++static int setattr_raw(struct inode *inode, struct iattr *iap)
++{
++      int err;
++
++      iap->ia_valid |= ATTR_RAW;
++      err = inode->i_op->setattr_raw(inode, iap);
++
++      return err;
++}
++
++int revalidate_it(struct dentry *dentry, struct lookup_intent *it)
++{
++      int err = 0;
++
++      if (dentry && dentry->d_op && dentry->d_op->d_revalidate_it) {
++              if (!dentry->d_op->d_revalidate_it(dentry, 0, it) &&
++                      !d_invalidate(dentry)) {
++                      dput(dentry);
++                      err = -EINVAL;
++                      dentry = NULL;
++                      return err;
++              }
++      }
++
++      return err;
++}
++
+ /*
+  * Look up one component of a pathname.
+  * N.B. After this call _both_ fhp and resfh need an fh_put
+@@ -302,7 +424,10 @@ nfsd_setattr(struct svc_rqst *rqstp, str
+       }
+       err = nfserr_notsync;
+       if (!check_guard || guardtime == inode->i_ctime) {
+-              err = notify_change(dentry, iap);
++              if ( dentry->d_inode->i_op && dentry->d_inode->i_op->setattr_raw)
++                      err = setattr_raw(dentry->d_inode, iap);
++              else
++                      err = notify_change(dentry, iap);
+               err = nfserrno(err);
+       }
+       if (size_change) {
+@@ -429,6 +554,7 @@ nfsd_open(struct svc_rqst *rqstp, struct
+ {
+       struct dentry   *dentry;
+       struct inode    *inode;
++      struct lookup_intent it;
+       int             err;
+       /* If we get here, then the client has already done an "open", and (hopefully)
+@@ -475,6 +601,14 @@ nfsd_open(struct svc_rqst *rqstp, struct
+               filp->f_mode  = FMODE_READ;
+       }
++      intent_init(&it, IT_OPEN, (filp->f_flags & ~O_ACCMODE) | filp->f_mode);
++
++      err = revalidate_it(dentry, &it);
++      if (err)
++              goto out_nfserr;
++      
++      filp->f_it = &it;
++      
+       err = 0;
+       if (filp->f_op && filp->f_op->open) {
+               err = filp->f_op->open(inode, filp);
+@@ -489,7 +623,11 @@ nfsd_open(struct svc_rqst *rqstp, struct
+                       atomic_dec(&filp->f_count);
+               }
+       }
++
+ out_nfserr:
++      if (it.it_op_release)
++              intent_release(&it);
++
+       if (err)
+               err = nfserrno(err);
+ out:
+@@ -820,7 +958,7 @@ nfsd_create(struct svc_rqst *rqstp, stru
+ {
+       struct dentry   *dentry, *dchild;
+       struct inode    *dirp;
+-      int             err;
++      int             err, error = -EOPNOTSUPP;
+       err = nfserr_perm;
+       if (!flen)
+@@ -836,20 +974,44 @@ nfsd_create(struct svc_rqst *rqstp, stru
+       dentry = fhp->fh_dentry;
+       dirp = dentry->d_inode;
++      switch (type) {
++                      case S_IFDIR:
++                              if (dirp->i_op->mkdir_raw)
++                          error = mkdir_raw(dentry, fname, flen, iap->ia_mode);
++                              break;
++                      case S_IFCHR:
++                      case S_IFBLK:
++                      case S_IFIFO:
++                      case S_IFSOCK:
++                      case S_IFREG:
++                          if (dirp->i_op->mknod_raw) {
++                                      if (type == S_IFREG)
++                                              rdev = 0;
++                                      error = mknod_raw(dentry, fname, flen, iap->ia_mode, rdev);
++                              }
++                              break;
++                              default:
++                      printk("nfsd: bad file type %o in nfsd_create\n", type);
++      }
++
+       err = nfserr_notdir;
+-      if(!dirp->i_op || !dirp->i_op->lookup)
++      if(!dirp->i_op || !(dirp->i_op->lookup || dirp->i_op->lookup_it))
+               goto out;
+       /*
+        * Check whether the response file handle has been verified yet.
+        * If it has, the parent directory should already be locked.
+        */
+-      if (!resfhp->fh_dentry) {
+-              /* called from nfsd_proc_mkdir, or possibly nfsd3_proc_create */
+-              fh_lock(fhp);
++      if (!resfhp->fh_dentry || dirp->i_op->lookup_it) {
++              /* called from nfsd_proc_mkdir, or possibly nfsd3_proc_create
++                 and nfsd_proc_create in case of lustre
++              */
++              if (!resfhp->fh_dentry)
++                      fh_lock(fhp);
+               dchild = lookup_one_len(fname, dentry, flen);
+               err = PTR_ERR(dchild);
+               if (IS_ERR(dchild))
+                       goto out_nfserr;
++              resfhp->fh_dentry = NULL;
+               err = fh_compose(resfhp, fhp->fh_export, dchild, fhp);
+               if (err)
+                       goto out;
+@@ -870,10 +1032,12 @@ nfsd_create(struct svc_rqst *rqstp, stru
+        * Make sure the child dentry is still negative ...
+        */
+       err = nfserr_exist;
+-      if (dchild->d_inode) {
+-              dprintk("nfsd_create: dentry %s/%s not negative!\n",
+-                      dentry->d_name.name, dchild->d_name.name);
+-              goto out; 
++      if ( error == -EOPNOTSUPP) {
++              if (dchild->d_inode) {
++                      dprintk("nfsd_create: dentry %s/%s not negative!\n",
++                              dentry->d_name.name, dchild->d_name.name);
++                      goto out; 
++              }
+       }
+       if (!(iap->ia_valid & ATTR_MODE))
+@@ -886,16 +1050,19 @@ nfsd_create(struct svc_rqst *rqstp, stru
+       err = nfserr_perm;
+       switch (type) {
+       case S_IFREG:
+-              err = vfs_create(dirp, dchild, iap->ia_mode);
++              if (error == -EOPNOTSUPP)
++                      err = vfs_create(dirp, dchild, iap->ia_mode);
+               break;
+       case S_IFDIR:
+-              err = vfs_mkdir(dirp, dchild, iap->ia_mode);
++              if (error == -EOPNOTSUPP)
++                      err = vfs_mkdir(dirp, dchild, iap->ia_mode);
+               break;
+       case S_IFCHR:
+       case S_IFBLK:
+       case S_IFIFO:
+       case S_IFSOCK:
+-              err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev);
++              if (error == -EOPNOTSUPP)       
++                      err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev);
+               break;
+       default:
+               printk("nfsd: bad file type %o in nfsd_create\n", type);
+@@ -964,7 +1131,13 @@ nfsd_create_v3(struct svc_rqst *rqstp, s
+       /* Get all the sanity checks out of the way before
+        * we lock the parent. */
+       err = nfserr_notdir;
+-      if(!dirp->i_op || !dirp->i_op->lookup)
++      if (dirp->i_op->mknod_raw) {
++              err = mknod_raw(dentry, fname, flen, iap->ia_mode, 0);
++              if (err && err != -EOPNOTSUPP)
++                      goto out;
++      }
++
++      if(!dirp->i_op ||  !(dirp->i_op->lookup || dirp->i_op->lookup_it))
+               goto out;
+       fh_lock(fhp);
+@@ -1015,6 +1188,8 @@ nfsd_create_v3(struct svc_rqst *rqstp, s
+               case NFS3_CREATE_GUARDED:
+                       err = nfserr_exist;
+               }
++              if(dirp->i_op->mknod_raw)
++                      err = 0;
+               goto out;
+       }
+@@ -1121,7 +1296,7 @@ nfsd_symlink(struct svc_rqst *rqstp, str
+                               struct iattr *iap)
+ {
+       struct dentry   *dentry, *dnew;
+-      int             err, cerr;
++      int             err, cerr, error = -EOPNOTSUPP;
+       err = nfserr_noent;
+       if (!flen || !plen)
+@@ -1135,12 +1310,18 @@ nfsd_symlink(struct svc_rqst *rqstp, str
+               goto out;
+       fh_lock(fhp);
+       dentry = fhp->fh_dentry;
++      
++      if (dentry->d_inode->i_op->symlink_raw)
++              error = symlink_raw(dentry, fname, flen, path);
++
+       dnew = lookup_one_len(fname, dentry, flen);
+       err = PTR_ERR(dnew);
+       if (IS_ERR(dnew))
+               goto out_nfserr;
+-      err = vfs_symlink(dentry->d_inode, dnew, path);
++      err = error;
++      if (err == -EOPNOTSUPP || !dentry->d_inode->i_op->symlink_raw)
++              err = vfs_symlink(dentry->d_inode, dnew, path);
+       if (!err) {
+               if (EX_ISSYNC(fhp->fh_export))
+                       nfsd_sync_dir(dentry);
+@@ -1150,7 +1331,10 @@ nfsd_symlink(struct svc_rqst *rqstp, str
+                               iap->ia_valid |= ATTR_CTIME;
+                               iap->ia_mode = (iap->ia_mode&S_IALLUGO)
+                                       | S_IFLNK;
+-                              err = notify_change(dnew, iap);
++                              if (dnew->d_inode->i_op && dnew->d_inode->i_op->setattr_raw)
++                                      err = setattr_raw(dnew->d_inode, iap);
++                              else
++                                      err = notify_change(dnew, iap);
+                               if (!err && EX_ISSYNC(fhp->fh_export))
+                                       write_inode_now(dentry->d_inode, 1);
+                      }
+@@ -1208,7 +1392,10 @@ nfsd_link(struct svc_rqst *rqstp, struct
+       dold = tfhp->fh_dentry;
+       dest = dold->d_inode;
+-      err = vfs_link(dold, dirp, dnew);
++      if (dirp->i_op->link_raw)
++              err = link_raw(dold, ddir, dnew);
++      else
++              err = vfs_link(dold, dirp, dnew);
+       if (!err) {
+               if (EX_ISSYNC(ffhp->fh_export)) {
+                       nfsd_sync_dir(ddir);
+@@ -1293,7 +1480,10 @@ nfsd_rename(struct svc_rqst *rqstp, stru
+                       err = nfserr_perm;
+       } else
+ #endif
+-      err = vfs_rename(fdir, odentry, tdir, ndentry);
++      if(fdir->i_op->rename_raw)
++              err = rename_raw(fdentry, tdentry, odentry, ndentry);
++      else
++              err = vfs_rename(fdir, odentry, tdir, ndentry);
+       if (!err && EX_ISSYNC(tfhp->fh_export)) {
+               nfsd_sync_dir(tdentry);
+               nfsd_sync_dir(fdentry);
+@@ -1314,7 +1504,7 @@ nfsd_rename(struct svc_rqst *rqstp, stru
+       fill_post_wcc(tfhp);
+       double_up(&tdir->i_sem, &fdir->i_sem);
+       ffhp->fh_locked = tfhp->fh_locked = 0;
+-      
++
+ out:
+       return err;
+ }
+@@ -1360,9 +1550,15 @@ nfsd_unlink(struct svc_rqst *rqstp, stru
+                       err = nfserr_perm;
+               } else
+ #endif
+-              err = vfs_unlink(dirp, rdentry);
++              if (dirp->i_op->unlink_raw)
++                      err = unlink_raw(dentry, fname, flen, rdentry);
++              else
++                      err = vfs_unlink(dirp, rdentry);
+       } else { /* It's RMDIR */
+-              err = vfs_rmdir(dirp, rdentry);
++              if (dirp->i_op->rmdir_raw)
++                      err = rmdir_raw(dentry, fname, flen, rdentry);
++              else
++                      err = vfs_rmdir(dirp, rdentry);
+       }
+       dput(rdentry);
+--- linux-2.4.20-rh-20.9/include/linux/fs.h~nfs_export_kernel-2.4.20-rh        2003-09-14 17:35:22.000000000 +0400
++++ linux-2.4.20-rh-20.9-alexey/include/linux/fs.h     2003-10-08 10:48:38.000000000 +0400
+@@ -94,6 +94,9 @@ extern int leases_enable, dir_notify_ena
+ #define FS_SINGLE     8 /* Filesystem that can have only one superblock */
+ #define FS_NOMOUNT    16 /* Never mount from userland */
+ #define FS_LITTER     32 /* Keeps the tree in dcache */
++#define FS_NFSEXP_FSID 64 /* Use file system specific fsid for
++                         * exporting non device filesystems.
++                         */
+ #define FS_ODD_RENAME 32768   /* Temporary stuff; will go away as soon
+                                 * as nfs_rename() will be cleaned up
+                                 */
+@@ -1124,6 +1127,9 @@ extern int open_namei_it(const char *fil
+                        struct nameidata *nd, struct lookup_intent *it);
+ extern struct file *dentry_open_it(struct dentry *dentry, struct vfsmount *mnt,
+                           int flags, struct lookup_intent *it);
++extern int revalidate_it(struct dentry *dentry, struct lookup_intent *it);
++extern int init_private_file_it(struct file *, struct dentry *dentry, int mode,
++                                struct lookup_intent *it);
+ extern int filp_close(struct file *, fl_owner_t id);
+ extern char * getname(const char *);
+@@ -1423,6 +1429,8 @@ extern void path_release(struct nameidat
+ extern int follow_down(struct vfsmount **, struct dentry **);
+ extern int follow_up(struct vfsmount **, struct dentry **);
+ extern struct dentry * lookup_one_len(const char *, struct dentry *, int);
++extern struct dentry * lookup_one_len_it(const char *, struct dentry *, int,
++                                         struct lookup_intent *);
+ extern struct dentry * lookup_hash(struct qstr *, struct dentry *);
+ #define user_path_walk(name,nd)        __user_walk(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, nd)
+ #define user_path_walk_link(name,nd) __user_walk(name, LOOKUP_POSITIVE, nd)
+@@ -1439,6 +1447,8 @@ extern ino_t iunique(struct super_block 
+ typedef int (*find_inode_t)(struct inode *, unsigned long, void *);
+ extern struct inode * iget4(struct super_block *, unsigned long, find_inode_t, void *);
++extern struct inode * ilookup4(struct super_block *, unsigned long,
++                               find_inode_t, void *);
+ static inline struct inode *iget(struct super_block *sb, unsigned long ino)
+ {
+       return iget4(sb, ino, NULL, NULL);
+--- linux-2.4.20-rh-20.9/kernel/ksyms.c~nfs_export_kernel-2.4.20-rh    2003-09-14 17:35:20.000000000 +0400
++++ linux-2.4.20-rh-20.9-alexey/kernel/ksyms.c 2003-10-08 10:48:38.000000000 +0400
+@@ -164,6 +164,7 @@ EXPORT_SYMBOL(fget);
+ EXPORT_SYMBOL(igrab);
+ EXPORT_SYMBOL(iunique);
+ EXPORT_SYMBOL(iget4);
++EXPORT_SYMBOL(ilookup4);
+ EXPORT_SYMBOL(iput);
+ EXPORT_SYMBOL(inode_init_once);
+ EXPORT_SYMBOL(force_delete);
+@@ -175,6 +176,7 @@ EXPORT_SYMBOL(path_walk);
+ EXPORT_SYMBOL(path_release);
+ EXPORT_SYMBOL(__user_walk);
+ EXPORT_SYMBOL(lookup_one_len);
++EXPORT_SYMBOL(lookup_one_len_it);
+ EXPORT_SYMBOL(lookup_hash);
+ EXPORT_SYMBOL(sys_close);
+ EXPORT_SYMBOL(sys_read);
+
+_
diff --git a/lustre/kernel_patches/pc/nfs_export_kernel-2.4.20-hp.pc b/lustre/kernel_patches/pc/nfs_export_kernel-2.4.20-hp.pc
new file mode 100644 (file)
index 0000000..e70ab4d
--- /dev/null
@@ -0,0 +1,9 @@
+fs/file_table.c
+fs/inode.c
+fs/Makefile
+fs/namei.c
+fs/nfsd/export.c
+fs/nfsd/nfsfh.c
+fs/nfsd/vfs.c
+include/linux/fs.h
+kernel/ksyms.c
diff --git a/lustre/kernel_patches/pc/nfs_export_kernel-2.4.20-rh.pc b/lustre/kernel_patches/pc/nfs_export_kernel-2.4.20-rh.pc
new file mode 100644 (file)
index 0000000..e70ab4d
--- /dev/null
@@ -0,0 +1,9 @@
+fs/file_table.c
+fs/inode.c
+fs/Makefile
+fs/namei.c
+fs/nfsd/export.c
+fs/nfsd/nfsfh.c
+fs/nfsd/vfs.c
+include/linux/fs.h
+kernel/ksyms.c
index cf6f36a..9872be9 100644 (file)
@@ -31,3 +31,4 @@ removepage-2.4.20.patch
 jbd-ctx_switch.patch
 jbd-flushtime.patch
 jbd-get_write_access.patch
+nfs_export_kernel-2.4.20-hp.patch
index 3800650..dfdddd3 100644 (file)
@@ -34,3 +34,4 @@ gpl_header-chaos-2.4.20.patch
 add_page_private.patch
 jbd-flushtime.patch
 jbd-get_write_access.patch
+nfs_export_kernel-2.4.20-rh.patch