]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blobdiff - src/patches/suse-2.6.27.31/patches.suse/xfs-dmapi-src
Reenabled linux-xen, added patches for Xen Kernel Version 2.6.27.31,
[people/pmueller/ipfire-2.x.git] / src / patches / suse-2.6.27.31 / patches.suse / xfs-dmapi-src
diff --git a/src/patches/suse-2.6.27.31/patches.suse/xfs-dmapi-src b/src/patches/suse-2.6.27.31/patches.suse/xfs-dmapi-src
new file mode 100644 (file)
index 0000000..ab7b433
--- /dev/null
@@ -0,0 +1,10845 @@
+Date: Thu, 09 Oct 2008 17:11:31 +1100
+From: Donald Douwsma <donaldd@sgi.com>
+Subject: DMAPI Source 
+Patch-mainline: ?
+References: bnc#450658
+
+Acked-by: Jan Kara <jack@suse.cz>
+
+---
+ fs/dmapi/Makefile          |   53 +
+ fs/dmapi/Status            |  128 +++
+ fs/dmapi/dmapi.h           | 1086 ++++++++++++++++++++++++++
+ fs/dmapi/dmapi_attr.c      |   93 ++
+ fs/dmapi/dmapi_bulkattr.c  |  170 ++++
+ fs/dmapi/dmapi_config.c    |  117 ++
+ fs/dmapi/dmapi_dmattr.c    |  228 +++++
+ fs/dmapi/dmapi_event.c     |  860 +++++++++++++++++++++
+ fs/dmapi/dmapi_handle.c    |  119 ++
+ fs/dmapi/dmapi_hole.c      |  119 ++
+ fs/dmapi/dmapi_io.c        |  142 +++
+ fs/dmapi/dmapi_kern.h      |  599 ++++++++++++++
+ fs/dmapi/dmapi_mountinfo.c |  527 ++++++++++++
+ fs/dmapi/dmapi_port.h      |  138 +++
+ fs/dmapi/dmapi_private.h   |  619 +++++++++++++++
+ fs/dmapi/dmapi_region.c    |   91 ++
+ fs/dmapi/dmapi_register.c  | 1644 ++++++++++++++++++++++++++++++++++++++++
+ fs/dmapi/dmapi_right.c     | 1256 ++++++++++++++++++++++++++++++
+ fs/dmapi/dmapi_session.c   | 1825 +++++++++++++++++++++++++++++++++++++++++++++
+ fs/dmapi/dmapi_sysent.c    |  805 +++++++++++++++++++
+ fs/dmapi/sv.h              |   89 ++
+ 21 files changed, 10708 insertions(+)
+
+Index: linux-2.6.26/fs/dmapi/dmapi_attr.c
+===================================================================
+--- /dev/null
++++ linux-2.6.26/fs/dmapi/dmapi_attr.c
+@@ -0,0 +1,93 @@
++/*
++ * Copyright (c) 2000 Silicon Graphics, Inc.  All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of version 2 of the GNU General Public License as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it would be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
++ *
++ * Further, this software is distributed without any warranty that it is
++ * free of the rightful claim of any third person regarding infringement
++ * or the like.        Any license provided herein, whether implied or
++ * otherwise, applies only to this software file.  Patent licenses, if
++ * any, provided herein do not apply to combinations of this program with
++ * other software, or any other product whatsoever.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write the Free Software Foundation, Inc., 59
++ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
++ *
++ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
++ * Mountain View, CA  94043, or:
++ *
++ * http://www.sgi.com
++ *
++ * For further information regarding this notice, see:
++ *
++ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
++ */
++
++#include "dmapi.h"
++#include "dmapi_kern.h"
++#include "dmapi_private.h"
++
++
++/* Retrieve attributes for a single file, directory or symlink. */
++
++int
++dm_get_fileattr(
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token,
++      u_int           mask,
++      dm_stat_t       __user *statp)
++{
++      dm_fsys_vector_t *fsys_vector;
++      dm_tokdata_t    *tdp;
++      int             error;
++
++      error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VNO,
++              DM_RIGHT_SHARED, &tdp);
++      if (error != 0)
++              return(error);
++
++      fsys_vector = dm_fsys_vector(tdp->td_ip);
++      error = fsys_vector->get_fileattr(tdp->td_ip, tdp->td_right,
++              mask, statp);
++
++      dm_app_put_tdp(tdp);
++      return(error);
++}
++
++
++/* Set one or more file attributes of a file, directory, or symlink. */
++
++int
++dm_set_fileattr(
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token,
++      u_int           mask,
++      dm_fileattr_t   __user *attrp)
++{
++      dm_fsys_vector_t *fsys_vector;
++      dm_tokdata_t    *tdp;
++      int             error;
++
++      error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VNO,
++              DM_RIGHT_EXCL, &tdp);
++      if (error != 0)
++              return(error);
++
++      fsys_vector = dm_fsys_vector(tdp->td_ip);
++      error = fsys_vector->set_fileattr(tdp->td_ip, tdp->td_right,
++              mask, attrp);
++
++      dm_app_put_tdp(tdp);
++      return(error);
++}
+Index: linux-2.6.26/fs/dmapi/dmapi_bulkattr.c
+===================================================================
+--- /dev/null
++++ linux-2.6.26/fs/dmapi/dmapi_bulkattr.c
+@@ -0,0 +1,170 @@
++/*
++ * Copyright (c) 2000 Silicon Graphics, Inc.  All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of version 2 of the GNU General Public License as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it would be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
++ *
++ * Further, this software is distributed without any warranty that it is
++ * free of the rightful claim of any third person regarding infringement
++ * or the like.        Any license provided herein, whether implied or
++ * otherwise, applies only to this software file.  Patent licenses, if
++ * any, provided herein do not apply to combinations of this program with
++ * other software, or any other product whatsoever.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write the Free Software Foundation, Inc., 59
++ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
++ *
++ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
++ * Mountain View, CA  94043, or:
++ *
++ * http://www.sgi.com
++ *
++ * For further information regarding this notice, see:
++ *
++ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
++ */
++
++#include "dmapi.h"
++#include "dmapi_kern.h"
++#include "dmapi_private.h"
++
++
++int
++dm_init_attrloc(
++      dm_sessid_t     sid,
++      void            __user  *hanp,
++      size_t          hlen,
++      dm_token_t      token,
++      dm_attrloc_t    __user *locp)
++{
++      dm_fsys_vector_t *fsys_vector;
++      dm_tokdata_t    *tdp;
++      int             error;
++
++      error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VFS|DM_TDT_DIR,
++              DM_RIGHT_SHARED, &tdp);
++      if (error != 0)
++              return(error);
++
++      fsys_vector = dm_fsys_vector(tdp->td_ip);
++      error = fsys_vector->init_attrloc(tdp->td_ip, tdp->td_right, locp);
++
++      dm_app_put_tdp(tdp);
++      return(error);
++}
++
++
++/*
++ * Retrieves both standard and DM specific file attributes for the file
++ * system indicated by the handle. (The FS has to be mounted).
++ * Syscall returns 1 to indicate SUCCESS and more information is available.
++ * -1 is returned on error, and errno will be set appropriately.
++ * 0 is returned upon successful completion.
++ */
++
++int
++dm_get_bulkattr_rvp(
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token,
++      u_int           mask,
++      dm_attrloc_t    __user *locp,
++      size_t          buflen,
++      void            __user *bufp,
++      size_t          __user *rlenp,
++      int             *rvp)
++{
++      dm_fsys_vector_t *fsys_vector;
++      dm_tokdata_t    *tdp;
++      int             error;
++
++      error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VFS,
++              DM_RIGHT_SHARED, &tdp);
++      if (error != 0)
++              return(error);
++
++      fsys_vector = dm_fsys_vector(tdp->td_ip);
++      error = fsys_vector->get_bulkattr_rvp(tdp->td_ip, tdp->td_right,
++                      mask, locp, buflen, bufp, rlenp, rvp);
++
++      dm_app_put_tdp(tdp);
++      return(error);
++}
++
++
++/*
++ * Retrieves attributes of directory entries given a handle to that
++ * directory. Iterative.
++ * Syscall returns 1 to indicate SUCCESS and more information is available.
++ * -1 is returned on error, and errno will be set appropriately.
++ * 0 is returned upon successful completion.
++ */
++
++int
++dm_get_dirattrs_rvp(
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token,
++      u_int           mask,
++      dm_attrloc_t    __user *locp,
++      size_t          buflen,
++      void            __user *bufp,
++      size_t          __user *rlenp,
++      int             *rvp)
++{
++      dm_fsys_vector_t *fsys_vector;
++      dm_tokdata_t    *tdp;
++      int             error;
++
++      error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_DIR,
++              DM_RIGHT_SHARED, &tdp);
++      if (error != 0)
++              return(error);
++
++      fsys_vector = dm_fsys_vector(tdp->td_ip);
++      error = fsys_vector->get_dirattrs_rvp(tdp->td_ip, tdp->td_right,
++              mask, locp, buflen, bufp, rlenp, rvp);
++
++      dm_app_put_tdp(tdp);
++      return(error);
++}
++
++
++int
++dm_get_bulkall_rvp(
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token,
++      u_int           mask,
++      dm_attrname_t   __user *attrnamep,
++      dm_attrloc_t    __user *locp,
++      size_t          buflen,
++      void            __user *bufp,
++      size_t          __user *rlenp,
++      int             *rvp)
++{
++      dm_fsys_vector_t *fsys_vector;
++      dm_tokdata_t    *tdp;
++      int             error;
++
++      error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VFS,
++              DM_RIGHT_SHARED, &tdp);
++      if (error != 0)
++              return(error);
++
++      fsys_vector = dm_fsys_vector(tdp->td_ip);
++      error = fsys_vector->get_bulkall_rvp(tdp->td_ip, tdp->td_right,
++              mask, attrnamep, locp, buflen, bufp, rlenp, rvp);
++
++      dm_app_put_tdp(tdp);
++      return(error);
++}
+Index: linux-2.6.26/fs/dmapi/dmapi_config.c
+===================================================================
+--- /dev/null
++++ linux-2.6.26/fs/dmapi/dmapi_config.c
+@@ -0,0 +1,117 @@
++/*
++ * Copyright (c) 2000-2004 Silicon Graphics, Inc.  All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of version 2 of the GNU General Public License as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it would be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
++ *
++ * Further, this software is distributed without any warranty that it is
++ * free of the rightful claim of any third person regarding infringement
++ * or the like.        Any license provided herein, whether implied or
++ * otherwise, applies only to this software file.  Patent licenses, if
++ * any, provided herein do not apply to combinations of this program with
++ * other software, or any other product whatsoever.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write the Free Software Foundation, Inc., 59
++ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
++ *
++ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
++ * Mountain View, CA  94043, or:
++ *
++ * http://www.sgi.com
++ *
++ * For further information regarding this notice, see:
++ *
++ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
++ */
++
++#include <asm/uaccess.h>
++#include "dmapi.h"
++#include "dmapi_kern.h"
++#include "dmapi_private.h"
++
++int
++dm_get_config(
++      void            __user *hanp,
++      size_t          hlen,
++      dm_config_t     flagname,
++      dm_size_t       __user *retvalp)
++{
++      dm_fsys_vector_t *fsys_vector;
++      dm_tokdata_t    *tdp;
++      dm_size_t       retval;
++      int             system = 1;
++      int             error;
++
++      /* Trap and process configuration parameters which are system-wide. */
++
++      switch (flagname) {
++      case DM_CONFIG_LEGACY:
++      case DM_CONFIG_PENDING:
++      case DM_CONFIG_OBJ_REF:
++              retval = DM_TRUE;
++              break;
++      case DM_CONFIG_MAX_MESSAGE_DATA:
++              retval = DM_MAX_MSG_DATA;
++              break;
++      default:
++              system = 0;
++              break;
++      }
++      if (system) {
++              if (copy_to_user(retvalp, &retval, sizeof(retval)))
++                      return(-EFAULT);
++              return(0);
++      }
++
++      /* Must be filesystem-specific.  Convert the handle into an inode. */
++
++      if ((error = dm_get_config_tdp(hanp, hlen, &tdp)) != 0)
++              return(error);
++
++      /* Now call the filesystem-specific routine to determine the
++         value of the configuration option for that filesystem.
++      */
++
++      fsys_vector = dm_fsys_vector(tdp->td_ip);
++      error = fsys_vector->get_config(tdp->td_ip, tdp->td_right,
++              flagname, retvalp);
++
++      dm_app_put_tdp(tdp);
++      return(error);
++}
++
++
++int
++dm_get_config_events(
++      void            __user *hanp,
++      size_t          hlen,
++      u_int           nelem,
++      dm_eventset_t   __user *eventsetp,
++      u_int           __user *nelemp)
++{
++      dm_fsys_vector_t *fsys_vector;
++      dm_tokdata_t    *tdp;
++      int             error;
++
++      /* Convert the handle into an inode. */
++
++      if ((error = dm_get_config_tdp(hanp, hlen, &tdp)) != 0)
++              return(error);
++
++      /* Now call the filesystem-specific routine to determine the
++         events supported by that filesystem.
++      */
++
++      fsys_vector = dm_fsys_vector(tdp->td_ip);
++      error = fsys_vector->get_config_events(tdp->td_ip, tdp->td_right,
++              nelem, eventsetp, nelemp);
++
++      dm_app_put_tdp(tdp);
++      return(error);
++}
+Index: linux-2.6.26/fs/dmapi/dmapi_dmattr.c
+===================================================================
+--- /dev/null
++++ linux-2.6.26/fs/dmapi/dmapi_dmattr.c
+@@ -0,0 +1,228 @@
++/*
++ * Copyright (c) 2000 Silicon Graphics, Inc.  All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of version 2 of the GNU General Public License as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it would be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
++ *
++ * Further, this software is distributed without any warranty that it is
++ * free of the rightful claim of any third person regarding infringement
++ * or the like.        Any license provided herein, whether implied or
++ * otherwise, applies only to this software file.  Patent licenses, if
++ * any, provided herein do not apply to combinations of this program with
++ * other software, or any other product whatsoever.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write the Free Software Foundation, Inc., 59
++ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
++ *
++ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
++ * Mountain View, CA  94043, or:
++ *
++ * http://www.sgi.com
++ *
++ * For further information regarding this notice, see:
++ *
++ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
++ */
++#include "dmapi.h"
++#include "dmapi_kern.h"
++#include "dmapi_private.h"
++
++
++int
++dm_clear_inherit(
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token,
++      dm_attrname_t   __user *attrnamep)
++{
++      dm_fsys_vector_t *fsys_vector;
++      dm_tokdata_t    *tdp;
++      int             error;
++
++      error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VFS,
++              DM_RIGHT_EXCL, &tdp);
++      if (error != 0)
++              return(error);
++
++      fsys_vector = dm_fsys_vector(tdp->td_ip);
++      error = fsys_vector->clear_inherit(tdp->td_ip, tdp->td_right,
++              attrnamep);
++
++      dm_app_put_tdp(tdp);
++      return(error);
++}
++
++
++int
++dm_get_dmattr(
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token,
++      dm_attrname_t   __user *attrnamep,
++      size_t          buflen,
++      void            __user *bufp,
++      size_t          __user *rlenp)
++{
++      dm_fsys_vector_t *fsys_vector;
++      dm_tokdata_t    *tdp;
++      int             error;
++
++      error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VNO,
++              DM_RIGHT_SHARED, &tdp);
++      if (error != 0)
++              return(error);
++
++      fsys_vector = dm_fsys_vector(tdp->td_ip);
++      error = fsys_vector->get_dmattr(tdp->td_ip, tdp->td_right,
++              attrnamep, buflen, bufp, rlenp);
++
++      dm_app_put_tdp(tdp);
++      return(error);
++}
++
++
++int
++dm_getall_dmattr(
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token,
++      size_t          buflen,
++      void            __user *bufp,
++      size_t          __user *rlenp)
++{
++      dm_fsys_vector_t *fsys_vector;
++      dm_tokdata_t    *tdp;
++      int             error;
++
++      error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VNO,
++              DM_RIGHT_SHARED, &tdp);
++      if (error != 0)
++              return(error);
++
++      fsys_vector = dm_fsys_vector(tdp->td_ip);
++      error = fsys_vector->getall_dmattr(tdp->td_ip, tdp->td_right,
++              buflen, bufp, rlenp);
++
++      dm_app_put_tdp(tdp);
++      return(error);
++}
++
++
++int
++dm_getall_inherit(
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token,
++      u_int           nelem,
++      dm_inherit_t    __user *inheritbufp,
++      u_int           __user *nelemp)
++{
++      dm_fsys_vector_t *fsys_vector;
++      dm_tokdata_t    *tdp;
++      int             error;
++
++      error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VFS,
++              DM_RIGHT_SHARED, &tdp);
++      if (error != 0)
++              return(error);
++
++      fsys_vector = dm_fsys_vector(tdp->td_ip);
++      error = fsys_vector->getall_inherit(tdp->td_ip, tdp->td_right,
++              nelem, inheritbufp, nelemp);
++
++      dm_app_put_tdp(tdp);
++      return(error);
++}
++
++
++int
++dm_remove_dmattr(
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token,
++      int             setdtime,
++      dm_attrname_t   __user *attrnamep)
++{
++      dm_fsys_vector_t *fsys_vector;
++      dm_tokdata_t    *tdp;
++      int             error;
++
++      error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VNO,
++              DM_RIGHT_EXCL, &tdp);
++      if (error != 0)
++              return(error);
++
++      fsys_vector = dm_fsys_vector(tdp->td_ip);
++      error = fsys_vector->remove_dmattr(tdp->td_ip, tdp->td_right,
++              setdtime, attrnamep);
++
++      dm_app_put_tdp(tdp);
++      return(error);
++}
++
++
++int
++dm_set_dmattr(
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token,
++      dm_attrname_t   __user *attrnamep,
++      int             setdtime,
++      size_t          buflen,
++      void            __user *bufp)
++{
++      dm_fsys_vector_t *fsys_vector;
++      dm_tokdata_t    *tdp;
++      int             error;
++
++      error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VNO,
++              DM_RIGHT_EXCL, &tdp);
++      if (error != 0)
++              return(error);
++
++      fsys_vector = dm_fsys_vector(tdp->td_ip);
++      error = fsys_vector->set_dmattr(tdp->td_ip, tdp->td_right,
++              attrnamep, setdtime, buflen, bufp);
++
++      dm_app_put_tdp(tdp);
++      return(error);
++}
++
++
++int
++dm_set_inherit(
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token,
++      dm_attrname_t   __user *attrnamep,
++      mode_t          mode)
++{
++      dm_fsys_vector_t *fsys_vector;
++      dm_tokdata_t    *tdp;
++      int             error;
++
++      error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VFS,
++              DM_RIGHT_EXCL, &tdp);
++      if (error != 0)
++              return(error);
++
++      fsys_vector = dm_fsys_vector(tdp->td_ip);
++      error = fsys_vector->set_inherit(tdp->td_ip, tdp->td_right,
++              attrnamep, mode);
++
++      dm_app_put_tdp(tdp);
++      return(error);
++}
+Index: linux-2.6.26/fs/dmapi/dmapi_event.c
+===================================================================
+--- /dev/null
++++ linux-2.6.26/fs/dmapi/dmapi_event.c
+@@ -0,0 +1,860 @@
++/*
++ * Copyright (c) 2000-2005 Silicon Graphics, Inc.  All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of version 2 of the GNU General Public License as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it would be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
++ *
++ * Further, this software is distributed without any warranty that it is
++ * free of the rightful claim of any third person regarding infringement
++ * or the like.        Any license provided herein, whether implied or
++ * otherwise, applies only to this software file.  Patent licenses, if
++ * any, provided herein do not apply to combinations of this program with
++ * other software, or any other product whatsoever.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write the Free Software Foundation, Inc., 59
++ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
++ *
++ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
++ * Mountain View, CA  94043, or:
++ *
++ * http://www.sgi.com
++ *
++ * For further information regarding this notice, see:
++ *
++ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
++ */
++#include <asm/uaccess.h>
++#include "dmapi.h"
++#include "dmapi_kern.h"
++#include "dmapi_private.h"
++
++/* The "rights" portion of the DMAPI spec is not currently implemented.        A
++   framework for rights is provided in the code, but turns out to be a noop
++   in practice.        The following comments are a brain dump to serve as input to
++   the poor soul that eventually has to get DMAPI rights working in IRIX.
++
++   A DMAPI right is similar but not identical to the mrlock_t mechanism
++   already used within the kernel.  The similarities are that it is a
++   sleeping lock, and that a multiple-reader, single-writer protocol is used.
++   How locks are obtained and dropped are different however.  With a mrlock_t,
++   a thread grabs the lock, does some stuff, then drops the lock, and all other
++   threads block in the meantime (assuming a write lock).  There is a one-to-
++   one relationship between the lock and the thread which obtained the lock.
++   Not so with DMAPI right locks.  A DMAPI lock is associated with a particular
++   session/token/hanp/hlen quad; since there is a dm_tokdata_t structure for
++   each such quad, you can think of it as a one-to-one relationship between the
++   lock and a dm_tokdata_t.  Any application thread which presents the correct
++   quad is entitled to grab or release the lock, or to use the rights
++   associated with that lock.  The thread that grabs the lock does not have to
++   be the one to use the lock, nor does it have to be the thread which drops
++   the lock.  The lock can be held for very long periods of time, even across
++   multiple systems calls by multiple application threads.  The idea is that a
++   coordinated group of DMAPI application threads can grab the lock, issue a
++   series of inode accesses and/or updates, then drop the lock, and be assured
++   that no other thread in the system could be modifying the inode at the same
++   time.  The kernel is expected to blindly trust that the application will
++   not forget to unlock inodes it has locked, and will not deadlock itself
++   against the kernel.
++
++   There are two types of DMAPI rights, file object (inode) and filesystem
++   object (superblock?).  An inode right is the equivalent of the combination
++   of both the XFS ilock and iolock; if held exclusively, no data or metadata
++   within the file can be changed by non-lock-holding threads.        The filesystem
++   object lock is a little fuzzier; I think that if it is held, things like
++   unmounts can be blocked, plus there is an event mask associated with the
++   filesystem which can't be updated without the lock.        (By the way, that
++   event mask is supposed to be persistent in the superblock; add that to
++   your worklist :-)
++
++   All events generated by XFS currently arrive with no rights, i.e.
++   DM_RIGHT_NULL, and return to the filesystem with no rights.        It would be
++   smart to leave it this way if possible, because it otherwise becomes more
++   likely that an application thread will deadlock against the kernel if the
++   one responsible for calling dm_get_events() happens to touch a file which
++   was locked at the time the event was queued.        Since the thread is blocked,
++   it can't read the event in order to find and drop the lock.        Catch-22.  If
++   you do have events that arrive with non-null rights, then dm_enqueue() needs
++   to have code added for synchronous events which atomically switches the
++   right from being a thread-based right to a dm_tokdata_t-based right without
++   allowing the lock to drop in between.  You will probably have to add a new
++   dm_fsys_vector entry point to do this.  The lock can't be lost during the
++   switch, or other threads might change the inode or superblock in between.
++   Likewise, if you need to return to the filesystem holding a right, then
++   you need a DMAPI-to-thread atomic switch to occur, most likely in
++   dm_change_right().  Again, the lock must not be lost during the switch; the
++   DMAPI spec spends a couple of pages stressing this.        Another dm_fsys_vector
++   entry point is probably the answer.
++
++   There are several assumptions implied in the current layout of the code.
++   First of all, if an event returns to the filesystem with a return value of
++   zero, then the filesystem can assume that any locks (rights) held at the
++   start of the event are still in effect at the end of the event.  (Note that
++   the application could have temporarily dropped and reaquired the right
++   while the event was outstanding, however).  If the event returns to the
++   filesystem with an errno, then the filesystem must assume that it has lost
++   any and all rights associated with any of the objects in the event.        This
++   was done for a couple of reasons.  First of all, since an errno is being
++   returned, most likely the filesystem is going to immediately drop all the
++   locks anyway.  If the DMAPI code was required to unconditionally reobtain
++   all locks before returning to the filesystem, then dm_pending() wouldn't
++   work for NFS server threads because the process would block indefinitely
++   trying to get its thread-based rights back, because the DMAPI-rights
++   associated with the dm_tokdata_t in the outstanding event would prevent
++   the rights from being obtained.  That would be a bad thing.        We wouldn't
++   be able to let users Cntl-C out of read/write/truncate events either.
++
++   If a case should ever surface where the thread has lost its rights even
++   though it has a zero return status, or where the thread has rights even
++   though it is returning with an errno, then this logic will have to be
++   reworked.  This could be done by changing the 'right' parameters on all
++   the event calls to (dm_right_t *), so that they could serve both as IN
++   and OUT parameters.
++
++   Some events such as DM_EVENT_DESTROY arrive without holding an inode
++   reference; if you don't have an inode reference, you can't have a right
++   on the file.
++
++   One more quirk.  The DM_EVENT_UNMOUNT event is defined to be synchronous
++   when it's behavior is asynchronous.        If an unmount event arrives with
++   rights, the event should return with the same rights and should NOT leave
++   any rights in the dm_tokdata_t where the application could use them.
++*/
++
++
++#define GETNEXTOFF(vdat)      ((vdat).vd_offset + (vdat).vd_length)
++#define HANDLE_SIZE(tdp)      \
++      ((tdp)->td_type & DM_TDT_VFS ? DM_FSHSIZE : DM_HSIZE((tdp)->td_handle))
++
++
++/* Given an inode pointer in a filesystem known to support DMAPI,
++   build a tdp structure for the corresponding inode.
++*/
++
++static dm_tokdata_t *
++dm_ip_data(
++      struct inode    *ip,
++      dm_right_t      right,
++      int             referenced)     /* != 0, caller holds inode reference */
++{
++      int             error;
++      dm_tokdata_t    *tdp;
++      int             filetype;
++
++      tdp = kmem_cache_alloc(dm_tokdata_cachep, GFP_KERNEL);
++      if (tdp == NULL) {
++              printk("%s/%d: kmem_cache_alloc(dm_tokdata_cachep) returned NULL\n", __FUNCTION__, __LINE__);
++              return NULL;
++      }
++
++      tdp->td_next = NULL;
++      tdp->td_tevp = NULL;
++      tdp->td_app_ref = 0;
++      tdp->td_orig_right = right;
++      tdp->td_right = right;
++      tdp->td_flags = DM_TDF_ORIG;
++      if (referenced) {
++              tdp->td_flags |= DM_TDF_EVTREF;
++      }
++
++      filetype = ip->i_mode & S_IFMT;
++      if (filetype == S_IFREG) {
++              tdp->td_type = DM_TDT_REG;
++      } else if (filetype == S_IFDIR) {
++              tdp->td_type = DM_TDT_DIR;
++      } else if (filetype == S_IFLNK) {
++              tdp->td_type = DM_TDT_LNK;
++      } else {
++              tdp->td_type = DM_TDT_OTH;
++      }
++
++      if (referenced) {
++              tdp->td_ip = ip;
++      } else {
++              tdp->td_ip = NULL;
++      }
++      tdp->td_vcount = 0;
++
++      if ((error = dm_ip_to_handle(ip, &tdp->td_handle)) != 0) {
++              panic("dm_ip_data: dm_ip_to_handle failed for ip %p in "
++                      "a DMAPI filesystem, errno %d\n", ip, error);
++      }
++
++      return(tdp);
++}
++
++
++/* Given a sb pointer to a filesystem known to support DMAPI, build a tdp
++   structure for that sb.
++*/
++static dm_tokdata_t *
++dm_sb_data(
++      struct super_block *sb,
++      struct inode    *ip,            /* will be NULL for DM_EVENT_UNMOUNT */
++      dm_right_t      right)
++{
++      dm_tokdata_t    *tdp;
++      struct filesystem_dmapi_operations *dops;
++      dm_fsid_t       fsid;
++
++      dops = dm_fsys_ops(sb);
++      ASSERT(dops);
++      dops->get_fsid(sb, &fsid);
++
++      tdp = kmem_cache_alloc(dm_tokdata_cachep, GFP_KERNEL);
++      if (tdp == NULL) {
++              printk("%s/%d: kmem_cache_alloc(dm_tokdata_cachep) returned NULL\n", __FUNCTION__, __LINE__);
++              return NULL;
++      }
++
++      tdp->td_next = NULL;
++      tdp->td_tevp = NULL;
++      tdp->td_app_ref = 0;
++      tdp->td_orig_right = right;
++      tdp->td_right = right;
++      tdp->td_flags = DM_TDF_ORIG;
++      if (ip) {
++              tdp->td_flags |= DM_TDF_EVTREF;
++      }
++      tdp->td_type = DM_TDT_VFS;
++      tdp->td_ip = ip;
++      tdp->td_vcount = 0;
++
++      memcpy(&tdp->td_handle.ha_fsid, &fsid, sizeof(fsid));
++      memset((char *)&tdp->td_handle.ha_fsid + sizeof(fsid), 0,
++              sizeof(tdp->td_handle) - sizeof(fsid));
++
++      return(tdp);
++}
++
++
++/* Link a tdp structure into the tevp. */
++
++static void
++dm_add_handle_to_event(
++      dm_tokevent_t   *tevp,
++      dm_tokdata_t    *tdp)
++{
++      tdp->td_next = tevp->te_tdp;
++      tevp->te_tdp = tdp;
++      tdp->td_tevp = tevp;
++}
++
++
++/* Generate the given data event for the inode, and wait for a reply.  The
++   caller must guarantee that the inode's reference count is greater than zero
++   so that the filesystem can't disappear while the request is outstanding.
++*/
++
++int
++dm_send_data_event(
++      dm_eventtype_t  event,
++      struct inode    *ip,
++      dm_right_t      vp_right,       /* current right for ip */
++      dm_off_t        offset,
++      size_t          length,
++      int             flags)          /* 0 or DM_FLAGS_NDELAY */
++{
++      dm_data_event_t *datap;
++      dm_tokevent_t   *tevp;
++      dm_tokdata_t    *tdp;
++      int             error;
++
++      tdp = dm_ip_data(ip, vp_right, /* reference held */ 1);
++      if (tdp == NULL)
++              return -ENOMEM;
++
++      /* Calculate the size of the event in bytes, create an event structure
++         for it, and insert the file's handle into the event.
++      */
++
++      tevp = dm_evt_create_tevp(event, HANDLE_SIZE(tdp), (void **)&datap);
++      if (tevp == NULL) {
++              kmem_cache_free(dm_tokdata_cachep, tdp);
++              return(-ENOMEM);
++      }
++      dm_add_handle_to_event(tevp, tdp);
++
++      /* Now fill in all the dm_data_event_t fields. */
++
++      datap->de_handle.vd_offset = sizeof(*datap);
++      datap->de_handle.vd_length = HANDLE_SIZE(tdp);
++      memcpy((char *)datap + datap->de_handle.vd_offset, &tdp->td_handle,
++              datap->de_handle.vd_length);
++      datap->de_offset = offset;
++      datap->de_length = length;
++
++      /* Queue the message and wait for the reply. */
++
++      error = dm_enqueue_normal_event(ip->i_sb, &tevp, flags);
++
++      /* If no errors occurred, we must leave with the same rights we had
++         upon entry.  If errors occurred, we must leave with no rights.
++      */
++
++      dm_evt_rele_tevp(tevp, error);
++
++      return(error);
++}
++
++
++/* Generate the destroy event for the inode and wait until the request has been
++   queued.  The caller does not hold an inode reference or a right on the inode,
++   but it must otherwise lock down the inode such that the filesystem can't
++   disappear while the request is waiting to be queued.        While waiting to be
++   queued, the inode must not be referenceable either by path or by a call
++   to dm_handle_to_ip().
++*/
++
++int
++dm_send_destroy_event(
++      struct inode    *ip,
++      dm_right_t      vp_right)       /* always DM_RIGHT_NULL */
++{
++      dm_fsys_vector_t *fsys_vector;
++      dm_tokevent_t   *tevp;
++      dm_tokdata_t    *tdp;
++      dm_destroy_event_t *destp;
++      dm_attrname_t   attrname;
++      char            *value;
++      int             value_len;
++      int             error;
++
++      tdp = dm_ip_data(ip, vp_right, /* no reference held */ 0);
++      if (tdp == NULL)
++              return -ENOMEM;
++
++      if ((error = dm_waitfor_destroy_attrname(ip->i_sb, &attrname)) != 0)
++              return(error);
++
++      /* If a return-on-destroy attribute name exists for this filesystem,
++         see if the object being deleted has this attribute.  If the object
++         doesn't have the attribute or if we encounter an error, then send
++         the event without the attribute.
++       */
++
++      value_len = -1;         /* because zero is a valid attribute length */
++      if (attrname.an_chars[0] != '\0') {
++              fsys_vector = dm_fsys_vector(ip);
++              error = fsys_vector->get_destroy_dmattr(ip, vp_right, &attrname,
++                      &value, &value_len);
++              if (error && error != -ENODATA)
++                      return error;
++      }
++
++      /* Now that we know the size of the attribute value, if any, calculate
++         the size of the event in bytes, create an event structure for it,
++         and insert the handle into the event.
++      */
++
++      tevp = dm_evt_create_tevp(DM_EVENT_DESTROY,
++              HANDLE_SIZE(tdp) + (value_len >= 0 ? value_len : 0),
++              (void **)&destp);
++      if (tevp == NULL) {
++              kmem_cache_free(dm_tokdata_cachep, tdp);
++              if (value_len > 0)
++                      kfree(value);
++              return(-ENOMEM);
++      }
++      dm_add_handle_to_event(tevp, tdp);
++
++      /* Now fill in all the dm_destroy_event_t fields. */
++
++      destp->ds_handle.vd_offset = sizeof(*destp);
++      destp->ds_handle.vd_length = HANDLE_SIZE(tdp);
++      memcpy((char *)destp + destp->ds_handle.vd_offset, &tdp->td_handle,
++              destp->ds_handle.vd_length);
++      if (value_len >= 0) {
++              destp->ds_attrname = attrname;
++              destp->ds_attrcopy.vd_length = value_len;
++              if (value_len == 0) {
++                      destp->ds_attrcopy.vd_offset = 0;
++              } else {
++                      destp->ds_attrcopy.vd_offset = GETNEXTOFF(destp->ds_handle);
++                      memcpy((char *)destp + destp->ds_attrcopy.vd_offset, value,
++                              value_len);
++                      kfree(value);
++              }
++      }
++
++      /* Queue the message asynchronously. */
++
++      error = dm_enqueue_normal_event(ip->i_sb, &tevp, 0);
++
++      /* Since we had no rights upon entry, we have none to reobtain before
++         leaving.
++      */
++
++      dm_evt_rele_tevp(tevp, 1);
++
++      return(error);
++}
++
++
++/* The dm_mount_event_t event is sent in turn to all sessions that have asked
++   for it until one either rejects it or accepts it.  The filesystem is not
++   going anywhere because the mount is blocked until the event is answered.
++*/
++
++int
++dm_send_mount_event(
++      struct super_block *sb,         /* filesystem being mounted */
++      dm_right_t      vfsp_right,
++      struct inode    *ip,            /* mounted on directory */
++      dm_right_t      vp_right,
++      struct inode    *rootip,
++      dm_right_t      rootvp_right,
++      char            *name1,         /* mount path */
++      char            *name2)         /* filesystem device name */
++{
++      int             error;
++      dm_tokevent_t   *tevp = NULL;
++      dm_tokdata_t    *tdp1 = NULL;   /* filesystem handle for event */
++      dm_tokdata_t    *tdp2 = NULL;   /* file handle for mounted-on dir. */
++      dm_tokdata_t    *tdp3 = NULL;   /* file handle for root inode */
++      dm_mount_event_t *mp;
++      size_t          nextoff;
++
++      /* Convert the sb to a filesystem handle, and ip and rootip into
++         file handles.  ip (the mounted-on directory) may not have a handle
++         if it is a different filesystem type which does not support DMAPI.
++      */
++
++      tdp1 = dm_sb_data(sb, rootip, vfsp_right);
++      if (tdp1 == NULL)
++              goto out_nomem;
++
++      if ((ip == NULL) || dm_check_dmapi_ip(ip)) {
++              ip = NULL;      /* we are mounting on non-DMAPI FS */
++      } else {
++              tdp2 = dm_ip_data(ip, vp_right, /* reference held */ 1);
++              if (tdp2 == NULL)
++                      goto out_nomem;
++      }
++
++      tdp3 = dm_ip_data(rootip, rootvp_right, /* reference held */ 1);
++      if (tdp3 == NULL)
++              goto out_nomem;
++
++      /* Calculate the size of the event in bytes, create an event structure
++         for it, and insert the handles into the event.
++      */
++
++      tevp = dm_evt_create_tevp(DM_EVENT_MOUNT,
++                      HANDLE_SIZE(tdp1) + (ip ? HANDLE_SIZE(tdp2) : 0) +
++                      HANDLE_SIZE(tdp3) + strlen(name1) + 1 +
++                      strlen(name2) + 1, (void **)&mp);
++      if (tevp == NULL)
++              goto out_nomem;
++
++      dm_add_handle_to_event(tevp, tdp1);
++      if (ip)
++              dm_add_handle_to_event(tevp, tdp2);
++      dm_add_handle_to_event(tevp, tdp3);
++
++      /* Now fill in all the dm_mount_event_t fields. */
++
++      mp->me_handle1.vd_offset = sizeof(*mp);
++      mp->me_handle1.vd_length = HANDLE_SIZE(tdp1);
++      memcpy((char *) mp + mp->me_handle1.vd_offset, &tdp1->td_handle,
++                      mp->me_handle1.vd_length);
++      nextoff = GETNEXTOFF(mp->me_handle1);
++
++      if (ip) {
++              mp->me_handle2.vd_offset = nextoff;
++              mp->me_handle2.vd_length = HANDLE_SIZE(tdp2);
++              memcpy((char *)mp + mp->me_handle2.vd_offset, &tdp2->td_handle,
++                      mp->me_handle2.vd_length);
++              nextoff = GETNEXTOFF(mp->me_handle2);
++      }
++
++      mp->me_name1.vd_offset = nextoff;
++      mp->me_name1.vd_length = strlen(name1) + 1;
++      memcpy((char *)mp + mp->me_name1.vd_offset, name1, mp->me_name1.vd_length);
++      nextoff = GETNEXTOFF(mp->me_name1);
++
++      mp->me_name2.vd_offset = nextoff;
++      mp->me_name2.vd_length = strlen(name2) + 1;
++      memcpy((char *)mp + mp->me_name2.vd_offset, name2, mp->me_name2.vd_length);
++      nextoff = GETNEXTOFF(mp->me_name2);
++
++      mp->me_roothandle.vd_offset = nextoff;
++      mp->me_roothandle.vd_length = HANDLE_SIZE(tdp3);
++      memcpy((char *)mp + mp->me_roothandle.vd_offset, &tdp3->td_handle,
++                      mp->me_roothandle.vd_length);
++
++      mp->me_mode = (sb->s_flags & MS_RDONLY ? DM_MOUNT_RDONLY : 0);
++
++      /* Queue the message and wait for the reply. */
++
++      error = dm_enqueue_mount_event(sb, tevp);
++
++      /* If no errors occurred, we must leave with the same rights we had
++         upon entry.  If errors occurred, we must leave with no rights.
++      */
++
++      dm_evt_rele_tevp(tevp, error);
++
++      return(error);
++
++out_nomem:
++      if (tevp)
++              kfree(tevp);
++      if (tdp1)
++              kmem_cache_free(dm_tokdata_cachep, tdp1);
++      if (tdp2)
++              kmem_cache_free(dm_tokdata_cachep, tdp2);
++      if (tdp3)
++              kmem_cache_free(dm_tokdata_cachep, tdp3);
++      return -ENOMEM;
++}
++
++
++/* Generate an DM_EVENT_UNMOUNT event and wait for a reply.  The 'retcode'
++   field indicates whether this is a successful or unsuccessful unmount.
++   If successful, the filesystem is already unmounted, and any pending handle
++   reference to the filesystem will be failed.        If the unmount was
++   unsuccessful, then the filesystem will be placed back into full service.
++
++   The DM_EVENT_UNMOUNT event should really be asynchronous, because the
++   application has no control over whether or not the unmount succeeds.        (The
++   DMAPI spec defined it that way because asynchronous events aren't always
++   guaranteed to be delivered.)
++
++   Since the filesystem is already unmounted in the successful case, the
++   DM_EVENT_UNMOUNT event can't make available any inode to be used in
++   subsequent sid/hanp/hlen/token calls by the application.  The event will
++   hang around until the application does a DM_RESP_CONTINUE, but the handle
++   within the event is unusable by the application.
++*/
++
++void
++dm_send_unmount_event(
++      struct super_block *sb,
++      struct inode    *ip,            /* NULL if unmount successful */
++      dm_right_t      vfsp_right,
++      mode_t          mode,
++      int             retcode,        /* errno, if unmount failed */
++      int             flags)
++{
++      dm_namesp_event_t       *np;
++      dm_tokevent_t   *tevp;
++      dm_tokdata_t    *tdp1;
++
++      /* If the unmount failed, put the filesystem back into full service,
++         allowing blocked handle references to finish.  If it succeeded, put
++         the filesystem into the DM_STATE_UNMOUNTED state and fail all
++         blocked DM_NO_TOKEN handle accesses.
++      */
++
++      if (retcode != 0) {     /* unmount was unsuccessful */
++              dm_change_fsys_entry(sb, DM_STATE_MOUNTED);
++      } else {
++              dm_change_fsys_entry(sb, DM_STATE_UNMOUNTED);
++      }
++
++      /* If the event wasn't in the filesystem dm_eventset_t, just remove
++         the filesystem from the list of DMAPI filesystems and return.
++      */
++
++      if (flags & DM_FLAGS_UNWANTED) {
++              if (retcode == 0)
++                      dm_remove_fsys_entry(sb);
++              return;
++      }
++
++      /* Calculate the size of the event in bytes and allocate zeroed memory
++         for it.
++      */
++
++      tdp1 = dm_sb_data(sb, ip, vfsp_right);
++      if (tdp1 == NULL)
++              return;
++
++      tevp = dm_evt_create_tevp(DM_EVENT_UNMOUNT, HANDLE_SIZE(tdp1),
++              (void **)&np);
++      if (tevp == NULL) {
++              kmem_cache_free(dm_tokdata_cachep, tdp1);
++              return;
++      }
++
++      dm_add_handle_to_event(tevp, tdp1);
++
++      /* Now copy in all the dm_namesp_event_t specific fields. */
++
++      np->ne_handle1.vd_offset = sizeof(*np);
++      np->ne_handle1.vd_length = HANDLE_SIZE(tdp1);
++      memcpy((char *) np + np->ne_handle1.vd_offset, &tdp1->td_handle,
++                      np->ne_handle1.vd_length);
++      np->ne_mode = mode;
++      np->ne_retcode = retcode;
++
++      /* Since DM_EVENT_UNMOUNT is effectively asynchronous, queue the
++         message and ignore any error return for DM_EVENT_UNMOUNT.
++      */
++
++      (void)dm_enqueue_normal_event(sb, &tevp, flags);
++
++      if (retcode == 0)
++              dm_remove_fsys_entry(sb);
++
++      dm_evt_rele_tevp(tevp, 0);
++}
++
++
++/* Generate the given namespace event and wait for a reply (if synchronous) or
++   until the event has been queued (asynchronous).  The caller must guarantee
++   that at least one inode within the filesystem has had its reference count
++   bumped so that the filesystem can't disappear while the event is
++   outstanding.
++*/
++
++int
++dm_send_namesp_event(
++      dm_eventtype_t  event,
++      struct super_block *sb,         /* used by PREUNMOUNT */
++      struct inode    *ip1,
++      dm_right_t      vp1_right,
++      struct inode    *ip2,
++      dm_right_t      vp2_right,
++      const char      *name1,
++      const char      *name2,
++      mode_t          mode,
++      int             retcode,
++      int             flags)
++{
++      dm_namesp_event_t       *np;
++      dm_tokevent_t   *tevp;
++      dm_tokdata_t    *tdp1 = NULL;   /* primary handle for event */
++      dm_tokdata_t    *tdp2 = NULL;   /* additional handle for event */
++      size_t          nextoff;
++      int             error;
++
++      if (sb == NULL)
++              sb = ip1->i_sb;
++
++      switch (event) {
++      case DM_EVENT_PREUNMOUNT:
++              /*
++               *  PREUNMOUNT - Send the file system handle in handle1,
++               *  and the handle for the root dir in the second.  Otherwise
++               *  it's a normal sync message; i.e. succeeds or fails
++               *  depending on the app's return code.
++               *      ip1 and ip2 are both the root dir of mounted FS
++               *      vp1_right is the filesystem right.
++               *      vp2_right is the root inode right.
++               */
++
++              if (flags & DM_FLAGS_UNWANTED) {
++                      dm_change_fsys_entry(sb, DM_STATE_UNMOUNTING);
++                      return(0);
++              }
++              if (ip1 == NULL) {
++                      /* If preunmount happens after kill_super then
++                       * it's too late; there's nothing left with which
++                       * to construct an event.
++                       */
++                      return(0);
++              }
++              tdp1 = dm_sb_data(sb, ip1, vp1_right);
++              if (tdp1 == NULL)
++                      return -ENOMEM;
++              tdp2 = dm_ip_data(ip2, vp2_right, /* reference held */ 1);
++              if (tdp2 == NULL) {
++                      kmem_cache_free(dm_tokdata_cachep, tdp1);
++                      return -ENOMEM;
++              }
++              break;
++
++      case DM_EVENT_NOSPACE:
++              /* vp1_right is the filesystem right. */
++
++              tdp1 = dm_sb_data(sb, ip1, vp1_right);
++              if (tdp1 == NULL)
++                      return -ENOMEM;
++              tdp2 = dm_ip_data(ip2, vp2_right, /* reference held */ 1); /* additional info - not in the spec */
++              if (tdp2 == NULL) {
++                      kmem_cache_free(dm_tokdata_cachep, tdp1);
++                      return -ENOMEM;
++              }
++              break;
++
++      default:
++              /* All other events only pass in inodes and don't require any
++                 special cases.
++              */
++
++              tdp1 = dm_ip_data(ip1, vp1_right, /* reference held */ 1);
++              if (tdp1 == NULL)
++                      return -ENOMEM;
++              if (ip2) {
++                      tdp2 = dm_ip_data(ip2, vp2_right, /* reference held */ 1);
++                      if (tdp2 == NULL) {
++                              kmem_cache_free(dm_tokdata_cachep, tdp1);
++                              return -ENOMEM;
++                      }
++              }
++      }
++
++      /* Calculate the size of the event in bytes and allocate zeroed memory
++         for it.
++      */
++
++      tevp = dm_evt_create_tevp(event,
++              HANDLE_SIZE(tdp1) + (ip2 ? HANDLE_SIZE(tdp2) : 0) +
++              (name1 ? strlen(name1) + 1 : 0) +
++              (name2 ? strlen(name2) + 1 : 0), (void **)&np);
++      if (tevp == NULL) {
++              if (tdp1)
++                      kmem_cache_free(dm_tokdata_cachep, tdp1);
++              if (tdp2)
++                      kmem_cache_free(dm_tokdata_cachep, tdp2);
++              return(-ENOMEM);
++      }
++
++      dm_add_handle_to_event(tevp, tdp1);
++      if (ip2)
++              dm_add_handle_to_event(tevp, tdp2);
++
++      /* Now copy in all the dm_namesp_event_t specific fields. */
++
++      np->ne_handle1.vd_offset = sizeof(*np);
++      np->ne_handle1.vd_length = HANDLE_SIZE(tdp1);
++      memcpy((char *) np + np->ne_handle1.vd_offset, &tdp1->td_handle,
++                      np->ne_handle1.vd_length);
++      nextoff = GETNEXTOFF(np->ne_handle1);
++      if (ip2) {
++              np->ne_handle2.vd_offset = nextoff;
++              np->ne_handle2.vd_length = HANDLE_SIZE(tdp2);
++              memcpy((char *)np + np->ne_handle2.vd_offset, &tdp2->td_handle,
++                              np->ne_handle2.vd_length);
++              nextoff = GETNEXTOFF(np->ne_handle2);
++      }
++      if (name1) {
++              np->ne_name1.vd_offset = nextoff;
++              np->ne_name1.vd_length = strlen(name1) + 1;
++              memcpy((char *)np + np->ne_name1.vd_offset, name1,
++                              np->ne_name1.vd_length);
++              nextoff = GETNEXTOFF(np->ne_name1);
++      }
++      if (name2) {
++              np->ne_name2.vd_offset = nextoff;
++              np->ne_name2.vd_length = strlen(name2) + 1;
++              memcpy((char *)np + np->ne_name2.vd_offset, name2,
++                              np->ne_name2.vd_length);
++      }
++      np->ne_mode = mode;
++      np->ne_retcode = retcode;
++
++      /* Queue the message and wait for the reply. */
++
++      error = dm_enqueue_normal_event(sb, &tevp, flags);
++
++      /* If no errors occurred, we must leave with the same rights we had
++         upon entry.  If errors occurred, we must leave with no rights.
++      */
++
++      dm_evt_rele_tevp(tevp, error);
++
++      if (!error && event == DM_EVENT_PREUNMOUNT) {
++              dm_change_fsys_entry(sb, DM_STATE_UNMOUNTING);
++      }
++
++      return(error);
++}
++
++
++/*
++ *  Send a message of type "DM_EVENT_USER".  Since no inode is involved, we
++ *  don't have to worry about rights here.
++ */
++
++int
++dm_send_msg(
++      dm_sessid_t     targetsid,
++      dm_msgtype_t    msgtype,                /* SYNC or ASYNC */
++      size_t          buflen,
++      void            __user *bufp)
++{
++      dm_tokevent_t   *tevp;
++      int             sync;
++      void            *msgp;
++      int             error;
++
++      if (buflen > DM_MAX_MSG_DATA)
++              return(-E2BIG);
++      if (msgtype == DM_MSGTYPE_ASYNC) {
++              sync = 0;
++      } else if (msgtype == DM_MSGTYPE_SYNC) {
++              sync = 1;
++      } else {
++              return(-EINVAL);
++      }
++
++      tevp = dm_evt_create_tevp(DM_EVENT_USER, buflen, (void **)&msgp);
++      if (tevp == NULL)
++              return -ENOMEM;
++
++      if (buflen && copy_from_user(msgp, bufp, buflen)) {
++              dm_evt_rele_tevp(tevp, 0);
++              return(-EFAULT);
++      }
++
++      /* Enqueue the request and wait for the reply. */
++
++      error = dm_enqueue_sendmsg_event(targetsid, tevp, sync);
++
++      /* Destroy the tevp and return the reply.  (dm_pending is not
++         supported here.)
++      */
++
++      dm_evt_rele_tevp(tevp, error);
++
++      return(error);
++}
++
++
++/*
++ *  Send a message of type "DM_EVENT_USER".  Since no inode is involved, we
++ *  don't have to worry about rights here.
++ */
++
++int
++dm_create_userevent(
++      dm_sessid_t     sid,
++      size_t          msglen,
++      void            __user *msgdatap,
++      dm_token_t      __user *tokenp)         /* return token created */
++{
++      dm_tokevent_t   *tevp;
++      dm_token_t      token;
++      int             error;
++      void            *msgp;
++
++      if (msglen > DM_MAX_MSG_DATA)
++              return(-E2BIG);
++
++      tevp = dm_evt_create_tevp(DM_EVENT_USER, msglen, (void **)&msgp);
++      if (tevp == NULL)
++              return(-ENOMEM);
++
++      if (msglen && copy_from_user(msgp, msgdatap, msglen)) {
++              dm_evt_rele_tevp(tevp, 0);
++              return(-EFAULT);
++      }
++
++      /* Queue the message.  If that didn't work, free the tevp structure. */
++
++      if ((error = dm_enqueue_user_event(sid, tevp, &token)) != 0)
++              dm_evt_rele_tevp(tevp, 0);
++
++      if (!error && copy_to_user(tokenp, &token, sizeof(token)))
++              error = -EFAULT;
++
++      return(error);
++}
+Index: linux-2.6.26/fs/dmapi/dmapi.h
+===================================================================
+--- /dev/null
++++ linux-2.6.26/fs/dmapi/dmapi.h
+@@ -0,0 +1,1086 @@
++/*
++ * Copyright (c) 1995-2003 Silicon Graphics, Inc.  All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of version 2.1 of the GNU Lesser General Public License
++ * as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it would be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
++ *
++ * Further, this software is distributed without any warranty that it is
++ * free of the rightful claim of any third person regarding infringement
++ * or the like.        Any license provided herein, whether implied or
++ * otherwise, applies only to this software file.  Patent licenses, if
++ * any, provided herein do not apply to combinations of this program with
++ * other software, or any other product whatsoever.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this program; if not, write the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307,
++ * USA.
++ *
++ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
++ * Mountain View, CA  94043, or:
++ *
++ * http://www.sgi.com
++ *
++ * For further information regarding this notice, see:
++ *
++ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
++ */
++
++#ifndef __DMAPI_H__
++#define __DMAPI_H__
++
++#ifdef        __cplusplus
++extern        "C" {
++#endif
++
++#ifndef __KERNEL__
++#include <sys/types.h>
++#endif
++#include <linux/types.h>
++
++#ifndef __user
++#define __user
++#endif
++
++/**************************************************************************
++ *                                                                      *
++ * The SGI implementation of DMAPI is based upon the X/Open document    *
++ *    Systems Management: Data Storage Managment (XDSM) API             *
++ * dated February 1997.        Not all DMAPI functions and structure fields     *
++ * have been implemented.  Most importantly, the DMAPI functions        *
++ * dm_request_right, dm_release_right, dm_query_right, dm_upgrade_right         *
++ * and dm_downgrade_right do not work as described in the specification.  *
++ *                                                                      *
++ * The XFS filesystem currently does not allow its locking mechanisms to  *
++ * be externally accessed from user space.  While the above-mentioned   *
++ * dm_xxx_right functions exist and can be called by applications, they         *
++ * always return successfully without actually obtaining any locks      *
++ * within the filesystem.                                               *
++ *                                                                      *
++ * Applications which do not need full rights support and which only    *
++ * make dm_xxx_right calls in order to satisfy the input requirements of  *
++ * other DMAPI calls should be able to use these routines to avoid      *
++ * having to implement special-case code for SGI platforms.  Applications *
++ * which truely need the capabilities of a full implementation of rights  *
++ * will unfortunately have to come up with alternate software solutions         *
++ * until such time as rights can be completely implemented.             *
++ *                                                                      *
++ * Functions and structure fields defined within this file which are not  *
++ * supported in the SGI implementation of DMAPI are indicated by comments *
++ * following their definitions such as "not supported", or "not                 *
++ * completely supported".  Any function or field not so marked may be   *
++ * assumed to work exactly according to the spec.                       *
++ *                                                                      *
++ **************************************************************************/
++
++
++
++/* The first portion of this file contains defines and typedefs that are
++   DMAPI implementation-dependent, and could be different on other platforms.
++*/
++
++typedef __s64         dm_attrloc_t;
++typedef unsigned int  dm_boolean_t;
++typedef __u64         dm_eventset_t;
++typedef __u64         dm_fsid_t;
++typedef __u64         dm_ino_t;
++typedef __u32         dm_igen_t;
++typedef __s64         dm_off_t;
++typedef unsigned int  dm_sequence_t;
++typedef int           dm_sessid_t;
++typedef __u64         dm_size_t;
++typedef __s64         dm_ssize_t;
++typedef int           dm_token_t;
++
++/* XXX dev_t, mode_t, and nlink_t are not the same size in kernel space
++   and user space.  This affects the field offsets for dm_stat_t.
++   The following solution is temporary.
++
++   user space sizes:  dev_t=8  mode_t=4        nlink_t=4
++   kernel space          :  dev_t=2  mode_t=2  nlink_t=2
++
++*/
++typedef __s64         dm_dev_t;
++typedef int           dm_mode_t;
++typedef int           dm_nlink_t;
++
++
++#define DM_REGION_NOEVENT     0x0
++#define DM_REGION_READ                0x1
++#define DM_REGION_WRITE               0x2
++#define DM_REGION_TRUNCATE    0x4
++
++/* Values for the mask argument used with dm_get_fileattr, dm_get_bulkattr,
++   dm_get_dirattrs, and dm_set_fileattr.
++*/
++
++#define DM_AT_MODE    0x0001
++#define DM_AT_UID     0x0002
++#define DM_AT_GID     0x0004
++#define DM_AT_ATIME   0x0008
++#define DM_AT_MTIME   0x0010
++#define DM_AT_CTIME   0x0020
++#define DM_AT_SIZE    0x0040
++#define DM_AT_DTIME   0x0080
++#define DM_AT_HANDLE  0x0100
++#define DM_AT_EMASK   0x0200
++#define DM_AT_PMANR   0x0400
++#define DM_AT_PATTR   0x0800
++#define DM_AT_STAT    0x1000
++#define DM_AT_CFLAG   0x2000
++
++#define DM_EV_WAIT    0x1             /* used in dm_get_events() */
++
++#define DM_MOUNT_RDONLY 0x1           /* me_mode field in dm_mount_event_t */
++
++#define DM_RR_WAIT    0x1
++
++#define DM_UNMOUNT_FORCE 0x1          /* ne_mode field in dm_namesp_event_t */
++
++#define DM_WRITE_SYNC 0x1             /* used in dm_write_invis() */
++
++#define DM_SESSION_INFO_LEN   256
++#define DM_NO_SESSION         0
++#define DM_TRUE                       1
++#define DM_FALSE              0
++#define DM_INVALID_TOKEN      0
++#define DM_NO_TOKEN           (-1)
++#define DM_INVALID_HANP               NULL
++#define DM_INVALID_HLEN               0
++#define DM_GLOBAL_HANP                ((void *)(1LL))
++#define DM_GLOBAL_HLEN                ((size_t)(1))
++#define DM_VER_STR_CONTENTS   "SGI DMAPI (XDSM) API, Release 1.1."
++
++
++#define DMEV_SET(event_type, event_list) \
++      ((event_list) |= (1 << (event_type)))
++#define DMEV_CLR(event_type, event_list) \
++      ((event_list) &= ~(1 << (event_type)))
++#define DMEV_ISSET(event_type, event_list) \
++      (int)(((event_list) & (1 << (event_type))) != 0)
++#define DMEV_ZERO(event_list) \
++      (event_list) = 0
++
++
++typedef struct {
++      int     vd_offset;      /* offset from start of containing struct */
++      unsigned int    vd_length;      /* length of data starting at vd_offset */
++} dm_vardata_t;
++
++#define DM_GET_VALUE(p, field, type) \
++      ((type) ((char *)(p) + (p)->field.vd_offset))
++
++#define DM_GET_LEN(p, field) \
++      ((p)->field.vd_length)
++
++#define DM_STEP_TO_NEXT(p, type) \
++      ((type) ((p)->_link ? (char *)(p) + (p)->_link : NULL))
++
++
++
++
++/* The remainder of this include file contains defines, typedefs, and
++   structures which are strictly defined by the DMAPI 2.3 specification.
++
++   (The _link field which appears in several structures is an
++   implementation-specific way to implement DM_STEP_TO_NEXT, and
++   should not be referenced directly by application code.)
++*/
++
++
++#define DM_ATTR_NAME_SIZE     8
++
++
++struct dm_attrname {
++      unsigned char   an_chars[DM_ATTR_NAME_SIZE];
++};
++typedef struct dm_attrname    dm_attrname_t;
++
++
++struct dm_attrlist {
++      int             _link;
++      dm_attrname_t   al_name;
++      dm_vardata_t    al_data;
++};
++typedef struct dm_attrlist    dm_attrlist_t;
++
++
++typedef enum {
++      DM_CONFIG_INVALID,
++      DM_CONFIG_BULKALL,
++      DM_CONFIG_CREATE_BY_HANDLE,
++      DM_CONFIG_DTIME_OVERLOAD,
++      DM_CONFIG_LEGACY,
++      DM_CONFIG_LOCK_UPGRADE,
++      DM_CONFIG_MAX_ATTR_ON_DESTROY,
++      DM_CONFIG_MAX_ATTRIBUTE_SIZE,
++      DM_CONFIG_MAX_HANDLE_SIZE,
++      DM_CONFIG_MAX_MANAGED_REGIONS,
++      DM_CONFIG_MAX_MESSAGE_DATA,
++      DM_CONFIG_OBJ_REF,
++      DM_CONFIG_PENDING,
++      DM_CONFIG_PERS_ATTRIBUTES,
++      DM_CONFIG_PERS_EVENTS,
++      DM_CONFIG_PERS_INHERIT_ATTRIBS,
++      DM_CONFIG_PERS_MANAGED_REGIONS,
++      DM_CONFIG_PUNCH_HOLE,
++      DM_CONFIG_TOTAL_ATTRIBUTE_SPACE,
++      DM_CONFIG_WILL_RETRY
++} dm_config_t;
++
++
++struct        dm_dioinfo {                    /* non-standard SGI addition */
++      unsigned int    d_mem;
++      unsigned int    d_miniosz;
++      unsigned int    d_maxiosz;
++      dm_boolean_t    d_dio_only;
++};
++typedef struct dm_dioinfo     dm_dioinfo_t;
++
++
++struct dm_dispinfo {
++      int             _link;
++      unsigned int    di_pad1;                /* reserved; do not reference */
++      dm_vardata_t    di_fshandle;
++      dm_eventset_t   di_eventset;
++};
++typedef struct dm_dispinfo    dm_dispinfo_t;
++
++
++#ifndef HAVE_DM_EVENTTYPE_T
++#define HAVE_DM_EVENTTYPE_T
++typedef enum {
++      DM_EVENT_INVALID        = -1,
++      DM_EVENT_CANCEL         = 0,            /* not supported */
++      DM_EVENT_MOUNT          = 1,
++      DM_EVENT_PREUNMOUNT     = 2,
++      DM_EVENT_UNMOUNT        = 3,
++      DM_EVENT_DEBUT          = 4,            /* not supported */
++      DM_EVENT_CREATE         = 5,
++      DM_EVENT_CLOSE          = 6,            /* not supported */
++      DM_EVENT_POSTCREATE     = 7,
++      DM_EVENT_REMOVE         = 8,
++      DM_EVENT_POSTREMOVE     = 9,
++      DM_EVENT_RENAME         = 10,
++      DM_EVENT_POSTRENAME     = 11,
++      DM_EVENT_LINK           = 12,
++      DM_EVENT_POSTLINK       = 13,
++      DM_EVENT_SYMLINK        = 14,
++      DM_EVENT_POSTSYMLINK    = 15,
++      DM_EVENT_READ           = 16,
++      DM_EVENT_WRITE          = 17,
++      DM_EVENT_TRUNCATE       = 18,
++      DM_EVENT_ATTRIBUTE      = 19,
++      DM_EVENT_DESTROY        = 20,
++      DM_EVENT_NOSPACE        = 21,
++      DM_EVENT_USER           = 22,
++      DM_EVENT_MAX            = 23
++} dm_eventtype_t;
++#endif
++
++
++struct dm_eventmsg {
++      int             _link;
++      dm_eventtype_t  ev_type;
++      dm_token_t      ev_token;
++      dm_sequence_t   ev_sequence;
++      dm_vardata_t    ev_data;
++};
++typedef struct dm_eventmsg    dm_eventmsg_t;
++
++
++struct dm_cancel_event {                      /* not supported */
++      dm_sequence_t   ce_sequence;
++      dm_token_t      ce_token;
++};
++typedef struct dm_cancel_event        dm_cancel_event_t;
++
++
++struct dm_data_event {
++      dm_vardata_t    de_handle;
++      dm_off_t        de_offset;
++      dm_size_t       de_length;
++};
++typedef struct dm_data_event dm_data_event_t;
++
++struct dm_destroy_event {
++      dm_vardata_t            ds_handle;
++      dm_attrname_t           ds_attrname;
++      dm_vardata_t            ds_attrcopy;
++};
++typedef struct dm_destroy_event dm_destroy_event_t;
++
++struct dm_mount_event {
++      dm_mode_t       me_mode;
++      dm_vardata_t    me_handle1;
++      dm_vardata_t    me_handle2;
++      dm_vardata_t    me_name1;
++      dm_vardata_t    me_name2;
++      dm_vardata_t    me_roothandle;
++};
++typedef struct dm_mount_event dm_mount_event_t;
++
++struct dm_namesp_event {
++      dm_mode_t       ne_mode;
++      dm_vardata_t    ne_handle1;
++      dm_vardata_t    ne_handle2;
++      dm_vardata_t    ne_name1;
++      dm_vardata_t    ne_name2;
++      int             ne_retcode;
++};
++typedef struct dm_namesp_event dm_namesp_event_t;
++
++
++typedef enum {
++      DM_EXTENT_INVALID,
++      DM_EXTENT_RES,
++      DM_EXTENT_HOLE
++} dm_extenttype_t;
++
++
++struct dm_extent {
++      dm_extenttype_t ex_type;
++      unsigned int    ex_pad1;                /* reserved; do not reference */
++      dm_off_t        ex_offset;
++      dm_size_t       ex_length;
++};
++typedef struct dm_extent dm_extent_t;
++
++struct dm_fileattr {
++      dm_mode_t       fa_mode;
++      uid_t           fa_uid;
++      gid_t           fa_gid;
++      time_t          fa_atime;
++      time_t          fa_mtime;
++      time_t          fa_ctime;
++      time_t          fa_dtime;
++      unsigned int    fa_pad1;                /* reserved; do not reference */
++      dm_off_t        fa_size;
++};
++typedef struct dm_fileattr dm_fileattr_t;
++
++
++struct dm_inherit {                           /* not supported */
++      dm_attrname_t   ih_name;
++      dm_mode_t       ih_filetype;
++};
++typedef struct dm_inherit dm_inherit_t;
++
++
++typedef enum {
++      DM_MSGTYPE_INVALID,
++      DM_MSGTYPE_SYNC,
++      DM_MSGTYPE_ASYNC
++} dm_msgtype_t;
++
++
++struct dm_region {
++      dm_off_t        rg_offset;
++      dm_size_t       rg_size;
++      unsigned int    rg_flags;
++      unsigned int    rg_pad1;                /* reserved; do not reference */
++};
++typedef struct dm_region dm_region_t;
++
++
++typedef enum {
++      DM_RESP_INVALID,
++      DM_RESP_CONTINUE,
++      DM_RESP_ABORT,
++      DM_RESP_DONTCARE
++} dm_response_t;
++
++
++#ifndef HAVE_DM_RIGHT_T
++#define HAVE_DM_RIGHT_T
++typedef enum {
++      DM_RIGHT_NULL,
++      DM_RIGHT_SHARED,
++      DM_RIGHT_EXCL
++} dm_right_t;
++#endif
++
++
++struct dm_stat {
++      int             _link;
++      dm_vardata_t    dt_handle;
++      dm_vardata_t    dt_compname;
++      int             dt_nevents;
++      dm_eventset_t   dt_emask;
++      int             dt_pers;                /* field not supported */
++      int             dt_pmanreg;
++      time_t          dt_dtime;
++      unsigned int    dt_change;              /* field not supported */
++      unsigned int    dt_pad1;                /* reserved; do not reference */
++      dm_dev_t        dt_dev;
++      dm_ino_t        dt_ino;
++      dm_mode_t       dt_mode;
++      dm_nlink_t      dt_nlink;
++      uid_t           dt_uid;
++      gid_t           dt_gid;
++      dm_dev_t        dt_rdev;
++      unsigned int    dt_pad2;                /* reserved; do not reference */
++      dm_off_t        dt_size;
++      time_t          dt_atime;
++      time_t          dt_mtime;
++      time_t          dt_ctime;
++      unsigned int    dt_blksize;
++      dm_size_t       dt_blocks;
++
++      /* Non-standard filesystem-specific fields.  Currently XFS is the only
++         supported filesystem type.
++      */
++
++      __u64   dt_pad3;        /* reserved; do not reference */
++      int             dt_fstype;      /* filesystem index; see sysfs(2) */
++      union   {
++              struct  {
++                      dm_igen_t       igen;
++                      unsigned int    xflags;
++                      unsigned int    extsize;
++                      unsigned int    extents;
++                      unsigned short  aextents;
++                      unsigned short  dmstate;
++              } sgi_xfs;
++      } fsys_dep;
++};
++typedef struct dm_stat        dm_stat_t;
++
++#define dt_xfs_igen   fsys_dep.sgi_xfs.igen
++#define dt_xfs_xflags fsys_dep.sgi_xfs.xflags
++#define dt_xfs_extsize        fsys_dep.sgi_xfs.extsize
++#define dt_xfs_extents        fsys_dep.sgi_xfs.extents
++#define dt_xfs_aextents fsys_dep.sgi_xfs.aextents
++#define dt_xfs_dmstate        fsys_dep.sgi_xfs.dmstate
++
++/* Flags for the non-standard dt_xfs_xflags field. */
++
++#define DM_XFLAG_REALTIME     0x00000001
++#define DM_XFLAG_PREALLOC     0x00000002
++#define DM_XFLAG_IMMUTABLE    0x00000008
++#define DM_XFLAG_APPEND               0x00000010
++#define DM_XFLAG_SYNC         0x00000020
++#define DM_XFLAG_NOATIME      0x00000040
++#define DM_XFLAG_NODUMP               0x00000080
++#define DM_XFLAG_HASATTR      0x80000000
++
++
++struct        dm_timestruct {
++      time_t          dm_tv_sec;
++      int             dm_tv_nsec;
++};
++typedef struct dm_timestruct dm_timestruct_t;
++
++
++struct        dm_xstat {                              /* not supported */
++      dm_stat_t       dx_statinfo;
++      dm_vardata_t    dx_attrdata;
++};
++typedef struct dm_xstat dm_xstat_t;
++
++
++#define MAXDMFSFIDSZ  46
++
++struct dm_fid {
++      __u16   dm_fid_len;             /* length of remainder  */
++      __u16   dm_fid_pad;
++      __u32   dm_fid_gen;             /* generation number    */
++      __u64   dm_fid_ino;             /* 64 bits inode number */
++};
++typedef struct dm_fid dm_fid_t;
++
++
++struct dm_handle {
++      union {
++              __s64       align;      /* force alignment of ha_fid     */
++              dm_fsid_t  _ha_fsid;    /* unique file system identifier */
++      } ha_u;
++      dm_fid_t        ha_fid;         /* file system specific file ID  */
++};
++typedef struct dm_handle dm_handle_t;
++#define ha_fsid ha_u._ha_fsid
++
++#define DM_HSIZE(handle)      (((char *) &(handle).ha_fid.dm_fid_pad   \
++                               - (char *) &(handle))                    \
++                               + (handle).ha_fid.dm_fid_len)
++
++#define DM_HANDLE_CMP(h1, h2) memcmp(h1, h2, sizeof(dm_handle_t))
++
++#define DM_FSHSIZE            sizeof(dm_fsid_t)
++
++
++/* The following list provides the prototypes for all functions defined in
++   the DMAPI interface.
++*/
++
++extern int
++dm_clear_inherit(                             /* not supported */
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token,
++      dm_attrname_t   __user *attrnamep);
++
++extern int
++dm_create_by_handle(                          /* not supported */
++      dm_sessid_t     sid,
++      void            __user *dirhanp,
++      size_t          dirhlen,
++      dm_token_t      token,
++      void            __user *hanp,
++      size_t          hlen,
++      char            __user *cname);
++
++extern int
++dm_create_session(
++      dm_sessid_t     oldsid,
++      char            __user *sessinfop,
++      dm_sessid_t     __user *newsidp);
++
++extern int
++dm_create_userevent(
++      dm_sessid_t     sid,
++      size_t          msglen,
++      void            __user *msgdatap,
++      dm_token_t      __user *tokenp);
++
++extern int
++dm_destroy_session(
++      dm_sessid_t     sid);
++
++extern int
++dm_downgrade_right(           /* not completely supported; see caveat above */
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token);
++
++extern int
++dm_fd_to_handle(
++      int             fd,
++      void            **hanpp,
++      size_t          *hlenp);
++
++extern int
++dm_find_eventmsg(
++      dm_sessid_t     sid,
++      dm_token_t      token,
++      size_t          buflen,
++      void            __user *bufp,
++      size_t          __user *rlenp);
++
++extern int
++dm_get_allocinfo(
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token,
++      dm_off_t        *offp,
++      unsigned int    nelem,
++      dm_extent_t     *extentp,
++      unsigned int    *nelemp);
++
++extern int
++dm_get_bulkall(                                       /* not supported */
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token,
++      unsigned int    mask,
++      dm_attrname_t   *attrnamep,
++      dm_attrloc_t    *locp,
++      size_t          buflen,
++      void            *bufp,
++      size_t          *rlenp);
++
++extern int
++dm_get_bulkattr(
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token,
++      unsigned int    mask,
++      dm_attrloc_t    *locp,
++      size_t          buflen,
++      void            *bufp,
++      size_t          *rlenp);
++
++extern int
++dm_get_config(
++      void            __user *hanp,
++      size_t          hlen,
++      dm_config_t     flagname,
++      dm_size_t       __user *retvalp);
++
++extern int
++dm_get_config_events(
++      void            __user *hanp,
++      size_t          hlen,
++      unsigned int    nelem,
++      dm_eventset_t   __user *eventsetp,
++      unsigned int    __user *nelemp);
++
++extern int
++dm_get_dirattrs(
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token,
++      unsigned int    mask,
++      dm_attrloc_t    *locp,
++      size_t          buflen,
++      void            *bufp,
++      size_t          *rlenp);
++
++extern int
++dm_get_dmattr(
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token,
++      dm_attrname_t   __user *attrnamep,
++      size_t          buflen,
++      void            __user *bufp,
++      size_t          __user *rlenp);
++
++extern int
++dm_get_eventlist(
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token,
++      unsigned int    nelem,
++      dm_eventset_t   __user *eventsetp,
++      unsigned int    __user *nelemp);
++
++extern int
++dm_get_events(
++      dm_sessid_t     sid,
++      unsigned int    maxmsgs,
++      unsigned int    flags,
++      size_t          buflen,
++      void            __user *bufp,
++      size_t          __user *rlenp);
++
++extern int
++dm_get_fileattr(
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token,
++      unsigned int    mask,
++      dm_stat_t       __user *statp);
++
++extern int
++dm_get_mountinfo(
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token,
++      size_t          buflen,
++      void            __user *bufp,
++      size_t          __user *rlenp);
++
++extern int
++dm_get_region(
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token,
++      unsigned int    nelem,
++      dm_region_t     __user *regbufp,
++      unsigned int    __user *nelemp);
++
++extern int
++dm_getall_disp(
++      dm_sessid_t     sid,
++      size_t          buflen,
++      void            __user *bufp,
++      size_t          __user *rlenp);
++
++extern int
++dm_getall_dmattr(
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token,
++      size_t          buflen,
++      void            __user *bufp,
++      size_t          __user *rlenp);
++
++extern int
++dm_getall_inherit(                            /* not supported */
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token,
++      unsigned int    nelem,
++      dm_inherit_t    __user *inheritbufp,
++      unsigned int    __user *nelemp);
++
++extern int
++dm_getall_sessions(
++      unsigned int    nelem,
++      dm_sessid_t     __user *sidbufp,
++      unsigned int    __user *nelemp);
++
++extern int
++dm_getall_tokens(
++      dm_sessid_t     sid,
++      unsigned int    nelem,
++      dm_token_t      __user *tokenbufp,
++      unsigned int    __user *nelemp);
++
++extern int
++dm_handle_cmp(
++      void            *hanp1,
++      size_t          hlen1,
++      void            *hanp2,
++      size_t          hlen2);
++
++extern void
++dm_handle_free(
++      void            *hanp,
++      size_t          hlen);
++
++extern u_int
++dm_handle_hash(
++      void            *hanp,
++      size_t          hlen);
++
++extern dm_boolean_t
++dm_handle_is_valid(
++      void            *hanp,
++      size_t          hlen);
++
++extern int
++dm_handle_to_fshandle(
++      void            *hanp,
++      size_t          hlen,
++      void            **fshanpp,
++      size_t          *fshlenp);
++
++extern int
++dm_handle_to_fsid(
++      void            *hanp,
++      size_t          hlen,
++      dm_fsid_t       *fsidp);
++
++extern int
++dm_handle_to_igen(
++      void            *hanp,
++      size_t          hlen,
++      dm_igen_t       *igenp);
++
++extern int
++dm_handle_to_ino(
++      void            *hanp,
++      size_t          hlen,
++      dm_ino_t        *inop);
++
++extern int
++dm_handle_to_path(
++      void            *dirhanp,
++      size_t          dirhlen,
++      void            *targhanp,
++      size_t          targhlen,
++      size_t          buflen,
++      char            *pathbufp,
++      size_t          *rlenp);
++
++extern int
++dm_init_attrloc(
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token,
++      dm_attrloc_t    __user *locp);
++
++extern int
++dm_init_service(
++      char            **versionstrpp);
++
++extern int
++dm_make_handle(
++      dm_fsid_t       *fsidp,
++      dm_ino_t        *inop,
++      dm_igen_t       *igenp,
++      void            **hanpp,
++      size_t          *hlenp);
++
++extern int
++dm_make_fshandle(
++      dm_fsid_t       *fsidp,
++      void            **hanpp,
++      size_t          *hlenp);
++
++extern int
++dm_mkdir_by_handle(                           /* not supported */
++      dm_sessid_t     sid,
++      void            __user *dirhanp,
++      size_t          dirhlen,
++      dm_token_t      token,
++      void            __user *hanp,
++      size_t          hlen,
++      char            __user *cname);
++
++extern int
++dm_move_event(
++      dm_sessid_t     srcsid,
++      dm_token_t      token,
++      dm_sessid_t     targetsid,
++      dm_token_t      __user *rtokenp);
++
++extern int
++dm_obj_ref_hold(
++      dm_sessid_t     sid,
++      dm_token_t      token,
++      void            __user *hanp,
++      size_t          hlen);
++
++extern int
++dm_obj_ref_query(
++      dm_sessid_t     sid,
++      dm_token_t      token,
++      void            *hanp,
++      size_t          hlen);
++
++extern int
++dm_obj_ref_rele(
++      dm_sessid_t     sid,
++      dm_token_t      token,
++      void            __user *hanp,
++      size_t          hlen);
++
++extern int
++dm_path_to_fshandle(
++      char            *path,
++      void            **hanpp,
++      size_t          *hlenp);
++
++extern int
++dm_path_to_handle(
++      char            *path,
++      void            **hanpp,
++      size_t          *hlenp);
++
++extern int
++dm_pending(
++      dm_sessid_t     sid,
++      dm_token_t      token,
++      dm_timestruct_t __user *delay);
++
++extern int
++dm_probe_hole(
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token,
++      dm_off_t        off,
++      dm_size_t       len,
++      dm_off_t        __user  *roffp,
++      dm_size_t       __user *rlenp);
++
++extern int
++dm_punch_hole(
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token,
++      dm_off_t        off,
++      dm_size_t       len);
++
++extern int
++dm_query_right(                       /* not completely supported; see caveat above */
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token,
++      dm_right_t      __user *rightp);
++
++extern int
++dm_query_session(
++      dm_sessid_t     sid,
++      size_t          buflen,
++      void            __user *bufp,
++      size_t          __user *rlenp);
++
++extern dm_ssize_t
++dm_read_invis(
++      dm_sessid_t     sid,
++      void            *hanp,
++      size_t          hlen,
++      dm_token_t      token,
++      dm_off_t        off,
++      dm_size_t       len,
++      void            *bufp);
++
++extern int
++dm_release_right(             /* not completely supported; see caveat above */
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token);
++
++extern int
++dm_remove_dmattr(
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token,
++      int             setdtime,
++      dm_attrname_t   __user *attrnamep);
++
++extern int
++dm_request_right(             /* not completely supported; see caveat above */
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token,
++      unsigned int    flags,
++      dm_right_t      right);
++
++extern int
++dm_respond_event(
++      dm_sessid_t     sid,
++      dm_token_t      token,
++      dm_response_t   response,
++      int             reterror,
++      size_t          buflen,
++      void            __user *respbufp);
++
++extern int
++dm_send_msg(
++      dm_sessid_t     targetsid,
++      dm_msgtype_t    msgtype,
++      size_t          buflen,
++      void            __user *bufp);
++
++extern int
++dm_set_disp(
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token,
++      dm_eventset_t   __user *eventsetp,
++      unsigned int    maxevent);
++
++extern int
++dm_set_dmattr(
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token,
++      dm_attrname_t   __user *attrnamep,
++      int             setdtime,
++      size_t          buflen,
++      void            __user *bufp);
++
++extern int
++dm_set_eventlist(
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token,
++      dm_eventset_t   __user *eventsetp,
++      unsigned int    maxevent);
++
++extern int
++dm_set_fileattr(
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token,
++      unsigned int    mask,
++      dm_fileattr_t   __user *attrp);
++
++extern int
++dm_set_inherit(                                       /* not supported */
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token,
++      dm_attrname_t   __user *attrnamep,
++      mode_t          mode);
++
++extern int
++dm_set_region(
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token,
++      unsigned int    nelem,
++      dm_region_t     __user *regbufp,
++      dm_boolean_t    __user *exactflagp);
++
++extern int
++dm_set_return_on_destroy(
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token,
++      dm_attrname_t   __user *attrnamep,
++      dm_boolean_t    enable);
++
++extern int
++dm_symlink_by_handle(                         /* not supported */
++      dm_sessid_t     sid,
++      void            __user *dirhanp,
++      size_t          dirhlen,
++      dm_token_t      token,
++      void            __user *hanp,
++      size_t          hlen,
++      char            __user *cname,
++      char            __user *path);
++
++extern int
++dm_sync_by_handle(
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token);
++
++extern int
++dm_upgrade_right(             /* not completely supported; see caveat above */
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token);
++
++extern dm_ssize_t
++dm_write_invis(
++      dm_sessid_t     sid,
++      void            *hanp,
++      size_t          hlen,
++      dm_token_t      token,
++      int             flags,
++      dm_off_t        off,
++      dm_size_t       len,
++      void            *bufp);
++
++/* Non-standard SGI additions to the DMAPI interface. */
++
++int
++dm_open_by_handle(
++      void            __user *hanp,
++      size_t          hlen,
++      int             mode);
++
++extern int
++dm_get_dioinfo(
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token,
++      dm_dioinfo_t    __user *diop);
++
++#ifdef        __cplusplus
++}
++#endif
++
++#endif /* __DMAPI_H__ */
+Index: linux-2.6.26/fs/dmapi/dmapi_handle.c
+===================================================================
+--- /dev/null
++++ linux-2.6.26/fs/dmapi/dmapi_handle.c
+@@ -0,0 +1,119 @@
++/*
++ * Copyright (c) 2000 Silicon Graphics, Inc.  All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of version 2 of the GNU General Public License as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it would be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
++ *
++ * Further, this software is distributed without any warranty that it is
++ * free of the rightful claim of any third person regarding infringement
++ * or the like.        Any license provided herein, whether implied or
++ * otherwise, applies only to this software file.  Patent licenses, if
++ * any, provided herein do not apply to combinations of this program with
++ * other software, or any other product whatsoever.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write the Free Software Foundation, Inc., 59
++ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
++ *
++ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
++ * Mountain View, CA  94043, or:
++ *
++ * http://www.sgi.com
++ *
++ * For further information regarding this notice, see:
++ *
++ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
++ */
++#include "dmapi.h"
++#include "dmapi_kern.h"
++#include "dmapi_private.h"
++
++
++int
++dm_create_by_handle(
++      dm_sessid_t     sid,
++      void            __user *dirhanp,
++      size_t          dirhlen,
++      dm_token_t      token,
++      void            __user *hanp,
++      size_t          hlen,
++      char            __user *cname)
++{
++      dm_fsys_vector_t *fsys_vector;
++      dm_tokdata_t    *tdp;
++      int             error;
++
++      error = dm_app_get_tdp(sid, dirhanp, dirhlen, token, DM_TDT_DIR,
++              DM_RIGHT_EXCL, &tdp);
++      if (error != 0)
++              return(error);
++
++      fsys_vector = dm_fsys_vector(tdp->td_ip);
++      error = fsys_vector->create_by_handle(tdp->td_ip, tdp->td_right,
++              hanp, hlen, cname);
++
++      dm_app_put_tdp(tdp);
++      return(error);
++}
++
++
++int
++dm_mkdir_by_handle(
++      dm_sessid_t     sid,
++      void            __user *dirhanp,
++      size_t          dirhlen,
++      dm_token_t      token,
++      void            __user *hanp,
++      size_t          hlen,
++      char            __user *cname)
++{
++      dm_fsys_vector_t *fsys_vector;
++      dm_tokdata_t    *tdp;
++      int             error;
++
++      error = dm_app_get_tdp(sid, dirhanp, dirhlen, token, DM_TDT_DIR,
++              DM_RIGHT_EXCL, &tdp);
++      if (error != 0)
++              return(error);
++
++      fsys_vector = dm_fsys_vector(tdp->td_ip);
++      error = fsys_vector->mkdir_by_handle(tdp->td_ip, tdp->td_right,
++              hanp, hlen, cname);
++
++      dm_app_put_tdp(tdp);
++      return(error);
++}
++
++
++int
++dm_symlink_by_handle(
++      dm_sessid_t     sid,
++      void            __user *dirhanp,
++      size_t          dirhlen,
++      dm_token_t      token,
++      void            __user *hanp,
++      size_t          hlen,
++      char            __user *cname,
++      char            __user *path)
++{
++      dm_fsys_vector_t *fsys_vector;
++      dm_tokdata_t    *tdp;
++      int             error;
++
++      error = dm_app_get_tdp(sid, dirhanp, dirhlen, token, DM_TDT_DIR,
++              DM_RIGHT_EXCL, &tdp);
++      if (error != 0)
++              return(error);
++
++      fsys_vector = dm_fsys_vector(tdp->td_ip);
++      error = fsys_vector->symlink_by_handle(tdp->td_ip, tdp->td_right,
++              hanp, hlen, cname, path);
++
++      dm_app_put_tdp(tdp);
++      return(error);
++}
+Index: linux-2.6.26/fs/dmapi/dmapi_hole.c
+===================================================================
+--- /dev/null
++++ linux-2.6.26/fs/dmapi/dmapi_hole.c
+@@ -0,0 +1,119 @@
++/*
++ * Copyright (c) 2000 Silicon Graphics, Inc.  All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of version 2 of the GNU General Public License as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it would be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
++ *
++ * Further, this software is distributed without any warranty that it is
++ * free of the rightful claim of any third person regarding infringement
++ * or the like.        Any license provided herein, whether implied or
++ * otherwise, applies only to this software file.  Patent licenses, if
++ * any, provided herein do not apply to combinations of this program with
++ * other software, or any other product whatsoever.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write the Free Software Foundation, Inc., 59
++ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
++ *
++ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
++ * Mountain View, CA  94043, or:
++ *
++ * http://www.sgi.com
++ *
++ * For further information regarding this notice, see:
++ *
++ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
++ */
++#include "dmapi.h"
++#include "dmapi_kern.h"
++#include "dmapi_private.h"
++
++
++int
++dm_get_allocinfo_rvp(
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token,
++      dm_off_t        __user  *offp,
++      u_int           nelem,
++      dm_extent_t     __user *extentp,
++      u_int           __user *nelemp,
++      int             *rvp)
++{
++      dm_fsys_vector_t *fsys_vector;
++      dm_tokdata_t    *tdp;
++      int             error;
++
++      error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_REG,
++              DM_RIGHT_SHARED, &tdp);
++      if (error != 0)
++              return(error);
++
++      fsys_vector = dm_fsys_vector(tdp->td_ip);
++      error = fsys_vector->get_allocinfo_rvp(tdp->td_ip, tdp->td_right,
++              offp, nelem, extentp, nelemp, rvp);
++
++      dm_app_put_tdp(tdp);
++      return(error);
++}
++
++
++int
++dm_probe_hole(
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token,
++      dm_off_t        off,
++      dm_size_t       len,
++      dm_off_t        __user  *roffp,
++      dm_size_t       __user *rlenp)
++{
++      dm_fsys_vector_t *fsys_vector;
++      dm_tokdata_t    *tdp;
++      int             error;
++
++      error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_REG,
++              DM_RIGHT_SHARED, &tdp);
++      if (error != 0)
++              return(error);
++
++      fsys_vector = dm_fsys_vector(tdp->td_ip);
++      error = fsys_vector->probe_hole(tdp->td_ip, tdp->td_right,
++              off, len, roffp, rlenp);
++
++      dm_app_put_tdp(tdp);
++      return(error);
++}
++
++
++int
++dm_punch_hole(
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token,
++      dm_off_t        off,
++      dm_size_t       len)
++{
++      dm_fsys_vector_t *fsys_vector;
++      dm_tokdata_t    *tdp;
++      int             error;
++
++      error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_REG,
++              DM_RIGHT_EXCL, &tdp);
++      if (error != 0)
++              return(error);
++
++      fsys_vector = dm_fsys_vector(tdp->td_ip);
++      error = fsys_vector->punch_hole(tdp->td_ip, tdp->td_right, off, len);
++
++      dm_app_put_tdp(tdp);
++      return(error);
++}
+Index: linux-2.6.26/fs/dmapi/dmapi_io.c
+===================================================================
+--- /dev/null
++++ linux-2.6.26/fs/dmapi/dmapi_io.c
+@@ -0,0 +1,142 @@
++/*
++ * Copyright (c) 2000 Silicon Graphics, Inc.  All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of version 2 of the GNU General Public License as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it would be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
++ *
++ * Further, this software is distributed without any warranty that it is
++ * free of the rightful claim of any third person regarding infringement
++ * or the like.        Any license provided herein, whether implied or
++ * otherwise, applies only to this software file.  Patent licenses, if
++ * any, provided herein do not apply to combinations of this program with
++ * other software, or any other product whatsoever.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write the Free Software Foundation, Inc., 59
++ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
++ *
++ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
++ * Mountain View, CA  94043, or:
++ *
++ * http://www.sgi.com
++ *
++ * For further information regarding this notice, see:
++ *
++ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
++ */
++#include "dmapi.h"
++#include "dmapi_kern.h"
++#include "dmapi_private.h"
++
++
++int
++dm_read_invis_rvp(
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token,
++      dm_off_t        off,
++      dm_size_t       len,
++      void            __user *bufp,
++      int             *rvp)
++{
++      dm_fsys_vector_t *fsys_vector;
++      dm_tokdata_t    *tdp;
++      int             error;
++
++      error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_REG,
++              DM_RIGHT_SHARED, &tdp);
++      if (error != 0)
++              return(error);
++
++      fsys_vector = dm_fsys_vector(tdp->td_ip);
++      error = fsys_vector->read_invis_rvp(tdp->td_ip, tdp->td_right,
++              off, len, bufp, rvp);
++
++      dm_app_put_tdp(tdp);
++      return(error);
++}
++
++
++int
++dm_write_invis_rvp(
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token,
++      int             flags,
++      dm_off_t        off,
++      dm_size_t       len,
++      void            __user *bufp,
++      int             *rvp)
++{
++      dm_fsys_vector_t *fsys_vector;
++      dm_tokdata_t    *tdp;
++      int             error;
++
++      error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_REG,
++              DM_RIGHT_EXCL, &tdp);
++      if (error != 0)
++              return(error);
++
++      fsys_vector = dm_fsys_vector(tdp->td_ip);
++      error = fsys_vector->write_invis_rvp(tdp->td_ip, tdp->td_right,
++              flags, off, len, bufp, rvp);
++
++      dm_app_put_tdp(tdp);
++      return(error);
++}
++
++
++int
++dm_sync_by_handle (
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token)
++{
++      dm_fsys_vector_t *fsys_vector;
++      dm_tokdata_t    *tdp;
++      int             error;
++
++      error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_REG,
++              DM_RIGHT_EXCL, &tdp);
++      if (error != 0)
++              return(error);
++
++      fsys_vector = dm_fsys_vector(tdp->td_ip);
++      error = fsys_vector->sync_by_handle(tdp->td_ip, tdp->td_right);
++
++      dm_app_put_tdp(tdp);
++      return(error);
++}
++
++
++int
++dm_get_dioinfo (
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token,
++      dm_dioinfo_t    __user *diop)
++{
++      dm_fsys_vector_t *fsys_vector;
++      dm_tokdata_t    *tdp;
++      int             error;
++
++      error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_REG,
++              DM_RIGHT_SHARED, &tdp);
++      if (error != 0)
++              return(error);
++
++      fsys_vector = dm_fsys_vector(tdp->td_ip);
++      error = fsys_vector->get_dioinfo(tdp->td_ip, tdp->td_right, diop);
++
++      dm_app_put_tdp(tdp);
++      return(error);
++}
+Index: linux-2.6.26/fs/dmapi/dmapi_kern.h
+===================================================================
+--- /dev/null
++++ linux-2.6.26/fs/dmapi/dmapi_kern.h
+@@ -0,0 +1,599 @@
++/*
++ * Copyright (c) 2000-2005 Silicon Graphics, Inc.  All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of version 2 of the GNU General Public License as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it would be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
++ *
++ * Further, this software is distributed without any warranty that it is
++ * free of the rightful claim of any third person regarding infringement
++ * or the like.        Any license provided herein, whether implied or
++ * otherwise, applies only to this software file.  Patent licenses, if
++ * any, provided herein do not apply to combinations of this program with
++ * other software, or any other product whatsoever.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write the Free Software Foundation, Inc., 59
++ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
++ *
++ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
++ * Mountain View, CA  94043, or:
++ *
++ * http://www.sgi.com
++ *
++ * For further information regarding this notice, see:
++ *
++ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
++ */
++
++#ifndef __DMAPI_KERN_H__
++#define __DMAPI_KERN_H__
++
++#include <linux/fs.h>
++
++union sys_dmapi_uarg {
++      void *p;
++      __u64 u;
++};
++typedef union sys_dmapi_uarg sys_dmapi_u;
++
++struct sys_dmapi_args {
++      sys_dmapi_u uarg1, uarg2, uarg3, uarg4, uarg5, uarg6, uarg7, uarg8,
++              uarg9, uarg10, uarg11;
++};
++typedef struct sys_dmapi_args sys_dmapi_args_t;
++
++#define DM_Uarg(uap,i)        uap->uarg##i.u
++#define DM_Parg(uap,i)        uap->uarg##i.p
++
++#ifdef __KERNEL__
++
++struct dm_handle_t;
++
++/* The first group of definitions and prototypes define the filesystem's
++   interface into the DMAPI code.
++*/
++
++
++/* Definitions used for the flags field on dm_send_data_event(),
++   dm_send_unmount_event(), and dm_send_namesp_event() calls.
++*/
++
++#define DM_FLAGS_NDELAY               0x001   /* return EAGAIN after dm_pending() */
++#define DM_FLAGS_UNWANTED     0x002   /* event not in fsys dm_eventset_t */
++
++/* Possible code levels reported by dm_code_level(). */
++
++#define DM_CLVL_INIT  0       /* DMAPI prior to X/Open compliance */
++#define DM_CLVL_XOPEN 1       /* X/Open compliant DMAPI */
++
++
++/*
++ * Filesystem operations accessed by the DMAPI core.
++ */
++struct filesystem_dmapi_operations {
++      int (*get_fsys_vector)(struct super_block *sb, void *addr);
++      int (*fh_to_inode)(struct super_block *sb, struct inode **ip,
++                         dm_fid_t *fid);
++      const struct file_operations * (*get_invis_ops)(struct inode *ip);
++      int (*inode_to_fh)(struct inode *ip, dm_fid_t *fid,
++                         dm_fsid_t *fsid );
++      void (*get_fsid)(struct super_block *sb, dm_fsid_t *fsid);
++#define HAVE_DM_QUEUE_FLUSH
++      int (*flushing)(struct inode *ip);
++};
++
++
++/* Prototypes used outside of the DMI module/directory. */
++
++int           dm_send_data_event(
++                      dm_eventtype_t  event,
++                      struct inode    *ip,
++                      dm_right_t      vp_right,
++                      dm_off_t        off,
++                      size_t          len,
++                      int             flags);
++
++int           dm_send_destroy_event(
++                      struct inode    *ip,
++                      dm_right_t      vp_right);
++
++int           dm_send_mount_event(
++                      struct super_block      *sb,
++                      dm_right_t      vfsp_right,
++                      struct inode    *ip,
++                      dm_right_t      vp_right,
++                      struct inode    *rootip,
++                      dm_right_t      rootvp_right,
++                      char            *name1,
++                      char            *name2);
++
++int           dm_send_namesp_event(
++                      dm_eventtype_t  event,
++                      struct super_block      *sb,
++                      struct inode    *ip1,
++                      dm_right_t      vp1_right,
++                      struct inode    *ip2,
++                      dm_right_t      vp2_right,
++                      const char      *name1,
++                      const char      *name2,
++                      mode_t          mode,
++                      int             retcode,
++                      int             flags);
++
++void          dm_send_unmount_event(
++                      struct super_block *sbp,
++                      struct inode    *ip,
++                      dm_right_t      sbp_right,
++                      mode_t          mode,
++                      int             retcode,
++                      int             flags);
++
++int           dm_code_level(void);
++
++int           dm_ip_to_handle (
++                      struct inode    *ip,
++                      dm_handle_t     *handlep);
++
++#define HAVE_DM_RELEASE_THREADS_ERRNO
++int           dm_release_threads(
++                      struct super_block      *sb,
++                      struct inode            *inode,
++                      int                     errno);
++
++void          dmapi_register(
++                      struct file_system_type *fstype,
++                      struct filesystem_dmapi_operations *dmapiops);
++
++void          dmapi_unregister(
++                      struct file_system_type *fstype);
++
++int           dmapi_registered(
++                      struct file_system_type *fstype,
++                      struct filesystem_dmapi_operations **dmapiops);
++
++
++/* The following prototypes and definitions are used by DMAPI as its
++   interface into the filesystem code.        Communication between DMAPI and the
++   filesystem are established as follows:
++   1. DMAPI uses the VFS_DMAPI_FSYS_VECTOR to ask for the addresses
++      of all the functions within the filesystem that it may need to call.
++   2. The filesystem returns an array of function name/address pairs which
++      DMAPI builds into a function vector.
++   The VFS_DMAPI_FSYS_VECTOR call is only made one time for a particular
++   filesystem type.  From then on, DMAPI uses its function vector to call the
++   filesystem functions directly.  Functions in the array which DMAPI doesn't
++   recognize are ignored.  A dummy function which returns ENOSYS is used for
++   any function that DMAPI needs but which was not provided by the filesystem.
++   If XFS doesn't recognize the VFS_DMAPI_FSYS_VECTOR, DMAPI assumes that it
++   doesn't have the X/Open support code; in this case DMAPI uses the XFS-code
++   originally bundled within DMAPI.
++
++   The goal of this interface is allow incremental changes to be made to
++   both the filesystem and to DMAPI while minimizing inter-patch dependencies,
++   and to eventually allow DMAPI to support multiple filesystem types at the
++   same time should that become necessary.
++*/
++
++typedef enum {
++      DM_FSYS_CLEAR_INHERIT           =  0,
++      DM_FSYS_CREATE_BY_HANDLE        =  1,
++      DM_FSYS_DOWNGRADE_RIGHT         =  2,
++      DM_FSYS_GET_ALLOCINFO_RVP       =  3,
++      DM_FSYS_GET_BULKALL_RVP         =  4,
++      DM_FSYS_GET_BULKATTR_RVP        =  5,
++      DM_FSYS_GET_CONFIG              =  6,
++      DM_FSYS_GET_CONFIG_EVENTS       =  7,
++      DM_FSYS_GET_DESTROY_DMATTR      =  8,
++      DM_FSYS_GET_DIOINFO             =  9,
++      DM_FSYS_GET_DIRATTRS_RVP        = 10,
++      DM_FSYS_GET_DMATTR              = 11,
++      DM_FSYS_GET_EVENTLIST           = 12,
++      DM_FSYS_GET_FILEATTR            = 13,
++      DM_FSYS_GET_REGION              = 14,
++      DM_FSYS_GETALL_DMATTR           = 15,
++      DM_FSYS_GETALL_INHERIT          = 16,
++      DM_FSYS_INIT_ATTRLOC            = 17,
++      DM_FSYS_MKDIR_BY_HANDLE         = 18,
++      DM_FSYS_PROBE_HOLE              = 19,
++      DM_FSYS_PUNCH_HOLE              = 20,
++      DM_FSYS_READ_INVIS_RVP          = 21,
++      DM_FSYS_RELEASE_RIGHT           = 22,
++      DM_FSYS_REMOVE_DMATTR           = 23,
++      DM_FSYS_REQUEST_RIGHT           = 24,
++      DM_FSYS_SET_DMATTR              = 25,
++      DM_FSYS_SET_EVENTLIST           = 26,
++      DM_FSYS_SET_FILEATTR            = 27,
++      DM_FSYS_SET_INHERIT             = 28,
++      DM_FSYS_SET_REGION              = 29,
++      DM_FSYS_SYMLINK_BY_HANDLE       = 30,
++      DM_FSYS_SYNC_BY_HANDLE          = 31,
++      DM_FSYS_UPGRADE_RIGHT           = 32,
++      DM_FSYS_WRITE_INVIS_RVP         = 33,
++      DM_FSYS_OBJ_REF_HOLD            = 34,
++      DM_FSYS_MAX                     = 35
++} dm_fsys_switch_t;
++
++
++#define DM_FSYS_OBJ   0x1             /* object refers to a fsys handle */
++
++
++/*
++ *  Prototypes for filesystem-specific functions.
++ */
++
++typedef int   (*dm_fsys_clear_inherit_t)(
++                      struct inode    *ip,
++                      dm_right_t      right,
++                      dm_attrname_t   __user *attrnamep);
++
++typedef int   (*dm_fsys_create_by_handle_t)(
++                      struct inode    *ip,
++                      dm_right_t      right,
++                      void            __user *hanp,
++                      size_t          hlen,
++                      char            __user *cname);
++
++typedef int   (*dm_fsys_downgrade_right_t)(
++                      struct inode    *ip,
++                      dm_right_t      right,
++                      u_int           type);          /* DM_FSYS_OBJ or zero */
++
++typedef int   (*dm_fsys_get_allocinfo_rvp_t)(
++                      struct inode    *ip,
++                      dm_right_t      right,
++                      dm_off_t        __user  *offp,
++                      u_int           nelem,
++                      dm_extent_t     __user *extentp,
++                      u_int           __user *nelemp,
++                      int             *rvalp);
++
++typedef int   (*dm_fsys_get_bulkall_rvp_t)(
++                      struct inode    *ip,            /* root inode */
++                      dm_right_t      right,
++                      u_int           mask,
++                      dm_attrname_t   __user *attrnamep,
++                      dm_attrloc_t    __user *locp,
++                      size_t          buflen,
++                      void            __user *bufp,
++                      size_t          __user *rlenp,
++                      int             *rvalp);
++
++typedef int   (*dm_fsys_get_bulkattr_rvp_t)(
++                      struct inode    *ip,            /* root inode */
++                      dm_right_t      right,
++                      u_int           mask,
++                      dm_attrloc_t    __user *locp,
++                      size_t          buflen,
++                      void            __user *bufp,
++                      size_t          __user *rlenp,
++                      int             *rvalp);
++
++typedef int   (*dm_fsys_get_config_t)(
++                      struct inode    *ip,
++                      dm_right_t      right,
++                      dm_config_t     flagname,
++                      dm_size_t       __user *retvalp);
++
++typedef int   (*dm_fsys_get_config_events_t)(
++                      struct inode    *ip,
++                      dm_right_t      right,
++                      u_int           nelem,
++                      dm_eventset_t   __user *eventsetp,
++                      u_int           __user *nelemp);
++
++typedef int   (*dm_fsys_get_destroy_dmattr_t)(
++                      struct inode    *ip,
++                      dm_right_t      right,
++                      dm_attrname_t   *attrnamep,
++                      char            **valuepp,
++                      int             *vlenp);
++
++typedef int   (*dm_fsys_get_dioinfo_t)(
++                      struct inode    *ip,
++                      dm_right_t      right,
++                      dm_dioinfo_t    __user *diop);
++
++typedef int   (*dm_fsys_get_dirattrs_rvp_t)(
++                      struct inode    *ip,
++                      dm_right_t      right,
++                      u_int           mask,
++                      dm_attrloc_t    __user *locp,
++                      size_t          buflen,
++                      void            __user  *bufp,
++                      size_t          __user *rlenp,
++                      int             *rvalp);
++
++typedef int   (*dm_fsys_get_dmattr_t)(
++                      struct inode    *ip,
++                      dm_right_t      right,
++                      dm_attrname_t   __user *attrnamep,
++                      size_t          buflen,
++                      void            __user *bufp,
++                      size_t          __user *rlenp);
++
++typedef int   (*dm_fsys_get_eventlist_t)(
++                      struct inode    *ip,
++                      dm_right_t      right,
++                      u_int           type,
++                      u_int           nelem,
++                      dm_eventset_t   *eventsetp,     /* in kernel space! */
++                      u_int           *nelemp);       /* in kernel space! */
++
++typedef int   (*dm_fsys_get_fileattr_t)(
++                      struct inode    *ip,
++                      dm_right_t      right,
++                      u_int           mask,
++                      dm_stat_t       __user *statp);
++
++typedef int   (*dm_fsys_get_region_t)(
++                      struct inode    *ip,
++                      dm_right_t      right,
++                      u_int           nelem,
++                      dm_region_t     __user *regbufp,
++                      u_int           __user *nelemp);
++
++typedef int   (*dm_fsys_getall_dmattr_t)(
++                      struct inode    *ip,
++                      dm_right_t      right,
++                      size_t          buflen,
++                      void            __user *bufp,
++                      size_t          __user *rlenp);
++
++typedef int   (*dm_fsys_getall_inherit_t)(
++                      struct inode    *ip,
++                      dm_right_t      right,
++                      u_int           nelem,
++                      dm_inherit_t    __user *inheritbufp,
++                      u_int __user    *nelemp);
++
++typedef int   (*dm_fsys_init_attrloc_t)(
++                      struct inode    *ip,    /* sometimes root inode */
++                      dm_right_t      right,
++                      dm_attrloc_t    __user *locp);
++
++typedef int   (*dm_fsys_mkdir_by_handle_t)(
++                      struct inode    *ip,
++                      dm_right_t      right,
++                      void            __user *hanp,
++                      size_t          hlen,
++                      char            __user *cname);
++
++typedef int   (*dm_fsys_probe_hole_t)(
++                      struct inode    *ip,
++                      dm_right_t      right,
++                      dm_off_t        off,
++                      dm_size_t       len,
++                      dm_off_t        __user  *roffp,
++                      dm_size_t       __user *rlenp);
++
++typedef int   (*dm_fsys_punch_hole_t)(
++                      struct inode    *ip,
++                      dm_right_t      right,
++                      dm_off_t        off,
++                      dm_size_t       len);
++
++typedef int   (*dm_fsys_read_invis_rvp_t)(
++                      struct inode    *ip,
++                      dm_right_t      right,
++                      dm_off_t        off,
++                      dm_size_t       len,
++                      void            __user *bufp,
++                      int             *rvp);
++
++typedef int   (*dm_fsys_release_right_t)(
++                      struct inode    *ip,
++                      dm_right_t      right,
++                      u_int           type);
++
++typedef int   (*dm_fsys_remove_dmattr_t)(
++                      struct inode    *ip,
++                      dm_right_t      right,
++                      int             setdtime,
++                      dm_attrname_t   __user *attrnamep);
++
++typedef int   (*dm_fsys_request_right_t)(
++                      struct inode    *ip,
++                      dm_right_t      right,
++                      u_int           type,   /* DM_FSYS_OBJ or zero */
++                      u_int           flags,
++                      dm_right_t      newright);
++
++typedef int   (*dm_fsys_set_dmattr_t)(
++                      struct inode    *ip,
++                      dm_right_t      right,
++                      dm_attrname_t   __user *attrnamep,
++                      int             setdtime,
++                      size_t          buflen,
++                      void            __user *bufp);
++
++typedef int   (*dm_fsys_set_eventlist_t)(
++                      struct inode    *ip,
++                      dm_right_t      right,
++                      u_int           type,
++                      dm_eventset_t   *eventsetp,     /* in kernel space! */
++                      u_int           maxevent);
++
++typedef int   (*dm_fsys_set_fileattr_t)(
++                      struct inode    *ip,
++                      dm_right_t      right,
++                      u_int           mask,
++                      dm_fileattr_t   __user *attrp);
++
++typedef int   (*dm_fsys_set_inherit_t)(
++                      struct inode    *ip,
++                      dm_right_t      right,
++                      dm_attrname_t   __user *attrnamep,
++                      mode_t          mode);
++
++typedef int   (*dm_fsys_set_region_t)(
++                      struct inode    *ip,
++                      dm_right_t      right,
++                      u_int           nelem,
++                      dm_region_t     __user *regbufp,
++                      dm_boolean_t    __user *exactflagp);
++
++typedef int   (*dm_fsys_symlink_by_handle_t)(
++                      struct inode    *ip,
++                      dm_right_t      right,
++                      void            __user *hanp,
++                      size_t          hlen,
++                      char            __user *cname,
++                      char            __user *path);
++
++typedef int   (*dm_fsys_sync_by_handle_t)(
++                      struct inode    *ip,
++                      dm_right_t      right);
++
++typedef int   (*dm_fsys_upgrade_right_t)(
++                      struct inode    *ip,
++                      dm_right_t      right,
++                      u_int           type);  /* DM_FSYS_OBJ or zero */
++
++typedef int   (*dm_fsys_write_invis_rvp_t)(
++                      struct inode    *ip,
++                      dm_right_t      right,
++                      int             flags,
++                      dm_off_t        off,
++                      dm_size_t       len,
++                      void            __user *bufp,
++                      int             *rvp);
++
++typedef void  (*dm_fsys_obj_ref_hold_t)(
++                      struct inode    *ip);
++
++
++/* Structure definitions used by the VFS_DMAPI_FSYS_VECTOR call. */
++
++typedef struct {
++      dm_fsys_switch_t  func_no;      /* function number */
++      union {
++              dm_fsys_clear_inherit_t clear_inherit;
++              dm_fsys_create_by_handle_t create_by_handle;
++              dm_fsys_downgrade_right_t downgrade_right;
++              dm_fsys_get_allocinfo_rvp_t get_allocinfo_rvp;
++              dm_fsys_get_bulkall_rvp_t get_bulkall_rvp;
++              dm_fsys_get_bulkattr_rvp_t get_bulkattr_rvp;
++              dm_fsys_get_config_t get_config;
++              dm_fsys_get_config_events_t get_config_events;
++              dm_fsys_get_destroy_dmattr_t get_destroy_dmattr;
++              dm_fsys_get_dioinfo_t get_dioinfo;
++              dm_fsys_get_dirattrs_rvp_t get_dirattrs_rvp;
++              dm_fsys_get_dmattr_t get_dmattr;
++              dm_fsys_get_eventlist_t get_eventlist;
++              dm_fsys_get_fileattr_t get_fileattr;
++              dm_fsys_get_region_t get_region;
++              dm_fsys_getall_dmattr_t getall_dmattr;
++              dm_fsys_getall_inherit_t getall_inherit;
++              dm_fsys_init_attrloc_t init_attrloc;
++              dm_fsys_mkdir_by_handle_t mkdir_by_handle;
++              dm_fsys_probe_hole_t probe_hole;
++              dm_fsys_punch_hole_t punch_hole;
++              dm_fsys_read_invis_rvp_t read_invis_rvp;
++              dm_fsys_release_right_t release_right;
++              dm_fsys_remove_dmattr_t remove_dmattr;
++              dm_fsys_request_right_t request_right;
++              dm_fsys_set_dmattr_t set_dmattr;
++              dm_fsys_set_eventlist_t set_eventlist;
++              dm_fsys_set_fileattr_t set_fileattr;
++              dm_fsys_set_inherit_t set_inherit;
++              dm_fsys_set_region_t set_region;
++              dm_fsys_symlink_by_handle_t symlink_by_handle;
++              dm_fsys_sync_by_handle_t sync_by_handle;
++              dm_fsys_upgrade_right_t upgrade_right;
++              dm_fsys_write_invis_rvp_t write_invis_rvp;
++              dm_fsys_obj_ref_hold_t obj_ref_hold;
++      } u_fc;
++} fsys_function_vector_t;
++
++struct dm_fcntl_vector {
++      int     code_level;
++      int     count;          /* Number of functions in the vector */
++      fsys_function_vector_t *vecp;
++};
++typedef struct dm_fcntl_vector dm_fcntl_vector_t;
++
++struct dm_fcntl_mapevent {
++      size_t  length;                 /* length of transfer */
++      dm_eventtype_t  max_event;      /* Maximum (WRITE or READ)  event */
++      int     error;                  /* returned error code */
++};
++typedef struct dm_fcntl_mapevent dm_fcntl_mapevent_t;
++
++#endif        /* __KERNEL__ */
++
++
++/* The following definitions are needed both by the kernel and by the
++   library routines.
++*/
++
++#define DM_MAX_HANDLE_SIZE    56      /* maximum size for a file handle */
++
++
++/*
++ *  Opcodes for dmapi ioctl.
++ */
++
++#define DM_CLEAR_INHERIT      1
++#define DM_CREATE_BY_HANDLE   2
++#define DM_CREATE_SESSION     3
++#define DM_CREATE_USEREVENT   4
++#define DM_DESTROY_SESSION    5
++#define DM_DOWNGRADE_RIGHT    6
++#define DM_FD_TO_HANDLE               7
++#define DM_FIND_EVENTMSG      8
++#define DM_GET_ALLOCINFO      9
++#define DM_GET_BULKALL                10
++#define DM_GET_BULKATTR               11
++#define DM_GET_CONFIG         12
++#define DM_GET_CONFIG_EVENTS  13
++#define DM_GET_DIOINFO                14
++#define DM_GET_DIRATTRS               15
++#define DM_GET_DMATTR         16
++#define DM_GET_EVENTLIST      17
++#define DM_GET_EVENTS         18
++#define DM_GET_FILEATTR               19
++#define DM_GET_MOUNTINFO      20
++#define DM_GET_REGION         21
++#define DM_GETALL_DISP                22
++#define DM_GETALL_DMATTR      23
++#define DM_GETALL_INHERIT     24
++#define DM_GETALL_SESSIONS    25
++#define DM_GETALL_TOKENS      26
++#define DM_INIT_ATTRLOC               27
++#define DM_MKDIR_BY_HANDLE    28
++#define DM_MOVE_EVENT         29
++#define DM_OBJ_REF_HOLD               30
++#define DM_OBJ_REF_QUERY      31
++#define DM_OBJ_REF_RELE               32
++#define DM_PATH_TO_FSHANDLE   33
++#define DM_PATH_TO_HANDLE     34
++#define DM_PENDING            35
++#define DM_PROBE_HOLE         36
++#define DM_PUNCH_HOLE         37
++#define DM_QUERY_RIGHT                38
++#define DM_QUERY_SESSION      39
++#define DM_READ_INVIS         40
++#define DM_RELEASE_RIGHT      41
++#define DM_REMOVE_DMATTR      42
++#define DM_REQUEST_RIGHT      43
++#define DM_RESPOND_EVENT      44
++#define DM_SEND_MSG           45
++#define DM_SET_DISP           46
++#define DM_SET_DMATTR         47
++#define DM_SET_EVENTLIST      48
++#define DM_SET_FILEATTR               49
++#define DM_SET_INHERIT                50
++#define DM_SET_REGION         51
++#define DM_SET_RETURN_ON_DESTROY 52
++#define DM_SYMLINK_BY_HANDLE  53
++#define DM_SYNC_BY_HANDLE     54
++#define DM_UPGRADE_RIGHT      55
++#define DM_WRITE_INVIS                56
++#define DM_OPEN_BY_HANDLE     57
++
++#endif /* __DMAPI_KERN_H__ */
+Index: linux-2.6.26/fs/dmapi/dmapi_mountinfo.c
+===================================================================
+--- /dev/null
++++ linux-2.6.26/fs/dmapi/dmapi_mountinfo.c
+@@ -0,0 +1,527 @@
++/*
++ * Copyright (c) 2000-2005 Silicon Graphics, Inc.  All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of version 2 of the GNU General Public License as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it would be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
++ *
++ * Further, this software is distributed without any warranty that it is
++ * free of the rightful claim of any third person regarding infringement
++ * or the like.        Any license provided herein, whether implied or
++ * otherwise, applies only to this software file.  Patent licenses, if
++ * any, provided herein do not apply to combinations of this program with
++ * other software, or any other product whatsoever.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write the Free Software Foundation, Inc., 59
++ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
++ *
++ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
++ * Mountain View, CA  94043, or:
++ *
++ * http://www.sgi.com
++ *
++ * For further information regarding this notice, see:
++ *
++ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
++ */
++#include "dmapi.h"
++#include "dmapi_kern.h"
++#include "dmapi_private.h"
++
++static LIST_HEAD(dm_fsys_map);
++static spinlock_t dm_fsys_lock = SPIN_LOCK_UNLOCKED;
++
++int
++dm_code_level(void)
++{
++      return DM_CLVL_XOPEN;   /* initial X/Open compliant release */
++}
++
++
++/* Dummy routine which is stored in each function vector slot for which the
++   filesystem provides no function of its own.        If an application calls the
++   function, he will just get ENOSYS.
++*/
++
++static int
++dm_enosys(void)
++{
++      return -ENOSYS;         /* function not supported by filesystem */
++}
++
++
++/* dm_query_fsys_for_vector() asks a filesystem for its list of supported
++   DMAPI functions, and builds a dm_vector_map_t structure based upon the
++   reply.  We ignore functions supported by the filesystem which we do not
++   know about, and we substitute the subroutine 'dm_enosys' for each function
++   we know about but the filesystem does not support.
++*/
++
++static void
++dm_query_fsys_for_vector(
++      dm_vector_map_t         *map)
++{
++      struct super_block      *sb = map->sb;
++      fsys_function_vector_t  *vecp;
++      dm_fcntl_vector_t       vecrq;
++      dm_fsys_vector_t        *vptr;
++      struct filesystem_dmapi_operations *dmapiops = map->dmapiops;
++      int                     error;
++      int                     i;
++
++
++      /* Allocate a function vector and initialize all fields with a
++         dummy function that returns ENOSYS.
++      */
++
++      vptr = map->vptr = kmem_cache_alloc(dm_fsys_vptr_cachep, GFP_KERNEL);
++      if (vptr == NULL) {
++              printk("%s/%d: kmem_cache_alloc(dm_fsys_vptr_cachep) returned NULL\n", __FUNCTION__, __LINE__);
++              return;
++      }
++
++      vptr->code_level = 0;
++      vptr->clear_inherit = (dm_fsys_clear_inherit_t)dm_enosys;
++      vptr->create_by_handle = (dm_fsys_create_by_handle_t)dm_enosys;
++      vptr->downgrade_right = (dm_fsys_downgrade_right_t)dm_enosys;
++      vptr->get_allocinfo_rvp = (dm_fsys_get_allocinfo_rvp_t)dm_enosys;
++      vptr->get_bulkall_rvp = (dm_fsys_get_bulkall_rvp_t)dm_enosys;
++      vptr->get_bulkattr_rvp = (dm_fsys_get_bulkattr_rvp_t)dm_enosys;
++      vptr->get_config = (dm_fsys_get_config_t)dm_enosys;
++      vptr->get_config_events = (dm_fsys_get_config_events_t)dm_enosys;
++      vptr->get_destroy_dmattr = (dm_fsys_get_destroy_dmattr_t)dm_enosys;
++      vptr->get_dioinfo = (dm_fsys_get_dioinfo_t)dm_enosys;
++      vptr->get_dirattrs_rvp = (dm_fsys_get_dirattrs_rvp_t)dm_enosys;
++      vptr->get_dmattr = (dm_fsys_get_dmattr_t)dm_enosys;
++      vptr->get_eventlist = (dm_fsys_get_eventlist_t)dm_enosys;
++      vptr->get_fileattr = (dm_fsys_get_fileattr_t)dm_enosys;
++      vptr->get_region = (dm_fsys_get_region_t)dm_enosys;
++      vptr->getall_dmattr = (dm_fsys_getall_dmattr_t)dm_enosys;
++      vptr->getall_inherit = (dm_fsys_getall_inherit_t)dm_enosys;
++      vptr->init_attrloc = (dm_fsys_init_attrloc_t)dm_enosys;
++      vptr->mkdir_by_handle = (dm_fsys_mkdir_by_handle_t)dm_enosys;
++      vptr->probe_hole = (dm_fsys_probe_hole_t)dm_enosys;
++      vptr->punch_hole = (dm_fsys_punch_hole_t)dm_enosys;
++      vptr->read_invis_rvp = (dm_fsys_read_invis_rvp_t)dm_enosys;
++      vptr->release_right = (dm_fsys_release_right_t)dm_enosys;
++      vptr->request_right = (dm_fsys_request_right_t)dm_enosys;
++      vptr->remove_dmattr = (dm_fsys_remove_dmattr_t)dm_enosys;
++      vptr->set_dmattr = (dm_fsys_set_dmattr_t)dm_enosys;
++      vptr->set_eventlist = (dm_fsys_set_eventlist_t)dm_enosys;
++      vptr->set_fileattr = (dm_fsys_set_fileattr_t)dm_enosys;
++      vptr->set_inherit = (dm_fsys_set_inherit_t)dm_enosys;
++      vptr->set_region = (dm_fsys_set_region_t)dm_enosys;
++      vptr->symlink_by_handle = (dm_fsys_symlink_by_handle_t)dm_enosys;
++      vptr->sync_by_handle = (dm_fsys_sync_by_handle_t)dm_enosys;
++      vptr->upgrade_right = (dm_fsys_upgrade_right_t)dm_enosys;
++      vptr->write_invis_rvp = (dm_fsys_write_invis_rvp_t)dm_enosys;
++      vptr->obj_ref_hold = (dm_fsys_obj_ref_hold_t)dm_enosys;
++
++      /* Issue a call to the filesystem in order to obtain
++         its vector of filesystem-specific DMAPI routines.
++      */
++
++      vecrq.count = 0;
++      vecrq.vecp = NULL;
++
++      error = -ENOSYS;
++      ASSERT(dmapiops);
++      if (dmapiops->get_fsys_vector)
++              error = dmapiops->get_fsys_vector(sb, (caddr_t)&vecrq);
++
++      /* If we still have an error at this point, then the filesystem simply
++         does not support DMAPI, so we give up with all functions set to
++         ENOSYS.
++      */
++
++      if (error || vecrq.count == 0) {
++              kmem_cache_free(dm_fsys_vptr_cachep, vptr);
++              map->vptr = NULL;
++              return;
++      }
++
++      /* The request succeeded and we were given a vector which we need to
++         map to our current level.  Overlay the dummy function with every
++         filesystem function we understand.
++      */
++
++      vptr->code_level = vecrq.code_level;
++      vecp = vecrq.vecp;
++      for (i = 0; i < vecrq.count; i++) {
++              switch (vecp[i].func_no) {
++              case DM_FSYS_CLEAR_INHERIT:
++                      vptr->clear_inherit = vecp[i].u_fc.clear_inherit;
++                      break;
++              case DM_FSYS_CREATE_BY_HANDLE:
++                      vptr->create_by_handle = vecp[i].u_fc.create_by_handle;
++                      break;
++              case DM_FSYS_DOWNGRADE_RIGHT:
++                      vptr->downgrade_right = vecp[i].u_fc.downgrade_right;
++                      break;
++              case DM_FSYS_GET_ALLOCINFO_RVP:
++                      vptr->get_allocinfo_rvp = vecp[i].u_fc.get_allocinfo_rvp;
++                      break;
++              case DM_FSYS_GET_BULKALL_RVP:
++                      vptr->get_bulkall_rvp = vecp[i].u_fc.get_bulkall_rvp;
++                      break;
++              case DM_FSYS_GET_BULKATTR_RVP:
++                      vptr->get_bulkattr_rvp = vecp[i].u_fc.get_bulkattr_rvp;
++                      break;
++              case DM_FSYS_GET_CONFIG:
++                      vptr->get_config = vecp[i].u_fc.get_config;
++                      break;
++              case DM_FSYS_GET_CONFIG_EVENTS:
++                      vptr->get_config_events = vecp[i].u_fc.get_config_events;
++                      break;
++              case DM_FSYS_GET_DESTROY_DMATTR:
++                      vptr->get_destroy_dmattr = vecp[i].u_fc.get_destroy_dmattr;
++                      break;
++              case DM_FSYS_GET_DIOINFO:
++                      vptr->get_dioinfo = vecp[i].u_fc.get_dioinfo;
++                      break;
++              case DM_FSYS_GET_DIRATTRS_RVP:
++                      vptr->get_dirattrs_rvp = vecp[i].u_fc.get_dirattrs_rvp;
++                      break;
++              case DM_FSYS_GET_DMATTR:
++                      vptr->get_dmattr = vecp[i].u_fc.get_dmattr;
++                      break;
++              case DM_FSYS_GET_EVENTLIST:
++                      vptr->get_eventlist = vecp[i].u_fc.get_eventlist;
++                      break;
++              case DM_FSYS_GET_FILEATTR:
++                      vptr->get_fileattr = vecp[i].u_fc.get_fileattr;
++                      break;
++              case DM_FSYS_GET_REGION:
++                      vptr->get_region = vecp[i].u_fc.get_region;
++                      break;
++              case DM_FSYS_GETALL_DMATTR:
++                      vptr->getall_dmattr = vecp[i].u_fc.getall_dmattr;
++                      break;
++              case DM_FSYS_GETALL_INHERIT:
++                      vptr->getall_inherit = vecp[i].u_fc.getall_inherit;
++                      break;
++              case DM_FSYS_INIT_ATTRLOC:
++                      vptr->init_attrloc = vecp[i].u_fc.init_attrloc;
++                      break;
++              case DM_FSYS_MKDIR_BY_HANDLE:
++                      vptr->mkdir_by_handle = vecp[i].u_fc.mkdir_by_handle;
++                      break;
++              case DM_FSYS_PROBE_HOLE:
++                      vptr->probe_hole = vecp[i].u_fc.probe_hole;
++                      break;
++              case DM_FSYS_PUNCH_HOLE:
++                      vptr->punch_hole = vecp[i].u_fc.punch_hole;
++                      break;
++              case DM_FSYS_READ_INVIS_RVP:
++                      vptr->read_invis_rvp = vecp[i].u_fc.read_invis_rvp;
++                      break;
++              case DM_FSYS_RELEASE_RIGHT:
++                      vptr->release_right = vecp[i].u_fc.release_right;
++                      break;
++              case DM_FSYS_REMOVE_DMATTR:
++                      vptr->remove_dmattr = vecp[i].u_fc.remove_dmattr;
++                      break;
++              case DM_FSYS_REQUEST_RIGHT:
++                      vptr->request_right = vecp[i].u_fc.request_right;
++                      break;
++              case DM_FSYS_SET_DMATTR:
++                      vptr->set_dmattr = vecp[i].u_fc.set_dmattr;
++                      break;
++              case DM_FSYS_SET_EVENTLIST:
++                      vptr->set_eventlist = vecp[i].u_fc.set_eventlist;
++                      break;
++              case DM_FSYS_SET_FILEATTR:
++                      vptr->set_fileattr = vecp[i].u_fc.set_fileattr;
++                      break;
++              case DM_FSYS_SET_INHERIT:
++                      vptr->set_inherit = vecp[i].u_fc.set_inherit;
++                      break;
++              case DM_FSYS_SET_REGION:
++                      vptr->set_region = vecp[i].u_fc.set_region;
++                      break;
++              case DM_FSYS_SYMLINK_BY_HANDLE:
++                      vptr->symlink_by_handle = vecp[i].u_fc.symlink_by_handle;
++                      break;
++              case DM_FSYS_SYNC_BY_HANDLE:
++                      vptr->sync_by_handle = vecp[i].u_fc.sync_by_handle;
++                      break;
++              case DM_FSYS_UPGRADE_RIGHT:
++                      vptr->upgrade_right = vecp[i].u_fc.upgrade_right;
++                      break;
++              case DM_FSYS_WRITE_INVIS_RVP:
++                      vptr->write_invis_rvp = vecp[i].u_fc.write_invis_rvp;
++                      break;
++              case DM_FSYS_OBJ_REF_HOLD:
++                      vptr->obj_ref_hold = vecp[i].u_fc.obj_ref_hold;
++                      break;
++              default:                /* ignore ones we don't understand */
++                      break;
++              }
++      }
++}
++
++
++/* Must hold dm_fsys_lock.
++ * This returns the prototype for all instances of the fstype.
++ */
++static dm_vector_map_t *
++dm_fsys_map_by_fstype(
++      struct file_system_type *fstype)
++{
++      struct list_head *p;
++      dm_vector_map_t *proto = NULL;
++      dm_vector_map_t *m;
++
++      ASSERT_ALWAYS(fstype);
++      list_for_each(p, &dm_fsys_map) {
++              m = list_entry(p, dm_vector_map_t, ftype_list);
++              if (m->f_type == fstype) {
++                      proto = m;
++                      break;
++              }
++      }
++      return proto;
++}
++
++
++/* Must hold dm_fsys_lock */
++static dm_vector_map_t *
++dm_fsys_map_by_sb(
++      struct super_block *sb)
++{
++      struct list_head *p;
++      dm_vector_map_t *proto;
++      dm_vector_map_t *m;
++      dm_vector_map_t *foundmap = NULL;
++
++      proto = dm_fsys_map_by_fstype(sb->s_type);
++      if(proto == NULL) {
++              return NULL;
++      }
++
++      list_for_each(p, &proto->sb_list) {
++              m = list_entry(p, dm_vector_map_t, sb_list);
++              if (m->sb == sb) {
++                      foundmap = m;
++                      break;
++              }
++      }
++      return foundmap;
++}
++
++
++#ifdef CONFIG_DMAPI_DEBUG
++static void
++sb_list(
++      struct super_block *sb)
++{
++      struct list_head *p;
++      dm_vector_map_t *proto;
++      dm_vector_map_t *m;
++
++      proto = dm_fsys_map_by_fstype(sb->s_type);
++      ASSERT(proto);
++
++printk("%s/%d: Current sb_list\n", __FUNCTION__, __LINE__);
++      list_for_each(p, &proto->sb_list) {
++              m = list_entry(p, dm_vector_map_t, sb_list);
++printk("%s/%d: map 0x%p, sb 0x%p, vptr 0x%p, dmapiops 0x%p\n", __FUNCTION__, __LINE__, m, m->sb, m->vptr, m->dmapiops);
++      }
++printk("%s/%d: Done sb_list\n", __FUNCTION__, __LINE__);
++}
++#else
++#define sb_list(x)
++#endif
++
++#ifdef CONFIG_DMAPI_DEBUG
++static void
++ftype_list(void)
++{
++      struct list_head *p;
++      dm_vector_map_t *m;
++
++printk("%s/%d: Current ftype_list\n", __FUNCTION__, __LINE__);
++      list_for_each(p, &dm_fsys_map) {
++              m = list_entry(p, dm_vector_map_t, ftype_list);
++              printk("%s/%d: FS 0x%p, ftype 0x%p %s\n", __FUNCTION__, __LINE__, m, m->f_type, m->f_type->name);
++      }
++printk("%s/%d: Done ftype_list\n", __FUNCTION__, __LINE__);
++}
++#else
++#define ftype_list()
++#endif
++
++/* Ask for vptr for this filesystem instance.
++ * The caller knows this inode is on a dmapi-managed filesystem.
++ */
++dm_fsys_vector_t *
++dm_fsys_vector(
++      struct inode    *ip)
++{
++      dm_vector_map_t *map;
++
++      spin_lock(&dm_fsys_lock);
++      ftype_list();
++      map = dm_fsys_map_by_sb(ip->i_sb);
++      spin_unlock(&dm_fsys_lock);
++      ASSERT(map);
++      ASSERT(map->vptr);
++      return map->vptr;
++}
++
++
++/* Ask for the dmapiops for this filesystem instance.  The caller is
++ * also asking if this is a dmapi-managed filesystem.
++ */
++struct filesystem_dmapi_operations *
++dm_fsys_ops(
++      struct super_block      *sb)
++{
++      dm_vector_map_t *proto = NULL;
++      dm_vector_map_t *map;
++
++      spin_lock(&dm_fsys_lock);
++      ftype_list();
++      sb_list(sb);
++      map = dm_fsys_map_by_sb(sb);
++      if (map == NULL)
++              proto = dm_fsys_map_by_fstype(sb->s_type);
++      spin_unlock(&dm_fsys_lock);
++
++      if ((map == NULL) && (proto == NULL))
++              return NULL;
++
++      if (map == NULL) {
++              /* Find out if it's dmapi-managed */
++              dm_vector_map_t *m;
++
++              ASSERT(proto);
++              m = kmem_cache_alloc(dm_fsys_map_cachep, GFP_KERNEL);
++              if (m == NULL) {
++                      printk("%s/%d: kmem_cache_alloc(dm_fsys_map_cachep) returned NULL\n", __FUNCTION__, __LINE__);
++                      return NULL;
++              }
++              memset(m, 0, sizeof(*m));
++              m->dmapiops = proto->dmapiops;
++              m->f_type = sb->s_type;
++              m->sb = sb;
++              INIT_LIST_HEAD(&m->sb_list);
++              INIT_LIST_HEAD(&m->ftype_list);
++
++              dm_query_fsys_for_vector(m);
++              if (m->vptr == NULL) {
++                      /* This isn't dmapi-managed */
++                      kmem_cache_free(dm_fsys_map_cachep, m);
++                      return NULL;
++              }
++
++              spin_lock(&dm_fsys_lock);
++              if ((map = dm_fsys_map_by_sb(sb)) == NULL)
++                      list_add(&m->sb_list, &proto->sb_list);
++              spin_unlock(&dm_fsys_lock);
++
++              if (map) {
++                      kmem_cache_free(dm_fsys_vptr_cachep, m->vptr);
++                      kmem_cache_free(dm_fsys_map_cachep, m);
++              }
++              else {
++                      map = m;
++              }
++      }
++
++      return map->dmapiops;
++}
++
++
++
++/* Called when a filesystem instance is unregistered from dmapi */
++void
++dm_fsys_ops_release(
++      struct super_block      *sb)
++{
++      dm_vector_map_t *map;
++
++      spin_lock(&dm_fsys_lock);
++      ASSERT(!list_empty(&dm_fsys_map));
++      map = dm_fsys_map_by_sb(sb);
++      ASSERT(map);
++      list_del(&map->sb_list);
++      spin_unlock(&dm_fsys_lock);
++
++      ASSERT(map->vptr);
++      kmem_cache_free(dm_fsys_vptr_cachep, map->vptr);
++      kmem_cache_free(dm_fsys_map_cachep, map);
++}
++
++
++/* Called by a filesystem module that is loading into the kernel.
++ * This creates a new dm_vector_map_t which serves as the prototype
++ * for instances of this fstype and also provides the list_head
++ * for instances of this fstype.  The prototypes are the only ones
++ * on the fstype_list, and will never be on the sb_list.
++ */
++void
++dmapi_register(
++      struct file_system_type *fstype,
++      struct filesystem_dmapi_operations *dmapiops)
++{
++      dm_vector_map_t *proto;
++
++      proto = kmem_cache_alloc(dm_fsys_map_cachep, GFP_KERNEL);
++      if (proto == NULL) {
++              printk("%s/%d: kmem_cache_alloc(dm_fsys_map_cachep) returned NULL\n", __FUNCTION__, __LINE__);
++              return;
++      }
++      memset(proto, 0, sizeof(*proto));
++      proto->dmapiops = dmapiops;
++      proto->f_type = fstype;
++      INIT_LIST_HEAD(&proto->sb_list);
++      INIT_LIST_HEAD(&proto->ftype_list);
++
++      spin_lock(&dm_fsys_lock);
++      ASSERT(dm_fsys_map_by_fstype(fstype) == NULL);
++      list_add(&proto->ftype_list, &dm_fsys_map);
++      ftype_list();
++      spin_unlock(&dm_fsys_lock);
++}
++
++/* Called by a filesystem module that is unloading from the kernel */
++void
++dmapi_unregister(
++      struct file_system_type *fstype)
++{
++      struct list_head *p;
++      dm_vector_map_t *proto;
++      dm_vector_map_t *m;
++
++      spin_lock(&dm_fsys_lock);
++      ASSERT(!list_empty(&dm_fsys_map));
++      proto = dm_fsys_map_by_fstype(fstype);
++      ASSERT(proto);
++      list_del(&proto->ftype_list);
++      spin_unlock(&dm_fsys_lock);
++
++      p = &proto->sb_list;
++      while (!list_empty(p)) {
++              m = list_entry(p->next, dm_vector_map_t, sb_list);
++              list_del(&m->sb_list);
++              ASSERT(m->vptr);
++              kmem_cache_free(dm_fsys_vptr_cachep, m->vptr);
++              kmem_cache_free(dm_fsys_map_cachep, m);
++      }
++      kmem_cache_free(dm_fsys_map_cachep, proto);
++}
++
++
++int
++dmapi_registered(
++      struct file_system_type *fstype,
++      struct filesystem_dmapi_operations **dmapiops)
++{
++      return 0;
++}
+Index: linux-2.6.26/fs/dmapi/dmapi_port.h
+===================================================================
+--- /dev/null
++++ linux-2.6.26/fs/dmapi/dmapi_port.h
+@@ -0,0 +1,138 @@
++/*
++ * Copyright (c) 2000-2004 Silicon Graphics, Inc.  All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of version 2 of the GNU General Public License as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it would be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
++ *
++ * Further, this software is distributed without any warranty that it is
++ * free of the rightful claim of any third person regarding infringement
++ * or the like.        Any license provided herein, whether implied or
++ * otherwise, applies only to this software file.  Patent licenses, if
++ * any, provided herein do not apply to combinations of this program with
++ * other software, or any other product whatsoever.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write the Free Software Foundation, Inc., 59
++ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
++ *
++ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
++ * Mountain View, CA  94043, or:
++ *
++ * http://www.sgi.com
++ *
++ * For further information regarding this notice, see:
++ *
++ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
++ */
++#ifndef _DMAPI_PORT_H
++#define _DMAPI_PORT_H
++
++#include <asm/div64.h>
++#include "sv.h"
++
++#include <linux/sched.h>      /* preempt needs this */
++#include <linux/spinlock.h>
++
++typedef spinlock_t lock_t;
++
++#define spinlock_init(lock, name)     spin_lock_init(lock)
++#define       spinlock_destroy(lock)
++
++#define mutex_spinlock(lock)          ({ spin_lock(lock); 0; })
++#define mutex_spinunlock(lock, s)     spin_unlock(lock)
++#define nested_spinlock(lock)         spin_lock(lock)
++#define nested_spinunlock(lock)               spin_unlock(lock)
++
++typedef signed int            __int32_t;
++typedef unsigned int          __uint32_t;
++typedef signed long long int  __int64_t;
++typedef unsigned long long int        __uint64_t;
++
++
++/* __psint_t is the same size as a pointer */
++#if (BITS_PER_LONG == 32)
++typedef __int32_t __psint_t;
++typedef __uint32_t __psunsigned_t;
++#elif (BITS_PER_LONG == 64)
++typedef __int64_t __psint_t;
++typedef __uint64_t __psunsigned_t;
++#else
++#error BITS_PER_LONG must be 32 or 64
++#endif
++
++static inline void
++assfail(char *a, char *f, int l)
++{
++    printk("DMAPI assertion failed: %s, file: %s, line: %d\n", a, f, l);
++    BUG();
++}
++
++#ifdef DEBUG
++#define doass 1
++# ifdef lint
++#  define ASSERT(EX)  ((void)0) /* avoid "constant in conditional" babble */
++# else
++#  define ASSERT(EX) ((!doass||(EX))?((void)0):assfail(#EX, __FILE__, __LINE__))
++# endif       /* lint */
++#else
++# define ASSERT(x)    ((void)0)
++#endif /* DEBUG */
++
++#define ASSERT_ALWAYS(EX)  ((EX)?((void)0):assfail(#EX, __FILE__, __LINE__))
++
++
++#if defined __i386__
++
++/* Side effect free 64 bit mod operation */
++static inline __u32 dmapi_do_mod(void *a, __u32 b, int n)
++{
++      switch (n) {
++              case 4:
++                      return *(__u32 *)a % b;
++              case 8:
++                      {
++                      unsigned long __upper, __low, __high, __mod;
++                      __u64   c = *(__u64 *)a;
++                      __upper = __high = c >> 32;
++                      __low = c;
++                      if (__high) {
++                              __upper = __high % (b);
++                              __high = __high / (b);
++                      }
++                      asm("divl %2":"=a" (__low), "=d" (__mod):"rm" (b), "0" (__low), "1" (__upper));
++                      asm("":"=A" (c):"a" (__low),"d" (__high));
++                      return __mod;
++                      }
++      }
++
++      /* NOTREACHED */
++      return 0;
++}
++#else
++
++/* Side effect free 64 bit mod operation */
++static inline __u32 dmapi_do_mod(void *a, __u32 b, int n)
++{
++      switch (n) {
++              case 4:
++                      return *(__u32 *)a % b;
++              case 8:
++                      {
++                      __u64   c = *(__u64 *)a;
++                      return do_div(c, b);
++                      }
++      }
++
++      /* NOTREACHED */
++      return 0;
++}
++#endif
++
++#define do_mod(a, b)  dmapi_do_mod(&(a), (b), sizeof(a))
++
++#endif /* _DMAPI_PORT_H */
+Index: linux-2.6.26/fs/dmapi/dmapi_private.h
+===================================================================
+--- /dev/null
++++ linux-2.6.26/fs/dmapi/dmapi_private.h
+@@ -0,0 +1,619 @@
++/*
++ * Copyright (c) 2000-2005 Silicon Graphics, Inc.  All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of version 2 of the GNU General Public License as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it would be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
++ *
++ * Further, this software is distributed without any warranty that it is
++ * free of the rightful claim of any third person regarding infringement
++ * or the like.        Any license provided herein, whether implied or
++ * otherwise, applies only to this software file.  Patent licenses, if
++ * any, provided herein do not apply to combinations of this program with
++ * other software, or any other product whatsoever.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write the Free Software Foundation, Inc., 59
++ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
++ *
++ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
++ * Mountain View, CA  94043, or:
++ *
++ * http://www.sgi.com
++ *
++ * For further information regarding this notice, see:
++ *
++ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
++ */
++#ifndef _DMAPI_PRIVATE_H
++#define _DMAPI_PRIVATE_H
++
++#include <linux/slab.h>
++#include "dmapi_port.h"
++#include "sv.h"
++
++#ifdef CONFIG_PROC_FS
++#define DMAPI_PROCFS          "orig/fs/dmapi_v2" /* DMAPI device in /proc. */
++#define DMAPI_DBG_PROCFS      "orig/fs/dmapi_d" /* DMAPI debugging dir */
++#endif
++
++extern struct kmem_cache      *dm_fsreg_cachep;
++extern struct kmem_cache      *dm_tokdata_cachep;
++extern struct kmem_cache      *dm_session_cachep;
++extern struct kmem_cache      *dm_fsys_map_cachep;
++extern struct kmem_cache      *dm_fsys_vptr_cachep;
++
++typedef struct dm_tokdata {
++      struct dm_tokdata *td_next;
++      struct dm_tokevent *td_tevp;    /* pointer to owning tevp */
++      int             td_app_ref;     /* # app threads currently active */
++      dm_right_t      td_orig_right;  /* original right held when created */
++      dm_right_t      td_right;       /* current right held for this handle */
++      short           td_flags;
++      short           td_type;        /* object type */
++      int             td_vcount;      /* # of current application VN_HOLDs */
++      struct inode    *td_ip;         /* inode pointer */
++      dm_handle_t     td_handle;      /* handle for ip or sb */
++} dm_tokdata_t;
++
++/* values for td_type */
++
++#define DM_TDT_NONE   0x00            /* td_handle is empty */
++#define DM_TDT_VFS    0x01            /* td_handle points to a sb */
++#define DM_TDT_REG    0x02            /* td_handle points to a file */
++#define DM_TDT_DIR    0x04            /* td_handle points to a directory */
++#define DM_TDT_LNK    0x08            /* td_handle points to a symlink */
++#define DM_TDT_OTH    0x10            /* some other object eg. pipe, socket */
++
++#define DM_TDT_VNO    (DM_TDT_REG|DM_TDT_DIR|DM_TDT_LNK|DM_TDT_OTH)
++#define DM_TDT_ANY    (DM_TDT_VFS|DM_TDT_REG|DM_TDT_DIR|DM_TDT_LNK|DM_TDT_OTH)
++
++/* values for td_flags */
++
++#define DM_TDF_ORIG   0x0001          /* part of the original event */
++#define DM_TDF_EVTREF 0x0002          /* event thread holds inode reference */
++#define DM_TDF_STHREAD        0x0004          /* only one app can use this handle */
++#define DM_TDF_RIGHT  0x0008          /* vcount bumped for dm_request_right */
++#define DM_TDF_HOLD   0x0010          /* vcount bumped for dm_obj_ref_hold */
++
++
++/* Because some events contain __u64 fields, we force te_msg and te_event
++   to always be 8-byte aligned.        In order to send more than one message in
++   a single dm_get_events() call, we also ensure that each message is an
++   8-byte multiple.
++*/
++
++typedef struct dm_tokevent {
++      struct dm_tokevent  *te_next;
++      struct dm_tokevent  *te_hashnext; /* hash chain */
++      lock_t          te_lock;        /* lock for all fields but te_*next.
++                                       * te_next and te_hashnext are
++                                       * protected by the session lock.
++                                       */
++      short           te_flags;
++      short           te_allocsize;   /* alloc'ed size of this structure */
++      sv_t            te_evt_queue;   /* queue waiting for dm_respond_event */
++      sv_t            te_app_queue;   /* queue waiting for handle access */
++      int             te_evt_ref;     /* number of event procs using token */
++      int             te_app_ref;     /* number of app procs using token */
++      int             te_app_slp;     /* number of app procs sleeping */
++      int             te_reply;       /* return errno for sync messages */
++      dm_tokdata_t    *te_tdp;        /* list of handle/right pairs */
++      union {
++              __u64           align;  /* force alignment of te_msg */
++              dm_eventmsg_t   te_msg;         /* user visible part */
++      } te_u;
++      __u64           te_event;       /* start of dm_xxx_event_t message */
++} dm_tokevent_t;
++
++#define te_msg        te_u.te_msg
++
++/* values for te_flags */
++
++#define DM_TEF_LOCKED 0x0001          /* event "locked" by dm_get_events() */
++#define DM_TEF_INTERMED 0x0002                /* a dm_pending reply was received */
++#define DM_TEF_FINAL  0x0004          /* dm_respond_event has been received */
++#define DM_TEF_HASHED 0x0010          /* event is on hash chain  */
++#define DM_TEF_FLUSH  0x0020          /* flushing threads from queues */
++
++
++#ifdef CONFIG_DMAPI_DEBUG
++#define DM_SHASH_DEBUG
++#endif
++
++typedef struct dm_sesshash {
++      dm_tokevent_t   *h_next;        /* ptr to chain of tokevents */
++#ifdef DM_SHASH_DEBUG
++      int             maxlength;
++      int             curlength;
++      int             num_adds;
++      int             num_dels;
++      int             dup_hits;
++#endif
++} dm_sesshash_t;
++
++
++typedef struct dm_eventq {
++      dm_tokevent_t   *eq_head;
++      dm_tokevent_t   *eq_tail;
++      int             eq_count;       /* size of queue */
++} dm_eventq_t;
++
++
++typedef struct dm_session {
++      struct dm_session       *sn_next;       /* sessions linkage */
++      dm_sessid_t     sn_sessid;      /* user-visible session number */
++      u_int           sn_flags;
++      lock_t          sn_qlock;       /* lock for newq/delq related fields */
++      sv_t            sn_readerq;     /* waiting for message on sn_newq */
++      sv_t            sn_writerq;     /* waiting for room on sn_newq */
++      u_int           sn_readercnt;   /* count of waiting readers */
++      u_int           sn_writercnt;   /* count of waiting readers */
++      dm_eventq_t     sn_newq;        /* undelivered event queue */
++      dm_eventq_t     sn_delq;        /* delivered event queue */
++      dm_eventq_t     sn_evt_writerq; /* events of thrds in sn_writerq */
++      dm_sesshash_t   *sn_sesshash;   /* buckets for tokevent hash chains */
++#ifdef DM_SHASH_DEBUG
++      int             sn_buckets_in_use;
++      int             sn_max_buckets_in_use;
++#endif
++      char            sn_info[DM_SESSION_INFO_LEN];   /* user-supplied info */
++} dm_session_t;
++
++/* values for sn_flags */
++
++#define DM_SN_WANTMOUNT 0x0001                /* session wants to get mount events */
++
++
++typedef enum {
++      DM_STATE_MOUNTING,
++      DM_STATE_MOUNTED,
++      DM_STATE_UNMOUNTING,
++      DM_STATE_UNMOUNTED
++} dm_fsstate_t;
++
++
++typedef struct dm_fsreg {
++      struct dm_fsreg *fr_next;
++      struct super_block *fr_sb;      /* filesystem pointer */
++      dm_tokevent_t   *fr_tevp;
++      dm_fsid_t       fr_fsid;        /* filesystem ID */
++      void            *fr_msg;        /* dm_mount_event_t for filesystem */
++      int             fr_msgsize;     /* size of dm_mount_event_t */
++      dm_fsstate_t    fr_state;
++      sv_t            fr_dispq;
++      int             fr_dispcnt;
++      dm_eventq_t     fr_evt_dispq;   /* events of thrds in fr_dispq */
++      sv_t            fr_queue;       /* queue for hdlcnt/sbcnt/unmount */
++      lock_t          fr_lock;
++      int             fr_hdlcnt;      /* threads blocked during unmount */
++      int             fr_vfscnt;      /* threads in VFS_VGET or VFS_ROOT */
++      int             fr_unmount;     /* if non-zero, umount is sleeping */
++      dm_attrname_t   fr_rattr;       /* dm_set_return_on_destroy attribute */
++      dm_session_t    *fr_sessp [DM_EVENT_MAX];
++} dm_fsreg_t;
++
++
++
++
++/* events valid in dm_set_disp() when called with a filesystem handle. */
++
++#define DM_VALID_DISP_EVENTS          ( \
++      (1 << DM_EVENT_PREUNMOUNT)      | \
++      (1 << DM_EVENT_UNMOUNT)         | \
++      (1 << DM_EVENT_NOSPACE)         | \
++      (1 << DM_EVENT_DEBUT)           | \
++      (1 << DM_EVENT_CREATE)          | \
++      (1 << DM_EVENT_POSTCREATE)      | \
++      (1 << DM_EVENT_REMOVE)          | \
++      (1 << DM_EVENT_POSTREMOVE)      | \
++      (1 << DM_EVENT_RENAME)          | \
++      (1 << DM_EVENT_POSTRENAME)      | \
++      (1 << DM_EVENT_LINK)            | \
++      (1 << DM_EVENT_POSTLINK)        | \
++      (1 << DM_EVENT_SYMLINK)         | \
++      (1 << DM_EVENT_POSTSYMLINK)     | \
++      (1 << DM_EVENT_READ)            | \
++      (1 << DM_EVENT_WRITE)           | \
++      (1 << DM_EVENT_TRUNCATE)        | \
++      (1 << DM_EVENT_ATTRIBUTE)       | \
++      (1 << DM_EVENT_DESTROY)         )
++
++
++/* isolate the read/write/trunc events of a dm_tokevent_t */
++
++#define DM_EVENT_RDWRTRUNC(tevp)                      (  \
++      ((tevp)->te_msg.ev_type == DM_EVENT_READ)       || \
++      ((tevp)->te_msg.ev_type == DM_EVENT_WRITE)      || \
++      ((tevp)->te_msg.ev_type == DM_EVENT_TRUNCATE)   )
++
++
++/*
++ *  Global handle hack isolation.
++ */
++
++#define DM_GLOBALHAN(hanp, hlen)      (((hanp) == DM_GLOBAL_HANP) && \
++                                       ((hlen) == DM_GLOBAL_HLEN))
++
++
++#define DM_MAX_MSG_DATA               3960
++
++
++
++/* Supported filesystem function vector functions. */
++
++
++typedef struct {
++      int                             code_level;
++      dm_fsys_clear_inherit_t         clear_inherit;
++      dm_fsys_create_by_handle_t      create_by_handle;
++      dm_fsys_downgrade_right_t       downgrade_right;
++      dm_fsys_get_allocinfo_rvp_t     get_allocinfo_rvp;
++      dm_fsys_get_bulkall_rvp_t       get_bulkall_rvp;
++      dm_fsys_get_bulkattr_rvp_t      get_bulkattr_rvp;
++      dm_fsys_get_config_t            get_config;
++      dm_fsys_get_config_events_t     get_config_events;
++      dm_fsys_get_destroy_dmattr_t    get_destroy_dmattr;
++      dm_fsys_get_dioinfo_t           get_dioinfo;
++      dm_fsys_get_dirattrs_rvp_t      get_dirattrs_rvp;
++      dm_fsys_get_dmattr_t            get_dmattr;
++      dm_fsys_get_eventlist_t         get_eventlist;
++      dm_fsys_get_fileattr_t          get_fileattr;
++      dm_fsys_get_region_t            get_region;
++      dm_fsys_getall_dmattr_t         getall_dmattr;
++      dm_fsys_getall_inherit_t        getall_inherit;
++      dm_fsys_init_attrloc_t          init_attrloc;
++      dm_fsys_mkdir_by_handle_t       mkdir_by_handle;
++      dm_fsys_probe_hole_t            probe_hole;
++      dm_fsys_punch_hole_t            punch_hole;
++      dm_fsys_read_invis_rvp_t        read_invis_rvp;
++      dm_fsys_release_right_t         release_right;
++      dm_fsys_remove_dmattr_t         remove_dmattr;
++      dm_fsys_request_right_t         request_right;
++      dm_fsys_set_dmattr_t            set_dmattr;
++      dm_fsys_set_eventlist_t         set_eventlist;
++      dm_fsys_set_fileattr_t          set_fileattr;
++      dm_fsys_set_inherit_t           set_inherit;
++      dm_fsys_set_region_t            set_region;
++      dm_fsys_symlink_by_handle_t     symlink_by_handle;
++      dm_fsys_sync_by_handle_t        sync_by_handle;
++      dm_fsys_upgrade_right_t         upgrade_right;
++      dm_fsys_write_invis_rvp_t       write_invis_rvp;
++      dm_fsys_obj_ref_hold_t          obj_ref_hold;
++} dm_fsys_vector_t;
++
++
++typedef struct        {
++      struct list_head        ftype_list;     /* list of fstypes */
++      struct list_head        sb_list;        /* list of sb's per fstype */
++      struct file_system_type *f_type;
++      struct filesystem_dmapi_operations *dmapiops;
++      dm_fsys_vector_t        *vptr;
++      struct super_block      *sb;
++} dm_vector_map_t;
++
++
++extern        dm_session_t    *dm_sessions;           /* head of session list */
++extern        dm_fsreg_t      *dm_registers;
++extern        lock_t          dm_reg_lock;            /* lock for registration list */
++
++/*
++ *  Kernel only prototypes.
++ */
++
++int           dm_find_session_and_lock(
++                      dm_sessid_t     sid,
++                      dm_session_t    **sessionpp,
++                      unsigned long   *lcp);
++
++int           dm_find_msg_and_lock(
++                      dm_sessid_t     sid,
++                      dm_token_t      token,
++                      dm_tokevent_t   **tevpp,
++                      unsigned long   *lcp);
++
++dm_tokevent_t * dm_evt_create_tevp(
++                      dm_eventtype_t  event,
++                      int             variable_size,
++                      void            **msgpp);
++
++int           dm_app_get_tdp(
++                      dm_sessid_t     sid,
++                      void            __user *hanp,
++                      size_t          hlen,
++                      dm_token_t      token,
++                      short           types,
++                      dm_right_t      right,
++                      dm_tokdata_t    **tdpp);
++
++int           dm_get_config_tdp(
++                      void            __user *hanp,
++                      size_t          hlen,
++                      dm_tokdata_t    **tdpp);
++
++void          dm_app_put_tdp(
++                      dm_tokdata_t    *tdp);
++
++void          dm_put_tevp(
++                      dm_tokevent_t   *tevp,
++                      dm_tokdata_t    *tdp);
++
++void          dm_evt_rele_tevp(
++                      dm_tokevent_t   *tevp,
++                      int             droprights);
++
++int           dm_enqueue_normal_event(
++                      struct super_block *sbp,
++                      dm_tokevent_t   **tevpp,
++                      int             flags);
++
++int           dm_enqueue_mount_event(
++                      struct super_block *sbp,
++                      dm_tokevent_t   *tevp);
++
++int           dm_enqueue_sendmsg_event(
++                      dm_sessid_t     targetsid,
++                      dm_tokevent_t   *tevp,
++                      int             synch);
++
++int           dm_enqueue_user_event(
++                      dm_sessid_t     sid,
++                      dm_tokevent_t   *tevp,
++                      dm_token_t      *tokenp);
++
++int           dm_obj_ref_query_rvp(
++                      dm_sessid_t     sid,
++                      dm_token_t      token,
++                      void            __user *hanp,
++                      size_t          hlen,
++                      int             *rvp);
++
++int           dm_read_invis_rvp(
++                      dm_sessid_t     sid,
++                      void            __user *hanp,
++                      size_t          hlen,
++                      dm_token_t      token,
++                      dm_off_t        off,
++                      dm_size_t       len,
++                      void            __user *bufp,
++                      int             *rvp);
++
++int           dm_write_invis_rvp(
++                      dm_sessid_t     sid,
++                      void            __user *hanp,
++                      size_t          hlen,
++                      dm_token_t      token,
++                      int             flags,
++                      dm_off_t        off,
++                      dm_size_t       len,
++                      void            __user *bufp,
++                      int             *rvp);
++
++int           dm_get_bulkattr_rvp(
++                      dm_sessid_t     sid,
++                      void            __user *hanp,
++                      size_t          hlen,
++                      dm_token_t      token,
++                      u_int           mask,
++                      dm_attrloc_t    __user *locp,
++                      size_t          buflen,
++                      void            __user *bufp,
++                      size_t          __user *rlenp,
++                      int             *rvp);
++
++int           dm_get_bulkall_rvp(
++                      dm_sessid_t     sid,
++                      void            __user *hanp,
++                      size_t          hlen,
++                      dm_token_t      token,
++                      u_int           mask,
++                      dm_attrname_t   __user *attrnamep,
++                      dm_attrloc_t    __user *locp,
++                      size_t          buflen,
++                      void            __user *bufp,
++                      size_t          __user *rlenp,
++                      int             *rvp);
++
++int           dm_get_dirattrs_rvp(
++                      dm_sessid_t     sid,
++                      void            __user *hanp,
++                      size_t          hlen,
++                      dm_token_t      token,
++                      u_int           mask,
++                      dm_attrloc_t    __user *locp,
++                      size_t          buflen,
++                      void            __user *bufp,
++                      size_t          __user *rlenp,
++                      int             *rvp);
++
++int           dm_get_allocinfo_rvp(
++                      dm_sessid_t     sid,
++                      void            __user *hanp,
++                      size_t          hlen,
++                      dm_token_t      token,
++                      dm_off_t        __user  *offp,
++                      u_int           nelem,
++                      dm_extent_t     __user *extentp,
++                      u_int           __user *nelemp,
++                      int             *rvp);
++
++int           dm_waitfor_destroy_attrname(
++                      struct super_block      *sb,
++                      dm_attrname_t   *attrnamep);
++
++void          dm_clear_fsreg(
++                      dm_session_t    *s);
++
++int           dm_add_fsys_entry(
++                      struct super_block      *sb,
++                      dm_tokevent_t   *tevp);
++
++void          dm_change_fsys_entry(
++                      struct super_block      *sb,
++                      dm_fsstate_t    newstate);
++
++void          dm_remove_fsys_entry(
++                      struct super_block      *sb);
++
++dm_fsys_vector_t *dm_fsys_vector(
++                      struct inode    *ip);
++
++struct filesystem_dmapi_operations *dm_fsys_ops(
++                      struct super_block      *sb);
++
++void dm_fsys_ops_release(
++                       struct super_block     *sb);
++
++int           dm_waitfor_disp_session(
++                      struct super_block      *sb,
++                      dm_tokevent_t   *tevp,
++                      dm_session_t    **sessionpp,
++                      unsigned long   *lcp);
++
++struct inode *        dm_handle_to_ip (
++                      dm_handle_t     *handlep,
++                      short           *typep);
++
++int           dm_check_dmapi_ip(
++                      struct inode    *ip);
++
++dm_tokevent_t * dm_find_mount_tevp_and_lock(
++                      dm_fsid_t       *fsidp,
++                      unsigned long   *lcp);
++
++int           dm_path_to_hdl(
++                      char            __user *path,
++                      void            __user *hanp,
++                      size_t          __user *hlenp);
++
++int           dm_path_to_fshdl(
++                      char            __user *path,
++                      void            __user *hanp,
++                      size_t          __user *hlenp);
++
++int           dm_fd_to_hdl(
++                      int             fd,
++                      void            __user *hanp,
++                      size_t          __user *hlenp);
++
++int           dm_upgrade_right(
++                      dm_sessid_t     sid,
++                      void            __user *hanp,
++                      size_t          hlen,
++                      dm_token_t      token);
++
++int           dm_downgrade_right(
++                      dm_sessid_t     sid,
++                      void            __user *hanp,
++                      size_t          hlen,
++                      dm_token_t      token);
++
++int           dm_request_right(
++                      dm_sessid_t     sid,
++                      void            __user *hanp,
++                      size_t          hlen,
++                      dm_token_t      token,
++                      u_int           flags,
++                      dm_right_t      right);
++
++int           dm_release_right(
++                      dm_sessid_t     sid,
++                      void            __user *hanp,
++                      size_t          hlen,
++                      dm_token_t      token);
++
++int           dm_query_right(
++                      dm_sessid_t     sid,
++                      void            __user *hanp,
++                      size_t          hlen,
++                      dm_token_t      token,
++                      dm_right_t      __user *rightp);
++
++
++int           dm_set_eventlist(
++                      dm_sessid_t     sid,
++                      void            __user *hanp,
++                      size_t          hlen,
++                      dm_token_t      token,
++                      dm_eventset_t   __user *eventsetp,
++                      u_int           maxevent);
++
++int           dm_obj_ref_hold(
++                      dm_sessid_t     sid,
++                      dm_token_t      token,
++                      void            __user *hanp,
++                      size_t          hlen);
++
++int           dm_obj_ref_rele(
++                      dm_sessid_t     sid,
++                      dm_token_t      token,
++                      void            __user *hanp,
++                      size_t          hlen);
++
++int           dm_get_eventlist(
++                      dm_sessid_t     sid,
++                      void            __user *hanp,
++                      size_t          hlen,
++                      dm_token_t      token,
++                      u_int           nelem,
++                      dm_eventset_t   __user *eventsetp,
++                      u_int           __user *nelemp);
++
++
++int           dm_set_disp(
++                      dm_sessid_t     sid,
++                      void            __user *hanp,
++                      size_t          hlen,
++                      dm_token_t      token,
++                      dm_eventset_t   __user *eventsetp,
++                      u_int           maxevent);
++
++
++int           dm_set_return_on_destroy(
++                      dm_sessid_t     sid,
++                      void            __user *hanp,
++                      size_t          hlen,
++                      dm_token_t      token,
++                      dm_attrname_t   __user *attrnamep,
++                      dm_boolean_t    enable);
++
++
++int           dm_get_mountinfo(
++                      dm_sessid_t     sid,
++                      void            __user *hanp,
++                      size_t          hlen,
++                      dm_token_t      token,
++                      size_t          buflen,
++                      void            __user *bufp,
++                      size_t          __user *rlenp);
++
++void          dm_link_event(
++                      dm_tokevent_t   *tevp,
++                      dm_eventq_t     *queue);
++
++void          dm_unlink_event(
++                      dm_tokevent_t   *tevp,
++                      dm_eventq_t     *queue);
++
++int           dm_open_by_handle_rvp(
++                      unsigned int    fd,
++                      void            __user *hanp,
++                      size_t          hlen,
++                      int             mode,
++                      int             *rvp);
++
++int           dm_copyin_handle(
++                      void            __user *hanp,
++                      size_t          hlen,
++                      dm_handle_t     *handlep);
++
++int           dm_release_disp_threads(
++                      dm_fsid_t       *fsid,
++                      struct inode    *inode,
++                      int             errno);
++
++#endif        /* _DMAPI_PRIVATE_H */
+Index: linux-2.6.26/fs/dmapi/dmapi_region.c
+===================================================================
+--- /dev/null
++++ linux-2.6.26/fs/dmapi/dmapi_region.c
+@@ -0,0 +1,91 @@
++/*
++ * Copyright (c) 2000 Silicon Graphics, Inc.  All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of version 2 of the GNU General Public License as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it would be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
++ *
++ * Further, this software is distributed without any warranty that it is
++ * free of the rightful claim of any third person regarding infringement
++ * or the like.        Any license provided herein, whether implied or
++ * otherwise, applies only to this software file.  Patent licenses, if
++ * any, provided herein do not apply to combinations of this program with
++ * other software, or any other product whatsoever.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write the Free Software Foundation, Inc., 59
++ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
++ *
++ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
++ * Mountain View, CA  94043, or:
++ *
++ * http://www.sgi.com
++ *
++ * For further information regarding this notice, see:
++ *
++ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
++ */
++#include "dmapi.h"
++#include "dmapi_kern.h"
++#include "dmapi_private.h"
++
++
++int
++dm_get_region(
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token,
++      u_int           nelem,
++      dm_region_t     __user *regbufp,
++      u_int           __user *nelemp)
++{
++      dm_fsys_vector_t *fsys_vector;
++      dm_tokdata_t    *tdp;
++      int             error;
++
++      error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_REG,
++              DM_RIGHT_SHARED, &tdp);
++      if (error != 0)
++              return(error);
++
++      fsys_vector = dm_fsys_vector(tdp->td_ip);
++      error = fsys_vector->get_region(tdp->td_ip, tdp->td_right,
++              nelem, regbufp, nelemp);
++
++      dm_app_put_tdp(tdp);
++      return(error);
++}
++
++
++
++int
++dm_set_region(
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token,
++      u_int           nelem,
++      dm_region_t     __user *regbufp,
++      dm_boolean_t    __user *exactflagp)
++{
++      dm_fsys_vector_t *fsys_vector;
++      dm_tokdata_t    *tdp;
++      int             error;
++
++      error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_REG,
++              DM_RIGHT_EXCL, &tdp);
++      if (error != 0)
++              return(error);
++
++      fsys_vector = dm_fsys_vector(tdp->td_ip);
++      error = fsys_vector->set_region(tdp->td_ip, tdp->td_right,
++              nelem, regbufp, exactflagp);
++
++      dm_app_put_tdp(tdp);
++      return(error);
++}
+Index: linux-2.6.26/fs/dmapi/dmapi_register.c
+===================================================================
+--- /dev/null
++++ linux-2.6.26/fs/dmapi/dmapi_register.c
+@@ -0,0 +1,1644 @@
++/*
++ * Copyright (c) 2000-2005 Silicon Graphics, Inc.  All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of version 2 of the GNU General Public License as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it would be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
++ *
++ * Further, this software is distributed without any warranty that it is
++ * free of the rightful claim of any third person regarding infringement
++ * or the like.        Any license provided herein, whether implied or
++ * otherwise, applies only to this software file.  Patent licenses, if
++ * any, provided herein do not apply to combinations of this program with
++ * other software, or any other product whatsoever.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write the Free Software Foundation, Inc., 59
++ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
++ *
++ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
++ * Mountain View, CA  94043, or:
++ *
++ * http://www.sgi.com
++ *
++ * For further information regarding this notice, see:
++ *
++ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
++ */
++
++#include <linux/version.h>
++#include <linux/mm.h>
++#include <linux/proc_fs.h>
++#include <linux/module.h>
++#include <linux/mount.h>
++#include <linux/namei.h>
++#include <asm/uaccess.h>
++#include <linux/fs.h>
++#include <linux/file.h>
++#include "dmapi.h"
++#include "dmapi_kern.h"
++#include "dmapi_private.h"
++
++/* LOOKUP_POSTIVE was removed in Linux 2.6 */
++#ifndef LOOKUP_POSITIVE
++#define LOOKUP_POSITIVE       0
++#endif
++
++dm_fsreg_t    *dm_registers;  /* head of filesystem registration list */
++int           dm_fsys_cnt;    /* number of filesystems on dm_registers list */
++lock_t                dm_reg_lock = SPIN_LOCK_UNLOCKED;/* lock for dm_registers */
++
++
++
++#ifdef CONFIG_PROC_FS
++static int
++fsreg_read_pfs(char *buffer, char **start, off_t offset,
++               int count, int *eof, void *data)
++{
++      int len;
++      int i;
++      dm_fsreg_t      *fsrp = (dm_fsreg_t*)data;
++      char            statebuf[30];
++
++#define CHKFULL if(len >= count) break;
++#define ADDBUF(a,b)   len += sprintf(buffer + len, a, b); CHKFULL;
++
++      switch (fsrp->fr_state) {
++      case DM_STATE_MOUNTING:         sprintf(statebuf, "mounting"); break;
++      case DM_STATE_MOUNTED:          sprintf(statebuf, "mounted"); break;
++      case DM_STATE_UNMOUNTING:       sprintf(statebuf, "unmounting"); break;
++      case DM_STATE_UNMOUNTED:        sprintf(statebuf, "unmounted"); break;
++      default:
++              sprintf(statebuf, "unknown:%d", (int)fsrp->fr_state);
++              break;
++      }
++
++      len=0;
++      while(1){
++              ADDBUF("fsrp=0x%p\n", fsrp);
++              ADDBUF("fr_next=0x%p\n", fsrp->fr_next);
++              ADDBUF("fr_sb=0x%p\n", fsrp->fr_sb);
++              ADDBUF("fr_tevp=0x%p\n", fsrp->fr_tevp);
++              ADDBUF("fr_fsid=%c\n", '?');
++              ADDBUF("fr_msg=0x%p\n", fsrp->fr_msg);
++              ADDBUF("fr_msgsize=%d\n", fsrp->fr_msgsize);
++              ADDBUF("fr_state=%s\n", statebuf);
++              ADDBUF("fr_dispq=%c\n", '?');
++              ADDBUF("fr_dispcnt=%d\n", fsrp->fr_dispcnt);
++
++              ADDBUF("fr_evt_dispq.eq_head=0x%p\n", fsrp->fr_evt_dispq.eq_head);
++              ADDBUF("fr_evt_dispq.eq_tail=0x%p\n", fsrp->fr_evt_dispq.eq_tail);
++              ADDBUF("fr_evt_dispq.eq_count=%d\n", fsrp->fr_evt_dispq.eq_count);
++
++              ADDBUF("fr_queue=%c\n", '?');
++              ADDBUF("fr_lock=%c\n", '?');
++              ADDBUF("fr_hdlcnt=%d\n", fsrp->fr_hdlcnt);
++              ADDBUF("fr_vfscnt=%d\n", fsrp->fr_vfscnt);
++              ADDBUF("fr_unmount=%d\n", fsrp->fr_unmount);
++
++              len += sprintf(buffer + len, "fr_rattr=");
++              CHKFULL;
++              for(i = 0; i <= DM_ATTR_NAME_SIZE; ++i){
++                      ADDBUF("%c", fsrp->fr_rattr.an_chars[i]);
++              }
++              CHKFULL;
++              len += sprintf(buffer + len, "\n");
++              CHKFULL;
++
++              for(i = 0; i < DM_EVENT_MAX; i++){
++                      if( fsrp->fr_sessp[i] != NULL ){
++                              ADDBUF("fr_sessp[%d]=", i);
++                              ADDBUF("0x%p\n", fsrp->fr_sessp[i]);
++                      }
++              }
++              CHKFULL;
++
++              break;
++      }
++
++      if (offset >= len) {
++              *start = buffer;
++              *eof = 1;
++              return 0;
++      }
++      *start = buffer + offset;
++      if ((len -= offset) > count)
++              return count;
++      *eof = 1;
++
++      return len;
++}
++#endif
++
++
++/* Returns a pointer to the filesystem structure for the filesystem
++   referenced by fsidp. The caller is responsible for obtaining dm_reg_lock
++   before calling this routine.
++*/
++
++static dm_fsreg_t *
++dm_find_fsreg(
++      dm_fsid_t       *fsidp)
++{
++      dm_fsreg_t      *fsrp;
++
++      for (fsrp = dm_registers; fsrp; fsrp = fsrp->fr_next) {
++              if (!memcmp(&fsrp->fr_fsid, fsidp, sizeof(*fsidp)))
++                      break;
++      }
++      return(fsrp);
++}
++
++
++/* Given a fsid_t, dm_find_fsreg_and_lock() finds the dm_fsreg_t structure
++   for that filesytem if one exists, and returns a pointer to the structure
++   after obtaining its 'fr_lock' so that the caller can safely modify the
++   dm_fsreg_t.        The caller is responsible for releasing 'fr_lock'.
++*/
++
++static dm_fsreg_t *
++dm_find_fsreg_and_lock(
++      dm_fsid_t       *fsidp,
++      unsigned long   *lcp)           /* address of returned lock cookie */
++{
++      dm_fsreg_t      *fsrp;
++
++      for (;;) {
++              *lcp = mutex_spinlock(&dm_reg_lock);
++
++              if ((fsrp = dm_find_fsreg(fsidp)) == NULL) {
++                      mutex_spinunlock(&dm_reg_lock, *lcp);
++                      return(NULL);
++              }
++              if (spin_trylock(&fsrp->fr_lock)) {
++                      nested_spinunlock(&dm_reg_lock);
++                      return(fsrp);   /* success */
++              }
++
++              /* If the second lock is not available, drop the first and
++                 start over.  This gives the CPU a chance to process any
++                 interrupts, and also allows processes which want a fr_lock
++                 for a different filesystem to proceed.
++              */
++
++              mutex_spinunlock(&dm_reg_lock, *lcp);
++      }
++}
++
++
++/* dm_add_fsys_entry() is called when a DM_EVENT_MOUNT event is about to be
++   sent.  It creates a dm_fsreg_t structure for the filesystem and stores a
++   pointer to a copy of the mount event within that structure so that it is
++   available for subsequent dm_get_mountinfo() calls.
++*/
++
++int
++dm_add_fsys_entry(
++      struct super_block *sb,
++      dm_tokevent_t   *tevp)
++{
++      dm_fsreg_t      *fsrp;
++      int             msgsize;
++      void            *msg;
++      unsigned long   lc;                     /* lock cookie */
++      dm_fsid_t       fsid;
++      struct filesystem_dmapi_operations *dops;
++
++      dops = dm_fsys_ops(sb);
++      ASSERT(dops);
++      dops->get_fsid(sb, &fsid);
++
++      /* Allocate and initialize a dm_fsreg_t structure for the filesystem. */
++
++      msgsize = tevp->te_allocsize - offsetof(dm_tokevent_t, te_event);
++      msg = kmalloc(msgsize, GFP_KERNEL);
++      if (msg == NULL) {
++              printk("%s/%d: kmalloc returned NULL\n", __FUNCTION__, __LINE__);
++              return -ENOMEM;
++      }
++      memcpy(msg, &tevp->te_event, msgsize);
++
++      fsrp = kmem_cache_alloc(dm_fsreg_cachep, GFP_KERNEL);
++      if (fsrp == NULL) {
++              kfree(msg);
++              printk("%s/%d: kmem_cache_alloc(dm_fsreg_cachep) returned NULL\n", __FUNCTION__, __LINE__);
++              return -ENOMEM;
++      }
++      memset(fsrp, 0, sizeof(*fsrp));
++
++      fsrp->fr_sb = sb;
++      fsrp->fr_tevp = tevp;
++      memcpy(&fsrp->fr_fsid, &fsid, sizeof(fsid));
++      fsrp->fr_msg = msg;
++      fsrp->fr_msgsize = msgsize;
++      fsrp->fr_state = DM_STATE_MOUNTING;
++      sv_init(&fsrp->fr_dispq, SV_DEFAULT, "fr_dispq");
++      sv_init(&fsrp->fr_queue, SV_DEFAULT, "fr_queue");
++      spinlock_init(&fsrp->fr_lock, "fr_lock");
++
++      /* If no other mounted DMAPI filesystem already has this same
++         fsid_t, then add this filesystem to the list.
++      */
++
++      lc = mutex_spinlock(&dm_reg_lock);
++
++      if (!dm_find_fsreg(&fsid)) {
++              fsrp->fr_next = dm_registers;
++              dm_registers = fsrp;
++              dm_fsys_cnt++;
++              mutex_spinunlock(&dm_reg_lock, lc);
++#ifdef CONFIG_PROC_FS
++              {
++              char buf[100];
++              struct proc_dir_entry *entry;
++
++              sprintf(buf, DMAPI_DBG_PROCFS "/fsreg/0x%p", fsrp);
++              entry = create_proc_read_entry(buf, 0, NULL, fsreg_read_pfs, fsrp);
++              entry->owner = THIS_MODULE;
++              }
++#endif
++              return(0);
++      }
++
++      /* A fsid_t collision occurred, so prevent this new filesystem from
++         mounting.
++      */
++
++      mutex_spinunlock(&dm_reg_lock, lc);
++
++      sv_destroy(&fsrp->fr_dispq);
++      sv_destroy(&fsrp->fr_queue);
++      spinlock_destroy(&fsrp->fr_lock);
++      kfree(msg);
++      kmem_cache_free(dm_fsreg_cachep, fsrp);
++      return(-EBUSY);
++}
++
++
++/* dm_change_fsys_entry() is called whenever a filesystem's mount state is
++   about to change.  The state is changed to DM_STATE_MOUNTED after a
++   successful DM_EVENT_MOUNT event or after a failed unmount.  It is changed
++   to DM_STATE_UNMOUNTING after a successful DM_EVENT_PREUNMOUNT event.
++   Finally, the state is changed to DM_STATE_UNMOUNTED after a successful
++   unmount.  It stays in this state until the DM_EVENT_UNMOUNT event is
++   queued, at which point the filesystem entry is removed.
++*/
++
++void
++dm_change_fsys_entry(
++      struct super_block *sb,
++      dm_fsstate_t    newstate)
++{
++      dm_fsreg_t      *fsrp;
++      int             seq_error;
++      unsigned long   lc;                     /* lock cookie */
++      dm_fsid_t       fsid;
++      struct filesystem_dmapi_operations *dops;
++
++      /* Find the filesystem referenced by the sb's fsid_t.    This should
++         always succeed.
++      */
++
++      dops = dm_fsys_ops(sb);
++      ASSERT(dops);
++      dops->get_fsid(sb, &fsid);
++
++      if ((fsrp = dm_find_fsreg_and_lock(&fsid, &lc)) == NULL) {
++              panic("dm_change_fsys_entry: can't find DMAPI fsrp for "
++                      "sb %p\n", sb);
++      }
++
++      /* Make sure that the new state is acceptable given the current state
++         of the filesystem.  Any error here is a major DMAPI/filesystem
++         screwup.
++      */
++
++      seq_error = 0;
++      switch (newstate) {
++      case DM_STATE_MOUNTED:
++              if (fsrp->fr_state != DM_STATE_MOUNTING &&
++                  fsrp->fr_state != DM_STATE_UNMOUNTING) {
++                      seq_error++;
++              }
++              break;
++      case DM_STATE_UNMOUNTING:
++              if (fsrp->fr_state != DM_STATE_MOUNTED)
++                      seq_error++;
++              break;
++      case DM_STATE_UNMOUNTED:
++              if (fsrp->fr_state != DM_STATE_UNMOUNTING)
++                      seq_error++;
++              break;
++      default:
++              seq_error++;
++              break;
++      }
++      if (seq_error) {
++              panic("dm_change_fsys_entry: DMAPI sequence error: old state "
++                      "%d, new state %d, fsrp %p\n", fsrp->fr_state,
++                      newstate, fsrp);
++      }
++
++      /* If the old state was DM_STATE_UNMOUNTING, then processes could be
++         sleeping in dm_handle_to_ip() waiting for their DM_NO_TOKEN handles
++         to be translated to inodes.  Wake them up so that they either
++         continue (new state is DM_STATE_MOUNTED) or fail (new state is
++         DM_STATE_UNMOUNTED).
++      */
++
++      if (fsrp->fr_state == DM_STATE_UNMOUNTING) {
++              if (fsrp->fr_hdlcnt)
++                      sv_broadcast(&fsrp->fr_queue);
++      }
++
++      /* Change the filesystem's mount state to its new value. */
++
++      fsrp->fr_state = newstate;
++      fsrp->fr_tevp = NULL;           /* not valid after DM_STATE_MOUNTING */
++
++      /* If the new state is DM_STATE_UNMOUNTING, wait until any application
++         threads currently in the process of making VFS_VGET and VFS_ROOT
++         calls are done before we let this unmount thread continue the
++         unmount.  (We want to make sure that the unmount will see these
++         inode references during its scan.)
++      */
++
++      if (newstate == DM_STATE_UNMOUNTING) {
++              while (fsrp->fr_vfscnt) {
++                      fsrp->fr_unmount++;
++                      sv_wait(&fsrp->fr_queue, 1, &fsrp->fr_lock, lc);
++                      lc = mutex_spinlock(&fsrp->fr_lock);
++                      fsrp->fr_unmount--;
++              }
++      }
++
++      mutex_spinunlock(&fsrp->fr_lock, lc);
++}
++
++
++/* dm_remove_fsys_entry() gets called after a failed mount or after an
++   DM_EVENT_UNMOUNT event has been queued.  (The filesystem entry must stay
++   until the DM_EVENT_UNMOUNT reply is queued so that the event can use the
++   'fr_sessp' list to see which session to send the event to.)
++*/
++
++void
++dm_remove_fsys_entry(
++      struct super_block *sb)
++{
++      dm_fsreg_t      **fsrpp;
++      dm_fsreg_t      *fsrp;
++      unsigned long   lc;                     /* lock cookie */
++      struct filesystem_dmapi_operations *dops;
++      dm_fsid_t       fsid;
++
++      dops = dm_fsys_ops(sb);
++      ASSERT(dops);
++      dops->get_fsid(sb, &fsid);
++
++      /* Find the filesystem referenced by the sb's fsid_t and dequeue
++         it after verifying that the fr_state shows a filesystem that is
++         either mounting or unmounted.
++      */
++
++      lc = mutex_spinlock(&dm_reg_lock);
++
++      fsrpp = &dm_registers;
++      while ((fsrp = *fsrpp) != NULL) {
++              if (!memcmp(&fsrp->fr_fsid, &fsid, sizeof(fsrp->fr_fsid)))
++                      break;
++              fsrpp = &fsrp->fr_next;
++      }
++      if (fsrp == NULL) {
++              mutex_spinunlock(&dm_reg_lock, lc);
++              panic("dm_remove_fsys_entry: can't find DMAPI fsrp for "
++                      "sb %p\n", sb);
++      }
++
++      nested_spinlock(&fsrp->fr_lock);
++
++      /* Verify that it makes sense to remove this entry. */
++
++      if (fsrp->fr_state != DM_STATE_MOUNTING &&
++          fsrp->fr_state != DM_STATE_UNMOUNTED) {
++              nested_spinunlock(&fsrp->fr_lock);
++              mutex_spinunlock(&dm_reg_lock, lc);
++              panic("dm_remove_fsys_entry: DMAPI sequence error: old state "
++                      "%d, fsrp %p\n", fsrp->fr_state, fsrp);
++      }
++
++      *fsrpp = fsrp->fr_next;
++      dm_fsys_cnt--;
++
++      nested_spinunlock(&dm_reg_lock);
++
++      /* Since the filesystem is about to finish unmounting, we must be sure
++         that no inodes are being referenced within the filesystem before we
++         let this event thread continue.  If the filesystem is currently in
++         state DM_STATE_MOUNTING, then we know by definition that there can't
++         be any references.  If the filesystem is DM_STATE_UNMOUNTED, then
++         any application threads referencing handles with DM_NO_TOKEN should
++         have already been awakened by dm_change_fsys_entry and should be
++         long gone by now.  Just in case they haven't yet left, sleep here
++         until they are really gone.
++      */
++
++      while (fsrp->fr_hdlcnt) {
++              fsrp->fr_unmount++;
++              sv_wait(&fsrp->fr_queue, 1, &fsrp->fr_lock, lc);
++              lc = mutex_spinlock(&fsrp->fr_lock);
++              fsrp->fr_unmount--;
++      }
++      mutex_spinunlock(&fsrp->fr_lock, lc);
++
++      /* Release all memory. */
++
++#ifdef CONFIG_PROC_FS
++      {
++      char buf[100];
++      sprintf(buf, DMAPI_DBG_PROCFS "/fsreg/0x%p", fsrp);
++      remove_proc_entry(buf, NULL);
++      }
++#endif
++      dm_fsys_ops_release(sb);
++      sv_destroy(&fsrp->fr_dispq);
++      sv_destroy(&fsrp->fr_queue);
++      spinlock_destroy(&fsrp->fr_lock);
++      kfree(fsrp->fr_msg);
++      kmem_cache_free(dm_fsreg_cachep, fsrp);
++}
++
++
++/* Get an inode for the object referenced by handlep.  We cannot use
++   altgetvfs() because it fails if the VFS_OFFLINE bit is set, which means
++   that any call to dm_handle_to_ip() while a umount is in progress would
++   return an error, even if the umount can't possibly succeed because users
++   are in the filesystem.  The requests would start to fail as soon as the
++   umount begins, even before the application receives the DM_EVENT_PREUNMOUNT
++   event.
++
++   dm_handle_to_ip() emulates the behavior of lookup() while an unmount is
++   in progress.        Any call to dm_handle_to_ip() while the filesystem is in the
++   DM_STATE_UNMOUNTING state will block.  If the unmount eventually succeeds,
++   the requests will wake up and fail.        If the unmount fails, the requests will
++   wake up and complete normally.
++
++   While a filesystem is in state DM_STATE_MOUNTING, dm_handle_to_ip() will
++   fail all requests.  Per the DMAPI spec, the only handles in the filesystem
++   which are valid during a mount event are the handles within the event
++   itself.
++*/
++
++struct inode *
++dm_handle_to_ip(
++      dm_handle_t     *handlep,
++      short           *typep)
++{
++      dm_fsreg_t      *fsrp;
++      short           type;
++      unsigned long   lc;                     /* lock cookie */
++      int             error = 0;
++      dm_fid_t        *fidp;
++      struct super_block *sb;
++      struct inode    *ip;
++      int             filetype;
++      struct filesystem_dmapi_operations *dmapiops;
++
++      if ((fsrp = dm_find_fsreg_and_lock(&handlep->ha_fsid, &lc)) == NULL)
++              return NULL;
++
++      fidp = (dm_fid_t*)&handlep->ha_fid;
++      /* If mounting, and we are not asking for a filesystem handle,
++       * then fail the request.  (dm_fid_len==0 for fshandle)
++       */
++      if ((fsrp->fr_state == DM_STATE_MOUNTING) &&
++          (fidp->dm_fid_len != 0)) {
++              mutex_spinunlock(&fsrp->fr_lock, lc);
++              return NULL;
++      }
++
++      for (;;) {
++              if (fsrp->fr_state == DM_STATE_MOUNTING)
++                      break;
++              if (fsrp->fr_state == DM_STATE_MOUNTED)
++                      break;
++              if (fsrp->fr_state == DM_STATE_UNMOUNTED) {
++                      if (fsrp->fr_unmount && fsrp->fr_hdlcnt == 0)
++                              sv_broadcast(&fsrp->fr_queue);
++                      mutex_spinunlock(&fsrp->fr_lock, lc);
++                      return NULL;
++              }
++
++              /* Must be DM_STATE_UNMOUNTING. */
++
++              fsrp->fr_hdlcnt++;
++              sv_wait(&fsrp->fr_queue, 1, &fsrp->fr_lock, lc);
++              lc = mutex_spinlock(&fsrp->fr_lock);
++              fsrp->fr_hdlcnt--;
++      }
++
++      fsrp->fr_vfscnt++;
++      mutex_spinunlock(&fsrp->fr_lock, lc);
++
++      /* Now that the mutex is released, wait until we have access to the
++         inode.
++      */
++
++      sb = fsrp->fr_sb;
++      error = -ENOSYS;
++      dmapiops = dm_fsys_ops(sb);
++      ASSERT(dmapiops);
++      if (dmapiops->fh_to_inode)
++              error = dmapiops->fh_to_inode(sb, &ip, (void*)fidp);
++
++      lc = mutex_spinlock(&fsrp->fr_lock);
++
++      fsrp->fr_vfscnt--;
++      if (fsrp->fr_unmount && fsrp->fr_vfscnt == 0)
++              sv_broadcast(&fsrp->fr_queue);
++
++      mutex_spinunlock(&fsrp->fr_lock, lc);
++      if (error || ip == NULL)
++              return NULL;
++
++      filetype = ip->i_mode & S_IFMT;
++      if (fidp->dm_fid_len == 0) {
++              type = DM_TDT_VFS;
++      } else if (filetype == S_IFREG) {
++              type = DM_TDT_REG;
++      } else if (filetype == S_IFDIR) {
++              type = DM_TDT_DIR;
++      } else if (filetype == S_IFLNK) {
++              type = DM_TDT_LNK;
++      } else {
++              type = DM_TDT_OTH;
++      }
++      *typep = type;
++      return ip;
++}
++
++
++int
++dm_ip_to_handle(
++      struct inode    *ip,
++      dm_handle_t     *handlep)
++{
++      int             error;
++      dm_fid_t        fid;
++      dm_fsid_t       fsid;
++      int             hsize;
++      struct filesystem_dmapi_operations *dops;
++
++      dops = dm_fsys_ops(ip->i_sb);
++      ASSERT(dops);
++
++      error = dops->inode_to_fh(ip, &fid, &fsid);
++      if (error)
++              return error;
++
++      memcpy(&handlep->ha_fsid, &fsid, sizeof(fsid));
++      memcpy(&handlep->ha_fid, &fid, fid.dm_fid_len + sizeof fid.dm_fid_len);
++      hsize = DM_HSIZE(*handlep);
++      memset((char *)handlep + hsize, 0, sizeof(*handlep) - hsize);
++      return 0;
++}
++
++
++/* Given an inode, check if that inode resides in filesystem that supports
++   DMAPI.  Returns zero if the inode is in a DMAPI filesystem, otherwise
++   returns an errno.
++*/
++
++int
++dm_check_dmapi_ip(
++      struct inode    *ip)
++{
++      dm_handle_t     handle;
++      /* REFERENCED */
++      dm_fsreg_t      *fsrp;
++      int             error;
++      unsigned long   lc;                     /* lock cookie */
++
++      if ((error = dm_ip_to_handle(ip, &handle)) != 0)
++              return(error);
++
++      if ((fsrp = dm_find_fsreg_and_lock(&handle.ha_fsid, &lc)) == NULL)
++              return(-EBADF);
++      mutex_spinunlock(&fsrp->fr_lock, lc);
++      return(0);
++}
++
++
++/* Return a pointer to the DM_EVENT_MOUNT event while a mount is still in
++   progress.  This is only called by dm_get_config and dm_get_config_events
++   which need to access the filesystem during a mount but which don't have
++   a session and token to use.
++*/
++
++dm_tokevent_t *
++dm_find_mount_tevp_and_lock(
++      dm_fsid_t       *fsidp,
++      unsigned long   *lcp)           /* address of returned lock cookie */
++{
++      dm_fsreg_t      *fsrp;
++
++      if ((fsrp = dm_find_fsreg_and_lock(fsidp, lcp)) == NULL)
++              return(NULL);
++
++      if (!fsrp->fr_tevp || fsrp->fr_state != DM_STATE_MOUNTING) {
++              mutex_spinunlock(&fsrp->fr_lock, *lcp);
++              return(NULL);
++      }
++      nested_spinlock(&fsrp->fr_tevp->te_lock);
++      nested_spinunlock(&fsrp->fr_lock);
++      return(fsrp->fr_tevp);
++}
++
++
++/* Wait interruptibly until a session registers disposition for 'event' in
++   filesystem 'sb'.  Upon successful exit, both the filesystem's dm_fsreg_t
++   structure and the session's dm_session_t structure are locked.  The caller
++   is responsible for unlocking both structures using the returned cookies.
++
++   Warning: The locks can be dropped in any order, but the 'lc2p' cookie MUST
++   BE USED FOR THE FIRST UNLOCK, and the lc1p cookie must be used for the
++   second unlock.  If this is not done, the CPU will be interruptible while
++   holding a mutex, which could deadlock the machine!
++*/
++
++static int
++dm_waitfor_disp(
++      struct super_block *sb,
++      dm_tokevent_t   *tevp,
++      dm_fsreg_t      **fsrpp,
++      unsigned long   *lc1p,          /* addr of first returned lock cookie */
++      dm_session_t    **sessionpp,
++      unsigned long   *lc2p)          /* addr of 2nd returned lock cookie */
++{
++      dm_eventtype_t  event = tevp->te_msg.ev_type;
++      dm_session_t    *s;
++      dm_fsreg_t      *fsrp;
++      dm_fsid_t       fsid;
++      struct filesystem_dmapi_operations *dops;
++
++      dops = dm_fsys_ops(sb);
++      ASSERT(dops);
++
++      dops->get_fsid(sb, &fsid);
++      if ((fsrp = dm_find_fsreg_and_lock(&fsid, lc1p)) == NULL)
++              return -ENOENT;
++
++      /* If no session is registered for this event in the specified
++         filesystem, then sleep interruptibly until one does.
++      */
++
++      for (;;) {
++              int     rc = 0;
++
++              /* The dm_find_session_and_lock() call is needed because a
++                 session that is in the process of being removed might still
++                 be in the dm_fsreg_t structure but won't be in the
++                 dm_sessions list.
++              */
++
++              if ((s = fsrp->fr_sessp[event]) != NULL &&
++                  dm_find_session_and_lock(s->sn_sessid, &s, lc2p) == 0) {
++                      break;
++              }
++
++              /* Noone is currently registered.  DM_EVENT_UNMOUNT events
++                 don't wait for anyone to register because the unmount is
++                 already past the point of no return.
++              */
++
++              if (event == DM_EVENT_UNMOUNT) {
++                      mutex_spinunlock(&fsrp->fr_lock, *lc1p);
++                      return -ENOENT;
++              }
++
++              /* Wait until a session registers for disposition of this
++                 event.
++              */
++
++              fsrp->fr_dispcnt++;
++              dm_link_event(tevp, &fsrp->fr_evt_dispq);
++
++              sv_wait_sig(&fsrp->fr_dispq, 1, &fsrp->fr_lock, *lc1p);
++              rc = signal_pending(current);
++
++              *lc1p = mutex_spinlock(&fsrp->fr_lock);
++              fsrp->fr_dispcnt--;
++              dm_unlink_event(tevp, &fsrp->fr_evt_dispq);
++#ifdef HAVE_DM_QUEUE_FLUSH
++              if (tevp->te_flags & DM_TEF_FLUSH) {
++                      mutex_spinunlock(&fsrp->fr_lock, *lc1p);
++                      return tevp->te_reply;
++              }
++#endif /* HAVE_DM_QUEUE_FLUSH */
++              if (rc) {               /* if signal was received */
++                      mutex_spinunlock(&fsrp->fr_lock, *lc1p);
++                      return -EINTR;
++              }
++      }
++      *sessionpp = s;
++      *fsrpp = fsrp;
++      return 0;
++}
++
++
++/* Returns the session pointer for the session registered for an event
++   in the given sb.  If successful, the session is locked upon return.  The
++   caller is responsible for releasing the lock.  If no session is currently
++   registered for the event, dm_waitfor_disp_session() will sleep interruptibly
++   until a registration occurs.
++*/
++
++int
++dm_waitfor_disp_session(
++      struct super_block *sb,
++      dm_tokevent_t   *tevp,
++      dm_session_t    **sessionpp,
++      unsigned long   *lcp)
++{
++      dm_fsreg_t      *fsrp;
++      unsigned long   lc2;
++      int             error;
++
++      if (tevp->te_msg.ev_type < 0 || tevp->te_msg.ev_type > DM_EVENT_MAX)
++              return(-EIO);
++
++      error = dm_waitfor_disp(sb, tevp, &fsrp, lcp, sessionpp, &lc2);
++      if (!error)
++              mutex_spinunlock(&fsrp->fr_lock, lc2);  /* rev. cookie order*/
++      return(error);
++}
++
++
++/* Find the session registered for the DM_EVENT_DESTROY event on the specified
++   filesystem, sleeping if necessary until registration occurs.        Once found,
++   copy the session's return-on-destroy attribute name, if any, back to the
++   caller.
++*/
++
++int
++dm_waitfor_destroy_attrname(
++      struct super_block *sbp,
++      dm_attrname_t   *attrnamep)
++{
++      dm_tokevent_t   *tevp;
++      dm_session_t    *s;
++      dm_fsreg_t      *fsrp;
++      int             error;
++      unsigned long   lc1;            /* first lock cookie */
++      unsigned long   lc2;            /* second lock cookie */
++      void            *msgp;
++
++      tevp = dm_evt_create_tevp(DM_EVENT_DESTROY, 1, (void**)&msgp);
++      error = dm_waitfor_disp(sbp, tevp, &fsrp, &lc1, &s, &lc2);
++      if (!error) {
++              *attrnamep = fsrp->fr_rattr;            /* attribute or zeros */
++              mutex_spinunlock(&s->sn_qlock, lc2);    /* rev. cookie order */
++              mutex_spinunlock(&fsrp->fr_lock, lc1);
++      }
++      dm_evt_rele_tevp(tevp,0);
++      return(error);
++}
++
++
++/* Unregisters the session for the disposition of all events on all
++   filesystems.        This routine is not called until the session has been
++   dequeued from the session list and its session lock has been dropped,
++   but before the actual structure is freed, so it is safe to grab the
++   'dm_reg_lock' here.        If dm_waitfor_disp_session() happens to be called
++   by another thread, it won't find this session on the session list and
++   will wait until a new session registers.
++*/
++
++void
++dm_clear_fsreg(
++      dm_session_t    *s)
++{
++      dm_fsreg_t      *fsrp;
++      int             event;
++      unsigned long   lc;                     /* lock cookie */
++
++      lc = mutex_spinlock(&dm_reg_lock);
++
++      for (fsrp = dm_registers; fsrp != NULL; fsrp = fsrp->fr_next) {
++              nested_spinlock(&fsrp->fr_lock);
++              for (event = 0; event < DM_EVENT_MAX; event++) {
++                      if (fsrp->fr_sessp[event] != s)
++                              continue;
++                      fsrp->fr_sessp[event] = NULL;
++                      if (event == DM_EVENT_DESTROY)
++                              memset(&fsrp->fr_rattr, 0, sizeof(fsrp->fr_rattr));
++              }
++              nested_spinunlock(&fsrp->fr_lock);
++      }
++
++      mutex_spinunlock(&dm_reg_lock, lc);
++}
++
++
++/*
++ *  Return the handle for the object named by path.
++ */
++
++int
++dm_path_to_hdl(
++      char            __user *path,   /* any path name */
++      void            __user *hanp,   /* user's data buffer */
++      size_t          __user *hlenp)  /* set to size of data copied */
++{
++      /* REFERENCED */
++      dm_fsreg_t      *fsrp;
++      dm_handle_t     handle;
++      size_t          hlen;
++      int             error;
++      unsigned long   lc;             /* lock cookie */
++      struct nameidata nd;
++      struct inode *inode;
++      size_t          len;
++      char            *name;
++      struct filesystem_dmapi_operations *dops;
++
++      /* XXX get things straightened out so getname() works here? */
++      if (!(len = strnlen_user(path, PATH_MAX)))
++              return(-EFAULT);
++      if (len == 1)
++              return(-ENOENT);
++      if (len > PATH_MAX)
++              return(-ENAMETOOLONG);
++      name = kmalloc(len, GFP_KERNEL);
++      if (name == NULL) {
++              printk("%s/%d: kmalloc returned NULL\n", __FUNCTION__, __LINE__);
++              return(-ENOMEM);
++      }
++      if (copy_from_user(name, path, len)) {
++              kfree(name);
++              return(-EFAULT);
++      }
++
++      error = path_lookup(name, LOOKUP_POSITIVE, &nd);
++      kfree(name);
++      if (error)
++              return error;
++
++      ASSERT(nd.path.dentry);
++      ASSERT(nd.path.dentry->d_inode);
++      inode = igrab(nd.path.dentry->d_inode);
++      path_put(&nd.path);
++
++      dops = dm_fsys_ops(inode->i_sb);
++      if (dops == NULL) {
++              /* No longer in a dmapi-capable filesystem...Toto */
++              iput(inode);
++              return -EINVAL;
++      }
++
++      /* we need the inode */
++      error = dm_ip_to_handle(inode, &handle);
++      iput(inode);
++      if (error)
++              return(error);
++
++      if ((fsrp = dm_find_fsreg_and_lock(&handle.ha_fsid, &lc)) == NULL)
++              return(-EBADF);
++      mutex_spinunlock(&fsrp->fr_lock, lc);
++
++      hlen = DM_HSIZE(handle);
++
++      if (copy_to_user(hanp, &handle, (int)hlen))
++              return(-EFAULT);
++      if (put_user(hlen,hlenp))
++              return(-EFAULT);
++      return 0;
++}
++
++
++/*
++ *  Return the handle for the file system containing the object named by path.
++ */
++
++int
++dm_path_to_fshdl(
++      char            __user *path,   /* any path name */
++      void            __user *hanp,   /* user's data buffer */
++      size_t          __user *hlenp)  /* set to size of data copied */
++{
++      /* REFERENCED */
++      dm_fsreg_t      *fsrp;
++      dm_handle_t     handle;
++      size_t          hlen;
++      int             error;
++      unsigned long   lc;             /* lock cookie */
++      struct nameidata nd;
++      struct inode *inode;
++      size_t          len;
++      char            *name;
++      struct filesystem_dmapi_operations *dops;
++
++      /* XXX get things straightened out so getname() works here? */
++      if(!(len = strnlen_user(path, PATH_MAX)))
++              return(-EFAULT);
++      if (len == 1)
++              return(-ENOENT);
++      if (len > PATH_MAX)
++              return(-ENAMETOOLONG);
++      name = kmalloc(len, GFP_KERNEL);
++      if (name == NULL) {
++              printk("%s/%d: kmalloc returned NULL\n", __FUNCTION__, __LINE__);
++              return(-ENOMEM);
++      }
++      if (copy_from_user(name, path, len)) {
++              kfree(name);
++              return(-EFAULT);
++      }
++
++      error = path_lookup(name, LOOKUP_POSITIVE|LOOKUP_FOLLOW, &nd);
++      kfree(name);
++      if (error)
++              return error;
++
++      ASSERT(nd.path.dentry);
++      ASSERT(nd.path.dentry->d_inode);
++
++      inode = igrab(nd.path.dentry->d_inode);
++      path_put(&nd.path);
++
++      dops = dm_fsys_ops(inode->i_sb);
++      if (dops == NULL) {
++              /* No longer in a dmapi-capable filesystem...Toto */
++              iput(inode);
++              return -EINVAL;
++      }
++
++      error = dm_ip_to_handle(inode, &handle);
++      iput(inode);
++
++      if (error)
++              return(error);
++
++      if ((fsrp = dm_find_fsreg_and_lock(&handle.ha_fsid, &lc)) == NULL)
++              return(-EBADF);
++      mutex_spinunlock(&fsrp->fr_lock, lc);
++
++      hlen = DM_FSHSIZE;
++      if(copy_to_user(hanp, &handle, (int)hlen))
++              return(-EFAULT);
++      if(put_user(hlen,hlenp))
++              return(-EFAULT);
++      return 0;
++}
++
++
++int
++dm_fd_to_hdl(
++      int             fd,             /* any file descriptor */
++      void            __user *hanp,   /* user's data buffer */
++      size_t          __user *hlenp)  /* set to size of data copied */
++{
++      /* REFERENCED */
++      dm_fsreg_t      *fsrp;
++      dm_handle_t     handle;
++      size_t          hlen;
++      int             error;
++      unsigned long   lc;             /* lock cookie */
++      struct file     *filep = fget(fd);
++      struct inode    *ip = filep->f_dentry->d_inode;
++
++      if (!filep)
++              return(-EBADF);
++      if ((error = dm_ip_to_handle(ip, &handle)) != 0)
++              return(error);
++
++      if ((fsrp = dm_find_fsreg_and_lock(&handle.ha_fsid, &lc)) == NULL)
++              return(-EBADF);
++      mutex_spinunlock(&fsrp->fr_lock, lc);
++
++      hlen = DM_HSIZE(handle);
++      if (copy_to_user(hanp, &handle, (int)hlen))
++              return(-EFAULT);
++      fput(filep);
++      if(put_user(hlen, hlenp))
++              return(-EFAULT);
++      return 0;
++}
++
++
++/* Enable events on an object. */
++
++int
++dm_set_eventlist(
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token,
++      dm_eventset_t   __user *eventsetp,
++      u_int           maxevent)
++{
++      dm_fsys_vector_t *fsys_vector;
++      dm_eventset_t   eventset;
++      dm_tokdata_t    *tdp;
++      int             error;
++
++      if (copy_from_user(&eventset, eventsetp, sizeof(eventset)))
++              return(-EFAULT);
++
++      /* Do some minor sanity checking. */
++
++      if (maxevent == 0 || maxevent > DM_EVENT_MAX)
++              return(-EINVAL);
++
++      /* Access the specified object. */
++
++      error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_ANY,
++              DM_RIGHT_EXCL, &tdp);
++      if (error != 0)
++              return(error);
++
++      fsys_vector = dm_fsys_vector(tdp->td_ip);
++      error = fsys_vector->set_eventlist(tdp->td_ip, tdp->td_right,
++              (tdp->td_type == DM_TDT_VFS ? DM_FSYS_OBJ : 0),
++              &eventset, maxevent);
++
++      dm_app_put_tdp(tdp);
++      return(error);
++}
++
++
++/* Return the list of enabled events for an object. */
++
++int
++dm_get_eventlist(
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token,
++      u_int           nelem,
++      dm_eventset_t   __user *eventsetp,
++      u_int           __user *nelemp)
++{
++      dm_fsys_vector_t *fsys_vector;
++      dm_tokdata_t    *tdp;
++      dm_eventset_t   eventset;
++      u_int           elem;
++      int             error;
++
++      if (nelem == 0)
++              return(-EINVAL);
++
++      /* Access the specified object. */
++
++      error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_ANY,
++              DM_RIGHT_SHARED, &tdp);
++      if (error != 0)
++              return(error);
++
++      /* Get the object's event list. */
++
++      fsys_vector = dm_fsys_vector(tdp->td_ip);
++      error = fsys_vector->get_eventlist(tdp->td_ip, tdp->td_right,
++              (tdp->td_type == DM_TDT_VFS ? DM_FSYS_OBJ : 0),
++              nelem, &eventset, &elem);
++
++      dm_app_put_tdp(tdp);
++
++      if (error)
++              return(error);
++
++      if (copy_to_user(eventsetp, &eventset, sizeof(eventset)))
++              return(-EFAULT);
++      if (put_user(nelem, nelemp))
++              return(-EFAULT);
++      return(0);
++}
++
++
++/* Register for disposition of events.        The handle must either be the
++   global handle or must be the handle of a file system.  The list of events
++   is pointed to by eventsetp.
++*/
++
++int
++dm_set_disp(
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token,
++      dm_eventset_t   __user *eventsetp,
++      u_int           maxevent)
++{
++      dm_session_t    *s;
++      dm_fsreg_t      *fsrp;
++      dm_tokdata_t    *tdp;
++      dm_eventset_t   eventset;
++      int             error;
++      unsigned long   lc1;            /* first lock cookie */
++      unsigned long   lc2;            /* second lock cookie */
++      u_int           i;
++
++      /* Copy in and validate the event mask.  Only the lower maxevent bits
++         are meaningful, so clear any bits set above maxevent.
++      */
++
++      if (maxevent == 0 || maxevent > DM_EVENT_MAX)
++              return(-EINVAL);
++      if (copy_from_user(&eventset, eventsetp, sizeof(eventset)))
++              return(-EFAULT);
++      eventset &= (1 << maxevent) - 1;
++
++      /* If the caller specified the global handle, then the only valid token
++         is DM_NO_TOKEN, and the only valid event in the event mask is
++         DM_EVENT_MOUNT.  If it is set, add the session to the list of
++         sessions that want to receive mount events.  If it is clear, remove
++         the session from the list.  Since DM_EVENT_MOUNT events never block
++         waiting for a session to register, there is noone to wake up if we
++         do add the session to the list.
++      */
++
++      if (DM_GLOBALHAN(hanp, hlen)) {
++              if (token != DM_NO_TOKEN)
++                      return(-EINVAL);
++              if ((error = dm_find_session_and_lock(sid, &s, &lc1)) != 0)
++                      return(error);
++              if (eventset == 0) {
++                      s->sn_flags &= ~DM_SN_WANTMOUNT;
++                      error = 0;
++              } else if (eventset == 1 << DM_EVENT_MOUNT) {
++                      s->sn_flags |= DM_SN_WANTMOUNT;
++                      error = 0;
++              } else {
++                      error = -EINVAL;
++              }
++              mutex_spinunlock(&s->sn_qlock, lc1);
++              return(error);
++      }
++
++      /* Since it's not the global handle, it had better be a filesystem
++         handle.  Verify that the first 'maxevent' events in the event list
++         are all valid for a filesystem handle.
++      */
++
++      if (eventset & ~DM_VALID_DISP_EVENTS)
++              return(-EINVAL);
++
++      /* Verify that the session is valid, that the handle is a filesystem
++         handle, and that the filesystem is capable of sending events.  (If
++         a dm_fsreg_t structure exists, then the filesystem can issue events.)
++      */
++
++      error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VFS,
++              DM_RIGHT_EXCL, &tdp);
++      if (error != 0)
++              return(error);
++
++      fsrp = dm_find_fsreg_and_lock(&tdp->td_handle.ha_fsid, &lc1);
++      if (fsrp == NULL) {
++              dm_app_put_tdp(tdp);
++              return(-EINVAL);
++      }
++
++      /* Now that we own 'fsrp->fr_lock', get the lock on the session so that
++         it can't disappear while we add it to the filesystem's event mask.
++      */
++
++      if ((error = dm_find_session_and_lock(sid, &s, &lc2)) != 0) {
++              mutex_spinunlock(&fsrp->fr_lock, lc1);
++              dm_app_put_tdp(tdp);
++              return(error);
++      }
++
++      /* Update the event disposition array for this filesystem, adding
++         and/or removing the session as appropriate.  If this session is
++         dropping registration for DM_EVENT_DESTROY, or is overriding some
++         other session's registration for DM_EVENT_DESTROY, then clear any
++         any attr-on-destroy attribute name also.
++      */
++
++      for (i = 0; i < DM_EVENT_MAX; i++) {
++              if (DMEV_ISSET(i, eventset)) {
++                      if (i == DM_EVENT_DESTROY && fsrp->fr_sessp[i] != s)
++                              memset(&fsrp->fr_rattr, 0, sizeof(fsrp->fr_rattr));
++                      fsrp->fr_sessp[i] = s;
++              } else if (fsrp->fr_sessp[i] == s) {
++                      if (i == DM_EVENT_DESTROY)
++                              memset(&fsrp->fr_rattr, 0, sizeof(fsrp->fr_rattr));
++                      fsrp->fr_sessp[i] = NULL;
++              }
++      }
++      mutex_spinunlock(&s->sn_qlock, lc2);    /* reverse cookie order */
++
++      /* Wake up all processes waiting for a disposition on this filesystem
++         in case any of them happen to be waiting for an event which we just
++         added.
++      */
++
++      if (fsrp->fr_dispcnt)
++              sv_broadcast(&fsrp->fr_dispq);
++
++      mutex_spinunlock(&fsrp->fr_lock, lc1);
++
++      dm_app_put_tdp(tdp);
++      return(0);
++}
++
++
++/*
++ *    Register a specific attribute name with a filesystem.  The value of
++ *    the attribute is to be returned with an asynchronous destroy event.
++ */
++
++int
++dm_set_return_on_destroy(
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token,
++      dm_attrname_t   __user *attrnamep,
++      dm_boolean_t    enable)
++{
++      dm_attrname_t   attrname;
++      dm_tokdata_t    *tdp;
++      dm_fsreg_t      *fsrp;
++      dm_session_t    *s;
++      int             error;
++      unsigned long   lc1;            /* first lock cookie */
++      unsigned long   lc2;            /* second lock cookie */
++
++      /* If a dm_attrname_t is provided, copy it in and validate it. */
++
++      if (enable && (error = copy_from_user(&attrname, attrnamep, sizeof(attrname))) != 0)
++              return(error);
++
++      /* Validate the filesystem handle and use it to get the filesystem's
++         disposition structure.
++      */
++
++      error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VFS,
++              DM_RIGHT_EXCL, &tdp);
++      if (error != 0)
++              return(error);
++
++      fsrp = dm_find_fsreg_and_lock(&tdp->td_handle.ha_fsid, &lc1);
++      if (fsrp == NULL) {
++              dm_app_put_tdp(tdp);
++              return(-EINVAL);
++      }
++
++      /* Now that we own 'fsrp->fr_lock', get the lock on the session so that
++         it can't disappear while we add it to the filesystem's event mask.
++      */
++
++      if ((error = dm_find_session_and_lock(sid, &s, &lc2)) != 0) {
++              mutex_spinunlock(&fsrp->fr_lock, lc1);
++              dm_app_put_tdp(tdp);
++              return(error);
++      }
++
++      /* A caller cannot disable return-on-destroy if he is not registered
++         for DM_EVENT_DESTROY.  Enabling return-on-destroy is an implicit
++         dm_set_disp() for DM_EVENT_DESTROY; we wake up all processes
++         waiting for a disposition in case any was waiting for a
++         DM_EVENT_DESTROY event.
++      */
++
++      error = 0;
++      if (enable) {
++              fsrp->fr_sessp[DM_EVENT_DESTROY] = s;
++              fsrp->fr_rattr = attrname;
++              if (fsrp->fr_dispcnt)
++                      sv_broadcast(&fsrp->fr_dispq);
++      } else if (fsrp->fr_sessp[DM_EVENT_DESTROY] != s) {
++              error = -EINVAL;
++      } else {
++              memset(&fsrp->fr_rattr, 0, sizeof(fsrp->fr_rattr));
++      }
++      mutex_spinunlock(&s->sn_qlock, lc2);    /* reverse cookie order */
++      mutex_spinunlock(&fsrp->fr_lock, lc1);
++      dm_app_put_tdp(tdp);
++      return(error);
++}
++
++
++int
++dm_get_mountinfo(
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token,
++      size_t          buflen,
++      void            __user *bufp,
++      size_t          __user *rlenp)
++{
++      dm_fsreg_t      *fsrp;
++      dm_tokdata_t    *tdp;
++      int             error;
++      unsigned long   lc;             /* lock cookie */
++
++      /* Make sure that the caller's buffer is 8-byte aligned. */
++
++      if (((unsigned long)bufp & (sizeof(__u64) - 1)) != 0)
++              return(-EFAULT);
++
++      /* Verify that the handle is a filesystem handle, and that the
++         filesystem is capable of sending events.  If not, return an error.
++      */
++
++      error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VFS,
++              DM_RIGHT_SHARED, &tdp);
++      if (error != 0)
++              return(error);
++
++      /* Find the filesystem entry.  This should always succeed as the
++         dm_app_get_tdp call created a filesystem reference.  Once we find
++         the entry, drop the lock.  The mountinfo message is never modified,
++         the filesystem entry can't disappear, and we don't want to hold a
++         spinlock while doing copyout calls.
++      */
++
++      fsrp = dm_find_fsreg_and_lock(&tdp->td_handle.ha_fsid, &lc);
++      if (fsrp == NULL) {
++              dm_app_put_tdp(tdp);
++              return(-EINVAL);
++      }
++      mutex_spinunlock(&fsrp->fr_lock, lc);
++
++      /* Copy the message into the user's buffer and update his 'rlenp'. */
++
++      if (put_user(fsrp->fr_msgsize, rlenp)) {
++              error = -EFAULT;
++      } else if (fsrp->fr_msgsize > buflen) { /* user buffer not big enough */
++              error = -E2BIG;
++      } else if (copy_to_user(bufp, fsrp->fr_msg, fsrp->fr_msgsize)) {
++              error = -EFAULT;
++      } else {
++              error = 0;
++      }
++      dm_app_put_tdp(tdp);
++      return(error);
++}
++
++
++int
++dm_getall_disp(
++      dm_sessid_t     sid,
++      size_t          buflen,
++      void            __user *bufp,
++      size_t          __user  *rlenp)
++{
++      dm_session_t    *s;             /* pointer to session given by sid */
++      unsigned long   lc1;            /* first lock cookie */
++      unsigned long   lc2;            /* second lock cookie */
++      int             totalsize;
++      int             msgsize;
++      int             fsyscnt;
++      dm_dispinfo_t   *prevmsg;
++      dm_fsreg_t      *fsrp;
++      int             error;
++      char            *kbuf;
++
++      int tmp3;
++      int tmp4;
++
++      /* Because the dm_getall_disp structure contains a __u64 field,
++         make sure that the buffer provided by the caller is aligned so
++         that he can read such fields successfully.
++      */
++
++      if (((unsigned long)bufp & (sizeof(__u64) - 1)) != 0)
++              return(-EFAULT);
++
++      /* Compute the size of a dm_dispinfo structure, rounding up to an
++         8-byte boundary so that any subsequent structures will also be
++         aligned.
++      */
++
++#if 0
++      /* XXX  ug, what is going on here? */
++      msgsize = (sizeof(dm_dispinfo_t) + DM_FSHSIZE + sizeof(uint64_t) - 1) &
++              ~(sizeof(uint64_t) - 1);
++#else
++      tmp3 = sizeof(dm_dispinfo_t) + DM_FSHSIZE;
++      tmp3 += sizeof(__u64);
++      tmp3 -= 1;
++      tmp4 = ~((int)sizeof(__u64) - 1);
++      msgsize = tmp3 & tmp4;
++#endif
++
++      /* Loop until we can get the right amount of temp space, being careful
++         not to hold a mutex during the allocation.  Usually only one trip.
++      */
++
++      for (;;) {
++              if ((fsyscnt = dm_fsys_cnt) == 0) {
++                      /*if (dm_cpoutsizet(rlenp, 0))*/
++                      if (put_user(0,rlenp))
++                              return(-EFAULT);
++                      return(0);
++              }
++              kbuf = kmalloc(fsyscnt * msgsize, GFP_KERNEL);
++              if (kbuf == NULL) {
++                      printk("%s/%d: kmalloc returned NULL\n", __FUNCTION__, __LINE__);
++                      return -ENOMEM;
++              }
++
++              lc1 = mutex_spinlock(&dm_reg_lock);
++              if (fsyscnt == dm_fsys_cnt)
++                      break;
++
++              mutex_spinunlock(&dm_reg_lock, lc1);
++              kfree(kbuf);
++      }
++
++      /* Find the indicated session and lock it. */
++
++      if ((error = dm_find_session_and_lock(sid, &s, &lc2)) != 0) {
++              mutex_spinunlock(&dm_reg_lock, lc1);
++              kfree(kbuf);
++              return(error);
++      }
++
++      /* Create a dm_dispinfo structure for each filesystem in which
++         this session has at least one event selected for disposition.
++      */
++
++      totalsize = 0;          /* total bytes to transfer to the user */
++      prevmsg = NULL;
++
++      for (fsrp = dm_registers; fsrp; fsrp = fsrp->fr_next) {
++              dm_dispinfo_t   *disp;
++              int             event;
++              int             found;
++
++              disp = (dm_dispinfo_t *)(kbuf + totalsize);
++
++              DMEV_ZERO(disp->di_eventset);
++
++              for (event = 0, found = 0; event < DM_EVENT_MAX; event++) {
++                      if (fsrp->fr_sessp[event] != s)
++                              continue;
++                      DMEV_SET(event, disp->di_eventset);
++                      found++;
++              }
++              if (!found)
++                      continue;
++
++              disp->_link = 0;
++              disp->di_fshandle.vd_offset = sizeof(dm_dispinfo_t);
++              disp->di_fshandle.vd_length = DM_FSHSIZE;
++
++              memcpy((char *)disp + disp->di_fshandle.vd_offset,
++                      &fsrp->fr_fsid, disp->di_fshandle.vd_length);
++
++              if (prevmsg)
++                      prevmsg->_link = msgsize;
++
++              prevmsg = disp;
++              totalsize += msgsize;
++      }
++      mutex_spinunlock(&s->sn_qlock, lc2);    /* reverse cookie order */
++      mutex_spinunlock(&dm_reg_lock, lc1);
++
++      if (put_user(totalsize, rlenp)) {
++              error = -EFAULT;
++      } else if (totalsize > buflen) {        /* no more room */
++              error = -E2BIG;
++      } else if (totalsize && copy_to_user(bufp, kbuf, totalsize)) {
++              error = -EFAULT;
++      } else {
++              error = 0;
++      }
++
++      kfree(kbuf);
++      return(error);
++}
++
++int
++dm_open_by_handle_rvp(
++      unsigned int    fd,
++      void            __user *hanp,
++      size_t          hlen,
++      int             flags,
++      int             *rvp)
++{
++      dm_handle_t     handle;
++      int             error;
++      short           td_type;
++      struct dentry   *dentry;
++      struct inode    *inodep;
++      int             new_fd;
++      struct file     *mfilp;
++      struct file     *filp;
++
++      if ((error = dm_copyin_handle(hanp, hlen, &handle)) != 0) {
++              return(error);
++      }
++
++      if ((inodep = dm_handle_to_ip(&handle, &td_type)) == NULL) {
++              return(-EBADF);
++      }
++      if ((td_type == DM_TDT_VFS) || (td_type == DM_TDT_OTH)) {
++              iput(inodep);
++              return(-EBADF);
++      }
++
++      if ((new_fd = get_unused_fd()) < 0) {
++              iput(inodep);
++              return(-EMFILE);
++      }
++
++      dentry = d_alloc_anon(inodep);
++      if (dentry == NULL) {
++              iput(inodep);
++              put_unused_fd(new_fd);
++              return(-ENOMEM);
++      }
++
++      mfilp = fget(fd);
++      if (!mfilp) {
++              dput(dentry);
++              put_unused_fd(new_fd);
++              return(-EBADF);
++      }
++
++      mntget(mfilp->f_vfsmnt);
++
++      /* Create file pointer */
++      filp = dentry_open(dentry, mfilp->f_vfsmnt, flags);
++      if (IS_ERR(filp)) {
++              put_unused_fd(new_fd);
++              fput(mfilp);
++              return PTR_ERR(filp);
++      }
++
++      if (td_type == DM_TDT_REG) {
++              struct filesystem_dmapi_operations *dmapiops;
++              dmapiops = dm_fsys_ops(inodep->i_sb);
++              if (dmapiops && dmapiops->get_invis_ops) {
++                      /* invisible operation should not change atime */
++                      filp->f_flags |= O_NOATIME;
++                      filp->f_op = dmapiops->get_invis_ops(inodep);
++              }
++      }
++      fd_install(new_fd, filp);
++      fput(mfilp);
++      *rvp = new_fd;
++      return 0;
++}
++
++
++#ifdef HAVE_DM_QUEUE_FLUSH
++/* Find the threads that have a reference to our filesystem and force
++   them to return with the specified errno.
++   We look for them in each dm_fsreg_t's fr_evt_dispq.
++*/
++
++int
++dm_release_disp_threads(
++      dm_fsid_t       *fsidp,
++      struct inode    *inode, /* may be null */
++      int             errno)
++{
++      unsigned long   lc;
++      dm_fsreg_t      *fsrp;
++      dm_tokevent_t   *tevp;
++      dm_tokdata_t    *tdp;
++      dm_eventq_t     *queue;
++      int             found_events = 0;
++
++      if ((fsrp = dm_find_fsreg_and_lock(fsidp, &lc)) == NULL){
++              return 0;
++      }
++
++      queue = &fsrp->fr_evt_dispq;
++      for (tevp = queue->eq_head; tevp; tevp = tevp->te_next) {
++              nested_spinlock(&tevp->te_lock);
++              if (inode) {
++                      for (tdp = tevp->te_tdp; tdp; tdp = tdp->td_next) {
++                              if( tdp->td_ip == inode ) {
++                                      tevp->te_flags |= DM_TEF_FLUSH;
++                                      tevp->te_reply = errno;
++                                      found_events = 1;
++                                      break;
++                              }
++                      }
++              }
++              else {
++                      tevp->te_flags |= DM_TEF_FLUSH;
++                      tevp->te_reply = errno;
++                      found_events = 1;
++              }
++              nested_spinunlock(&tevp->te_lock);
++      }
++
++      if (found_events && fsrp->fr_dispcnt)
++              sv_broadcast(&fsrp->fr_dispq);
++      mutex_spinunlock(&fsrp->fr_lock, lc);
++      return 0;
++}
++#endif /* HAVE_DM_QUEUE_FLUSH */
+Index: linux-2.6.26/fs/dmapi/dmapi_right.c
+===================================================================
+--- /dev/null
++++ linux-2.6.26/fs/dmapi/dmapi_right.c
+@@ -0,0 +1,1256 @@
++/*
++ * Copyright (c) 2000-2004 Silicon Graphics, Inc.  All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of version 2 of the GNU General Public License as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it would be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
++ *
++ * Further, this software is distributed without any warranty that it is
++ * free of the rightful claim of any third person regarding infringement
++ * or the like.        Any license provided herein, whether implied or
++ * otherwise, applies only to this software file.  Patent licenses, if
++ * any, provided herein do not apply to combinations of this program with
++ * other software, or any other product whatsoever.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write the Free Software Foundation, Inc., 59
++ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
++ *
++ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
++ * Mountain View, CA  94043, or:
++ *
++ * http://www.sgi.com
++ *
++ * For further information regarding this notice, see:
++ *
++ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
++ */
++#include <asm/uaccess.h>
++#include "dmapi.h"
++#include "dmapi_kern.h"
++#include "dmapi_private.h"
++
++
++#define DM_FG_STHREAD         0x001   /* keep other threads from using tdp */
++#define DM_FG_MUSTEXIST               0x002   /* handle must exist in the event */
++#define DM_FG_DONTADD         0x004   /* don't add handle if not in event */
++
++/* Get a handle of the form (void *, size_t) from user space and convert it to
++   a handle_t.        Do as much validation of the result as possible; any error
++   other than a bad address should return EBADF per the DMAPI spec.
++*/
++
++int
++dm_copyin_handle(
++      void            __user *hanp,   /* input,  handle data */
++      size_t          hlen,           /* input,  size of handle data */
++      dm_handle_t     *handlep)       /* output, copy of data */
++{
++      u_short         len;
++      dm_fid_t        *fidp;
++
++      fidp = (dm_fid_t*)&handlep->ha_fid;
++
++      if (hlen < sizeof(handlep->ha_fsid) || hlen > sizeof(*handlep))
++              return -EBADF;
++
++      if (copy_from_user(handlep, hanp, hlen))
++              return -EFAULT;
++
++      if (hlen < sizeof(*handlep))
++              memset((char *)handlep + hlen, 0, sizeof(*handlep) - hlen);
++
++      if (hlen == sizeof(handlep->ha_fsid))
++              return 0;       /* FS handle, nothing more to check */
++
++      len = hlen - sizeof(handlep->ha_fsid) - sizeof(fidp->dm_fid_len);
++
++      if ((fidp->dm_fid_len != len) || fidp->dm_fid_pad)
++              return -EBADF;
++      return 0;
++}
++
++/* Allocate and initialize a tevp structure.  Called from both application and
++   event threads.
++*/
++
++static dm_tokevent_t *
++dm_init_tevp(
++      int             ev_size,        /* size of event structure */
++      int             var_size)       /* size of variable-length data */
++{
++      dm_tokevent_t   *tevp;
++      int             msgsize;
++
++      /* Calculate the size of the event in bytes and allocate memory for it.
++         Zero all but the variable portion of the message, which will be
++         eventually overlaid by the caller with data.
++      */
++
++      msgsize = offsetof(dm_tokevent_t, te_event) + ev_size + var_size;
++      tevp = kmalloc(msgsize, GFP_KERNEL);
++      if (tevp == NULL) {
++              printk("%s/%d: kmalloc returned NULL\n", __FUNCTION__, __LINE__);
++              return NULL;
++      }
++      memset(tevp, 0, msgsize - var_size);
++
++      /* Now initialize all the non-zero fields. */
++
++      spinlock_init(&tevp->te_lock, "te_lock");
++      sv_init(&tevp->te_evt_queue, SV_DEFAULT, "te_evt_queue");
++      sv_init(&tevp->te_app_queue, SV_DEFAULT, "te_app_queue");
++      tevp->te_allocsize = msgsize;
++      tevp->te_msg.ev_type = DM_EVENT_INVALID;
++      tevp->te_flags = 0;
++
++      return(tevp);
++}
++
++
++/* Given the event type and the number of bytes of variable length data that
++   will follow the event, dm_evt_create_tevp() creates a dm_tokevent_t
++   structure to hold the event and initializes all the common event fields.
++
++   No locking is required for this routine because the caller is an event
++   thread, and is therefore the only thread that can see the event.
++*/
++
++dm_tokevent_t *
++dm_evt_create_tevp(
++      dm_eventtype_t  event,
++      int             variable_size,
++      void            **msgpp)
++{
++      dm_tokevent_t   *tevp;
++      int             evsize;
++
++      switch (event) {
++      case DM_EVENT_READ:
++      case DM_EVENT_WRITE:
++      case DM_EVENT_TRUNCATE:
++              evsize = sizeof(dm_data_event_t);
++              break;
++
++      case DM_EVENT_DESTROY:
++              evsize = sizeof(dm_destroy_event_t);
++              break;
++
++      case DM_EVENT_MOUNT:
++              evsize = sizeof(dm_mount_event_t);
++              break;
++
++      case DM_EVENT_PREUNMOUNT:
++      case DM_EVENT_UNMOUNT:
++      case DM_EVENT_NOSPACE:
++      case DM_EVENT_CREATE:
++      case DM_EVENT_REMOVE:
++      case DM_EVENT_RENAME:
++      case DM_EVENT_SYMLINK:
++      case DM_EVENT_LINK:
++      case DM_EVENT_POSTCREATE:
++      case DM_EVENT_POSTREMOVE:
++      case DM_EVENT_POSTRENAME:
++      case DM_EVENT_POSTSYMLINK:
++      case DM_EVENT_POSTLINK:
++      case DM_EVENT_ATTRIBUTE:
++      case DM_EVENT_DEBUT:            /* currently not supported */
++      case DM_EVENT_CLOSE:            /* currently not supported */
++              evsize = sizeof(dm_namesp_event_t);
++              break;
++
++      case DM_EVENT_CANCEL:           /* currently not supported */
++              evsize = sizeof(dm_cancel_event_t);
++              break;
++
++      case DM_EVENT_USER:
++              evsize = 0;
++              break;
++
++      default:
++              panic("dm_create_tevp: called with unknown event type %d\n",
++                      event);
++      }
++
++      /* Allocate and initialize an event structure of the correct size. */
++
++      tevp = dm_init_tevp(evsize, variable_size);
++      if (tevp == NULL)
++              return NULL;
++      tevp->te_evt_ref = 1;
++
++      /* Fields ev_token, ev_sequence, and _link are all filled in when the
++         event is queued onto a session.  Initialize all other fields here.
++      */
++
++      tevp->te_msg.ev_type = event;
++      tevp->te_msg.ev_data.vd_offset = offsetof(dm_tokevent_t, te_event) -
++              offsetof(dm_tokevent_t, te_msg);
++      tevp->te_msg.ev_data.vd_length = evsize + variable_size;
++
++      /* Give the caller a pointer to the event-specific structure. */
++
++      *msgpp = ((char *)&tevp->te_msg + tevp->te_msg.ev_data.vd_offset);
++      return(tevp);
++}
++
++
++/* Given a pointer to an event (tevp) and a pointer to a handle_t, look for a
++   tdp structure within the event which contains the handle_t.        Either verify
++   that the event contains the tdp, or optionally add the tdp to the
++   event.  Called only from application threads.
++
++   On entry, tevp->te_lock is held; it is dropped prior to return.
++*/
++
++static int
++dm_app_lookup_tdp(
++      dm_handle_t     *handlep,       /* the handle we are looking for */
++      dm_tokevent_t   *tevp,          /* the event to search for the handle */
++      unsigned long   *lcp,           /* address of active lock cookie */
++      short           types,          /* acceptable object types */
++      dm_right_t      right,          /* minimum right the object must have */
++      u_int           flags,
++      dm_tokdata_t    **tdpp)         /* if ! NULL, pointer to matching tdp */
++{
++      dm_fsys_vector_t *fsys_vector;
++      dm_tokdata_t    *tdp;
++      struct inode    *ip;
++      int             error;
++
++      /* Bump the tevp application reference counter so that the event
++         can't disappear in case we have to drop the lock for a while.
++      */
++
++      tevp->te_app_ref++;
++      *tdpp = NULL;           /* assume failure */
++
++      for (;;) {
++              /* Look for a matching tdp in the tevp. */
++
++              for (tdp = tevp->te_tdp; tdp; tdp = tdp->td_next) {
++                      if (DM_HANDLE_CMP(&tdp->td_handle, handlep) == 0)
++                              break;
++              }
++
++              /* If the tdp exists, but either we need single-thread access
++                 to the handle and can't get it, or some other thread already
++                 has single-thread access, then sleep until we can try again.
++              */
++
++              if (tdp != NULL && tdp->td_app_ref &&
++                  ((flags & DM_FG_STHREAD) ||
++                   (tdp->td_flags & DM_TDF_STHREAD))) {
++                      tevp->te_app_slp++;
++                      sv_wait(&tevp->te_app_queue, 1,
++                              &tevp->te_lock, *lcp);
++                      *lcp = mutex_spinlock(&tevp->te_lock);
++                      tevp->te_app_slp--;
++                      continue;
++              }
++
++              if (tdp != NULL &&
++                  (tdp->td_vcount > 0 || tdp->td_flags & DM_TDF_EVTREF)) {
++                      /* We have an existing tdp with a non-zero inode
++                         reference count.  If it's the wrong type, return
++                         an appropriate errno.
++                      */
++
++                      if (!(tdp->td_type & types)) {
++                              mutex_spinunlock(&tevp->te_lock, *lcp);
++                              dm_put_tevp(tevp, NULL); /* no destroy events */
++                              return(-EOPNOTSUPP);
++                      }
++
++                      /* If the current access right isn't high enough,
++                         complain.
++                      */
++
++                      if (tdp->td_right < right) {
++                              mutex_spinunlock(&tevp->te_lock, *lcp);
++                              dm_put_tevp(tevp, NULL); /* no destroy events */
++                              return(-EACCES);
++                      }
++
++                      /* The handle is acceptable.  Increment the tdp
++                         application and inode references and mark the tdp
++                         as single-threaded if necessary.
++                      */
++
++                      tdp->td_app_ref++;
++                      if (flags & DM_FG_STHREAD)
++                              tdp->td_flags |= DM_TDF_STHREAD;
++                      tdp->td_vcount++;
++
++                      fsys_vector = dm_fsys_vector(tdp->td_ip);
++                      (void)fsys_vector->obj_ref_hold(tdp->td_ip);
++
++                      mutex_spinunlock(&tevp->te_lock, *lcp);
++                      *tdpp = tdp;
++                      return(0);
++              }
++
++              /* If the tdp is not in the tevp or does not have an inode
++                 reference, check to make sure it is okay to add/update it.
++              */
++
++              if (flags & DM_FG_MUSTEXIST) {
++                      mutex_spinunlock(&tevp->te_lock, *lcp);
++                      dm_put_tevp(tevp, NULL);        /* no destroy events */
++                      return(-EACCES);                /* i.e. an insufficient right */
++              }
++              if (flags & DM_FG_DONTADD) {
++                      tevp->te_app_ref--;
++                      mutex_spinunlock(&tevp->te_lock, *lcp);
++                      return(0);
++              }
++
++              /* If a tdp structure doesn't yet exist, create one and link
++                 it into the tevp.  Drop the lock while we are doing this as
++                 zallocs can go to sleep.  Once we have the memory, make
++                 sure that another thread didn't simultaneously add the same
++                 handle to the same event.  If so, toss ours and start over.
++              */
++
++              if (tdp == NULL) {
++                      dm_tokdata_t    *tmp;
++
++                      mutex_spinunlock(&tevp->te_lock, *lcp);
++
++                      tdp = kmem_cache_alloc(dm_tokdata_cachep, GFP_KERNEL);
++                      if (tdp == NULL){
++                              printk("%s/%d: kmem_cache_alloc(dm_tokdata_cachep) returned NULL\n", __FUNCTION__, __LINE__);
++                              return(-ENOMEM);
++                      }
++                      memset(tdp, 0, sizeof(*tdp));
++
++                      *lcp = mutex_spinlock(&tevp->te_lock);
++
++                      for (tmp = tevp->te_tdp; tmp; tmp = tmp->td_next) {
++                              if (DM_HANDLE_CMP(&tmp->td_handle, handlep) == 0)
++                                      break;
++                      }
++                      if (tmp) {
++                              kmem_cache_free(dm_tokdata_cachep, tdp);
++                              continue;
++                      }
++
++                      tdp->td_next = tevp->te_tdp;
++                      tevp->te_tdp = tdp;
++                      tdp->td_tevp = tevp;
++                      tdp->td_handle = *handlep;
++              }
++
++              /* Temporarily single-thread access to the tdp so that other
++                 threads don't touch it while we are filling the rest of the
++                 fields in.
++              */
++
++              tdp->td_app_ref = 1;
++              tdp->td_flags |= DM_TDF_STHREAD;
++
++              /* Drop the spinlock while we access, validate, and obtain the
++                 proper rights to the object.  This can take a very long time
++                 if the inode is not in memory, if the filesystem is
++                 unmounting,  or if the request_right() call should block
++                 because some other tdp or kernel thread is holding a right.
++              */
++
++              mutex_spinunlock(&tevp->te_lock, *lcp);
++
++              if ((ip = dm_handle_to_ip(handlep, &tdp->td_type)) == NULL) {
++                      error = -EBADF;
++              } else {
++                      tdp->td_vcount = 1;
++                      tdp->td_ip = ip;
++
++                      /* The handle is usable.  Check that the type of the
++                         object matches one of the types that the caller
++                         will accept.
++                      */
++
++                      if (!(types & tdp->td_type)) {
++                              error = -EOPNOTSUPP;
++                      } else if (right > DM_RIGHT_NULL) {
++                              /* Attempt to get the rights required by the
++                                 caller.  If rights can't be obtained, return
++                                 an error.
++                              */
++
++                              fsys_vector = dm_fsys_vector(tdp->td_ip);
++                              error = fsys_vector->request_right(tdp->td_ip,
++                                      DM_RIGHT_NULL,
++                                      (tdp->td_type == DM_TDT_VFS ?
++                                      DM_FSYS_OBJ : 0),
++                                      DM_RR_WAIT, right);
++                              if (!error) {
++                                      tdp->td_right = right;
++                              }
++                      } else {
++                              error = 0;
++                      }
++              }
++              if (error != 0) {
++                      dm_put_tevp(tevp, tdp); /* destroy event risk, although tiny */
++                      return(error);
++              }
++
++              *lcp = mutex_spinlock(&tevp->te_lock);
++
++              /* Wake up any threads which may have seen our tdp while we
++                 were filling it in.
++              */
++
++              if (!(flags & DM_FG_STHREAD)) {
++                      tdp->td_flags &= ~DM_TDF_STHREAD;
++                      if (tevp->te_app_slp)
++                              sv_broadcast(&tevp->te_app_queue);
++              }
++
++              mutex_spinunlock(&tevp->te_lock, *lcp);
++              *tdpp = tdp;
++              return(0);
++      }
++}
++
++
++/* dm_app_get_tdp_by_token() is called whenever the application request
++   contains a session ID and contains a token other than DM_NO_TOKEN.
++   Most of the callers provide a right that is either DM_RIGHT_SHARED or
++   DM_RIGHT_EXCL, but a few of the callers such as dm_obj_ref_hold() may
++   specify a right of DM_RIGHT_NULL.
++*/
++
++static int
++dm_app_get_tdp_by_token(
++      dm_sessid_t     sid,            /* an existing session ID */
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token,          /* an existing token */
++      short           types,          /* acceptable object types */
++      dm_right_t      right,          /* minimum right the object must have */
++      u_int           flags,
++      dm_tokdata_t    **tdpp)
++{
++      dm_tokevent_t   *tevp;
++      dm_handle_t     handle;
++      int             error;
++      unsigned long   lc;             /* lock cookie */
++
++      if (right < DM_RIGHT_NULL || right > DM_RIGHT_EXCL)
++              return(-EINVAL);
++
++      if ((error = dm_copyin_handle(hanp, hlen, &handle)) != 0)
++              return(error);
++
++      /* Find and lock the event which corresponds to the specified
++         session/token pair.
++      */
++
++      if ((error = dm_find_msg_and_lock(sid, token, &tevp, &lc)) != 0)
++              return(error);
++
++      return(dm_app_lookup_tdp(&handle, tevp, &lc, types,
++              right, flags, tdpp));
++}
++
++
++/* Function dm_app_get_tdp() must ONLY be called from routines associated with
++   application calls, e.g. dm_read_invis, dm_set_disp, etc.  It must not be
++   called by a thread responsible for generating an event such as
++   dm_send_data_event()!
++
++   dm_app_get_tdp() is the interface used by all application calls other than
++   dm_get_events, dm_respond_event, dm_get_config, dm_get_config_events, and by
++   the dm_obj_ref_* and dm_*_right families of requests.
++
++   dm_app_get_tdp() converts a sid/hanp/hlen/token quad into a tdp pointer,
++   increments the number of active application threads in the event, and
++   increments the number of active application threads using the tdp.  The
++   'right' parameter must be either DM_RIGHT_SHARED or DM_RIGHT_EXCL.  The
++   token may either be DM_NO_TOKEN, or can be a token received in a synchronous
++   event.
++*/
++
++int
++dm_app_get_tdp(
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token,
++      short           types,
++      dm_right_t      right,          /* minimum right */
++      dm_tokdata_t    **tdpp)
++{
++      dm_session_t    *s;
++      dm_handle_t     handle;
++      dm_tokevent_t   *tevp;
++      int             error;
++      unsigned long   lc;             /* lock cookie */
++
++      ASSERT(right >= DM_RIGHT_SHARED);
++
++      /* If a token other than DM_NO_TOKEN is specified, find the event on
++         this session which owns the token and increment its reference count.
++      */
++
++      if (token != DM_NO_TOKEN) {     /* look up existing tokevent struct */
++              return(dm_app_get_tdp_by_token(sid, hanp, hlen, token, types,
++                      right, DM_FG_MUSTEXIST, tdpp));
++      }
++
++      /* The token is DM_NO_TOKEN.  In this case we only want to verify that
++         the session ID is valid, and do not need to continue holding the
++         session lock after we know that to be true.
++      */
++
++      if ((error = dm_copyin_handle(hanp, hlen, &handle)) != 0)
++              return(error);
++
++      if ((error = dm_find_session_and_lock(sid, &s, &lc)) != 0)
++              return(error);
++      mutex_spinunlock(&s->sn_qlock, lc);
++
++      /* When DM_NO_TOKEN is used, we simply block until we can obtain the
++         right that we want (since the tevp contains no tdp structures).
++         The blocking when we eventually support it will occur within
++         fsys_vector->request_right().
++      */
++
++      tevp = dm_init_tevp(0, 0);
++      lc = mutex_spinlock(&tevp->te_lock);
++
++      return(dm_app_lookup_tdp(&handle, tevp, &lc, types, right, 0, tdpp));
++}
++
++
++/* dm_get_config_tdp() is only called by dm_get_config() and
++   dm_get_config_events(), which neither have a session ID nor a token.
++   Both of these calls are supposed to work even if the filesystem is in the
++   process of being mounted, as long as the caller only uses handles within
++   the mount event.
++*/
++
++int
++dm_get_config_tdp(
++      void            __user *hanp,
++      size_t          hlen,
++      dm_tokdata_t    **tdpp)
++{
++      dm_handle_t     handle;
++      dm_tokevent_t   *tevp;
++      int             error;
++      unsigned long   lc;             /* lock cookie */
++
++      if ((error = dm_copyin_handle(hanp, hlen, &handle)) != 0)
++              return(error);
++
++      tevp = dm_init_tevp(0, 0);
++      lc = mutex_spinlock(&tevp->te_lock);
++
++      /* Try to use the handle provided by the caller and assume DM_NO_TOKEN.
++         This will fail if the filesystem is in the process of being mounted.
++      */
++
++      error = dm_app_lookup_tdp(&handle, tevp, &lc, DM_TDT_ANY,
++              DM_RIGHT_NULL, 0, tdpp);
++
++      if (!error) {
++              return(0);
++      }
++
++      /* Perhaps the filesystem is still mounting, in which case we need to
++         see if this is one of the handles in the DM_EVENT_MOUNT tevp.
++      */
++
++      if ((tevp = dm_find_mount_tevp_and_lock(&handle.ha_fsid, &lc)) == NULL)
++              return(-EBADF);
++
++      return(dm_app_lookup_tdp(&handle, tevp, &lc, DM_TDT_ANY,
++              DM_RIGHT_NULL, DM_FG_MUSTEXIST, tdpp));
++}
++
++
++/* dm_put_tdp() is called to release any right held on the inode, and to
++   VN_RELE() all references held on the inode.        It is the caller's
++   responsibility to ensure that no other application threads are using the
++   tdp, and if necessary to unlink the tdp from the tevp before calling
++   this routine and to free the tdp afterwards.
++*/
++
++static void
++dm_put_tdp(
++      dm_tokdata_t    *tdp)
++{
++      ASSERT(tdp->td_app_ref <= 1);
++
++      /* If the application thread is holding a right, or if the event
++         thread had a right but it has disappeared because of a dm_pending
++         or Cntl-C, then we need to release it here.
++      */
++
++      if (tdp->td_right != DM_RIGHT_NULL) {
++              dm_fsys_vector_t *fsys_vector;
++
++              fsys_vector = dm_fsys_vector(tdp->td_ip);
++              (void)fsys_vector->release_right(tdp->td_ip, tdp->td_right,
++                      (tdp->td_type == DM_TDT_VFS ? DM_FSYS_OBJ : 0));
++              tdp->td_right = DM_RIGHT_NULL;
++      }
++
++      /* Given that we wouldn't be here if there was still an event thread,
++         this VN_RELE loop has the potential of generating a DM_EVENT_DESTROY
++         event if some other thread has unlinked the file.
++      */
++
++      while (tdp->td_vcount > 0) {
++              iput(tdp->td_ip);
++              tdp->td_vcount--;
++      }
++
++      tdp->td_flags &= ~(DM_TDF_HOLD|DM_TDF_RIGHT);
++      tdp->td_ip = NULL;
++}
++
++
++/* Function dm_put_tevp() must ONLY be called from routines associated with
++   application threads, e.g. dm_read_invis, dm_get_events, etc.        It must not be
++   called by a thread responsible for generating an event, such as
++   dm_send_data_event.
++
++   PLEASE NOTE: It is possible for this routine to generate DM_EVENT_DESTROY
++   events, because its calls to dm_put_tdp drop inode references, and another
++   thread may have already unlinked a file whose inode we are de-referencing.
++   This sets the stage for various types of deadlock if the thread calling
++   dm_put_tevp is the same thread that calls dm_respond_event!        In particular,
++   the dm_sent_destroy_event routine needs to obtain the dm_reg_lock,
++   dm_session_lock, and sn_qlock in order to queue the destroy event.  No
++   caller of dm_put_tevp can hold any of these locks!
++
++   Other possible deadlocks are that dm_send_destroy_event could block waiting
++   for a thread to register for the event using        dm_set_disp() and/or
++   dm_set_return_on_destroy, or it could block because the session's sn_newq
++   is at the dm_max_queued_msgs event limit.  The only safe solution
++   (unimplemented) is to have a separate kernel thread for each filesystem
++   whose only job is to do the inode-dereferencing.  That way dm_respond_event
++   will not block, so the application can keep calling dm_get_events to read
++   events even if the filesystem thread should block.  (If the filesystem
++   thread blocks, so will all subsequent destroy events for the same
++   filesystem.)
++*/
++
++void
++dm_put_tevp(
++      dm_tokevent_t   *tevp,
++      dm_tokdata_t    *tdp)
++{
++      int             free_tdp = 0;
++      unsigned long   lc;             /* lock cookie */
++
++      lc = mutex_spinlock(&tevp->te_lock);
++
++      if (tdp != NULL) {
++              if (tdp->td_vcount > 1 || (tdp->td_flags & DM_TDF_EVTREF)) {
++                      ASSERT(tdp->td_app_ref > 0);
++
++                      iput(tdp->td_ip);
++                      tdp->td_vcount--;
++              } else {
++                      ASSERT(tdp->td_app_ref == 1);
++
++                      /* The inode reference count is either already at
++                         zero (e.g. a failed dm_handle_to_ip() call in
++                         dm_app_lookup_tdp()) or is going to zero.  We can't
++                         hold the lock while we decrement the count because
++                         we could potentially end up being busy for a long
++                         time in VOP_INACTIVATE.  Use single-threading to
++                         lock others out while we clean house.
++                      */
++
++                      tdp->td_flags |= DM_TDF_STHREAD;
++
++                      /* WARNING - A destroy event is possible here if we are
++                         giving up the last reference on an inode which has
++                         been previously unlinked by some other thread!
++                      */
++
++                      mutex_spinunlock(&tevp->te_lock, lc);
++                      dm_put_tdp(tdp);
++                      lc = mutex_spinlock(&tevp->te_lock);
++
++                      /* If this tdp is not one of the original tdps in the
++                         event, then remove it from the tevp.
++                      */
++
++                      if (!(tdp->td_flags & DM_TDF_ORIG)) {
++                              dm_tokdata_t    **tdpp = &tevp->te_tdp;
++
++                              while (*tdpp && *tdpp != tdp) {
++                                      tdpp = &(*tdpp)->td_next;
++                              }
++                              if (*tdpp == NULL) {
++                                      panic("dm_remove_tdp_from_tevp: tdp "
++                                              "%p not in tevp %p\n", tdp,
++                                              tevp);
++                              }
++                              *tdpp = tdp->td_next;
++                              free_tdp++;
++                      }
++              }
++
++              /* If this is the last app thread actively using the tdp, clear
++                 any single-threading and wake up any other app threads who
++                 might be waiting to use this tdp, single-threaded or
++                 otherwise.
++              */
++
++              if (--tdp->td_app_ref == 0) {
++                      if (tdp->td_flags & DM_TDF_STHREAD) {
++                              tdp->td_flags &= ~DM_TDF_STHREAD;
++                              if (tevp->te_app_slp)
++                                      sv_broadcast(&tevp->te_app_queue);
++                      }
++              }
++
++              if (free_tdp) {
++                      kmem_cache_free(dm_tokdata_cachep, tdp);
++              }
++      }
++
++      /* If other application threads are using this token/event, they will
++         do the cleanup.
++      */
++
++      if (--tevp->te_app_ref > 0) {
++              mutex_spinunlock(&tevp->te_lock, lc);
++              return;
++      }
++
++      /* If event generation threads are waiting for this thread to go away,
++         wake them up and let them do the cleanup.
++      */
++
++      if (tevp->te_evt_ref > 0) {
++              sv_broadcast(&tevp->te_evt_queue);
++              mutex_spinunlock(&tevp->te_lock, lc);
++              return;
++      }
++
++      /* This thread is the last active thread using the token/event.  No
++         lock can be held while we disassemble the tevp because we could
++         potentially end up being busy for a long time in VOP_INACTIVATE.
++      */
++
++      mutex_spinunlock(&tevp->te_lock, lc);
++
++      /* WARNING - One or more destroy events are possible here if we are
++         giving up references on inodes which have been previously unlinked
++         by other kernel threads!
++      */
++
++      while ((tdp = tevp->te_tdp) != NULL) {
++              tevp->te_tdp = tdp->td_next;
++              dm_put_tdp(tdp);
++              kmem_cache_free(dm_tokdata_cachep, tdp);
++      }
++      spinlock_destroy(&tevp->te_lock);
++      sv_destroy(&tevp->te_evt_queue);
++      sv_destroy(&tevp->te_app_queue);
++      kfree(tevp);
++}
++
++
++/* No caller of dm_app_put_tevp can hold either of the locks dm_reg_lock,
++   dm_session_lock, or any sn_qlock!  (See dm_put_tevp for details.)
++*/
++
++void
++dm_app_put_tdp(
++      dm_tokdata_t    *tdp)
++{
++      dm_put_tevp(tdp->td_tevp, tdp);
++}
++
++
++/* dm_change_right is only called if the event thread is the one doing the
++   cleanup on a completed event.  It looks at the current rights of a tdp
++   and compares that with the rights it had on the tdp when the event was
++   created.  If different, it reaquires the original rights, then transfers
++   the rights back to being thread-based.
++*/
++
++static void
++dm_change_right(
++      dm_tokdata_t    *tdp)
++{
++#ifdef HAVE_DMAPI_RIGHTS
++      dm_fsys_vector_t *fsys_vector;
++      int             error;
++      u_int           type;
++#endif
++
++      /* If the event doesn't have an inode reference, if the original right
++         was DM_RIGHT_NULL, or if the rights were never switched from being
++         thread-based to tdp-based, then there is nothing to do.
++      */
++
++      if (!(tdp->td_flags & DM_TDF_EVTREF))
++              return;
++
++      if (tdp->td_orig_right == DM_RIGHT_NULL)
++              return;
++
++      /* DEBUG - Need a check here for event-based rights. */
++
++#ifdef HAVE_DMAPI_RIGHTS
++      /* The "rights" vectors are stubs now anyway.  When they are
++       * implemented then bhv locking will have to be sorted out.
++       */
++
++      /* If the current right is not the same as it was when the event was
++         created, first get back the original right.
++      */
++
++      if (tdp->td_right != tdp->td_orig_right) {
++              fsys_vector = dm_fsys_vector(tdp->td_ip);
++              type = (tdp->td_type == DM_TDT_VFS ? DM_FSYS_OBJ : 0);
++
++              switch (tdp->td_orig_right) {
++              case DM_RIGHT_SHARED:
++                      if (tdp->td_right == DM_RIGHT_EXCL) {
++                              error = fsys_vector->downgrade_right(
++                                      tdp->td_ip, tdp->td_right, type);
++                              if (!error)
++                                      break;
++                              (void)fsys_vector->release_right(tdp->td_ip,
++                                      tdp->td_right, type);
++                      }
++                      (void)fsys_vector->request_right(tdp->td_ip,
++                              tdp->td_right, type, DM_RR_WAIT,
++                              tdp->td_orig_right);
++                      break;
++
++              case DM_RIGHT_EXCL:
++                      if (tdp->td_right == DM_RIGHT_SHARED) {
++                              error = fsys_vector->upgrade_right(tdp->td_ip,
++                                      tdp->td_right, type);
++                              if (!error)
++                                      break;
++                              (void)fsys_vector->release_right(tdp->td_ip,
++                                      tdp->td_right, type);
++                      }
++                      (void)fsys_vector->request_right(tdp->td_ip,
++                              tdp->td_right, type, DM_RR_WAIT,
++                              tdp->td_orig_right);
++                      break;
++              case DM_RIGHT_NULL:
++                      break;
++              }
++      }
++#endif
++
++      /* We now have back the same level of rights as we had when the event
++         was generated.  Now transfer the rights from being tdp-based back
++         to thread-based.
++      */
++
++      /* DEBUG - Add a call here to transfer rights back to thread-based. */
++
++      /* Finally, update the tdp so that we don't mess with the rights when
++         we eventually call dm_put_tdp.
++      */
++
++      tdp->td_right = DM_RIGHT_NULL;
++}
++
++
++/* This routine is only called by event threads.  The calls to dm_put_tdp
++   are not a deadlock risk here because this is an event thread, and it is
++   okay for such a thread to block on an induced destroy event.        Okay, maybe
++   there is a slight risk; say that the event contains three inodes all of
++   which have DM_RIGHT_EXCL, and say that we are at the dm_max_queued_msgs
++   limit, and that the first inode is already unlinked.        In that case the
++   destroy event will block waiting to be queued, and the application thread
++   could happen to reference one of the other locked inodes.  Deadlock.
++*/
++
++void
++dm_evt_rele_tevp(
++      dm_tokevent_t   *tevp,
++      int             droprights)     /* non-zero, evt thread loses rights */
++{
++      dm_tokdata_t    *tdp;
++      unsigned long   lc;             /* lock cookie */
++
++      lc = mutex_spinlock(&tevp->te_lock);
++
++      /* If we are here without DM_TEF_FINAL set and with at least one
++         application reference still remaining, then one of several
++         possibilities is true:
++         1. This is an asynchronous event which has been queued but has not
++            yet been delivered, or which is in the process of being delivered.
++         2. This is an unmount event (pseudo-asynchronous) yet to be
++            delivered or in the process of being delivered.
++         3. This event had DM_FLAGS_NDELAY specified, and the application
++            has sent a dm_pending() reply for the event.
++         4. This is a DM_EVENT_READ, DM_EVENT_WRITE, or DM_EVENT_TRUNCATE
++            event and the user typed a Cntl-C.
++         In all of these cases, the correct behavior is to leave the
++         responsibility of releasing any rights to the application threads
++         when they are done.
++      */
++
++      if (tevp->te_app_ref > 0 && !(tevp->te_flags & DM_TEF_FINAL)) {
++              tevp->te_evt_ref--;
++              for (tdp = tevp->te_tdp; tdp; tdp = tdp->td_next) {
++                      if (tdp->td_flags & DM_TDF_EVTREF) {
++                              tdp->td_flags &= ~DM_TDF_EVTREF;
++                              if (tdp->td_vcount == 0) {
++                                      tdp->td_ip = NULL;
++                              }
++                      }
++              }
++              mutex_spinunlock(&tevp->te_lock, lc);
++              return;         /* not the last thread */
++      }
++
++      /* If the application reference count is non-zero here, that can only
++         mean that dm_respond_event() has been called, but the application
++         still has one or more threads in the kernel that haven't let go of
++         the tevp.  In these cases, the event thread must wait until all
++         application threads have given up their references, and their
++         rights to handles within the event.
++      */
++
++      while (tevp->te_app_ref) {
++              sv_wait(&tevp->te_evt_queue, 1, &tevp->te_lock, lc);
++              lc = mutex_spinlock(&tevp->te_lock);
++      }
++
++      /* This thread is the last active thread using the token/event.  Reset
++         the rights of any inode that was part of the original event back
++         to their initial values before returning to the filesystem.  The
++         exception is if the event failed (droprights is non-zero), in which
++         case we chose to return to the filesystem with all rights released.
++         Release the rights on any inode that was not part of the original
++         event.  Give up all remaining application inode references
++         regardless of whether or not the inode was part of the original
++         event.
++      */
++
++      mutex_spinunlock(&tevp->te_lock, lc);
++
++      while ((tdp = tevp->te_tdp) != NULL) {
++              tevp->te_tdp = tdp->td_next;
++              if ((tdp->td_flags & DM_TDF_ORIG) &&
++                  (tdp->td_flags & DM_TDF_EVTREF) &&
++                  (!droprights)) {
++                      dm_change_right(tdp);
++              }
++              dm_put_tdp(tdp);
++              kmem_cache_free(dm_tokdata_cachep, tdp);
++      }
++      spinlock_destroy(&tevp->te_lock);
++      sv_destroy(&tevp->te_evt_queue);
++      sv_destroy(&tevp->te_app_queue);
++      kfree(tevp);
++}
++
++
++/* dm_obj_ref_hold() is just a fancy way to get an inode reference on an object
++   to hold it in kernel memory.
++*/
++
++int
++dm_obj_ref_hold(
++      dm_sessid_t     sid,
++      dm_token_t      token,
++      void            __user *hanp,
++      size_t          hlen)
++{
++      dm_fsys_vector_t *fsys_vector;
++      dm_tokdata_t    *tdp;
++      int             error;
++
++      error = dm_app_get_tdp_by_token(sid, hanp, hlen, token, DM_TDT_VNO,
++              DM_RIGHT_NULL, DM_FG_STHREAD, &tdp);
++
++      /* The tdp is single-threaded, so no mutex lock needed for update. */
++
++      if (error == 0) {
++              if (tdp->td_flags & DM_TDF_HOLD) {      /* if already held */
++                      error = -EBUSY;
++              } else {
++                      tdp->td_flags |= DM_TDF_HOLD;
++                      tdp->td_vcount++;
++
++                      fsys_vector = dm_fsys_vector(tdp->td_ip);
++                      (void)fsys_vector->obj_ref_hold(tdp->td_ip);
++              }
++              dm_app_put_tdp(tdp);
++      }
++      return(error);
++}
++
++
++int
++dm_obj_ref_rele(
++      dm_sessid_t     sid,
++      dm_token_t      token,
++      void            __user *hanp,
++      size_t          hlen)
++{
++      dm_tokdata_t    *tdp;
++      int             error;
++
++      error = dm_app_get_tdp_by_token(sid, hanp, hlen, token, DM_TDT_VNO,
++              DM_RIGHT_NULL, DM_FG_MUSTEXIST|DM_FG_STHREAD, &tdp);
++
++      /* The tdp is single-threaded, so no mutex lock needed for update. */
++
++      if (error == 0) {
++              if (!(tdp->td_flags & DM_TDF_HOLD)) {   /* if not held */
++                      error = -EACCES; /* use the DM_FG_MUSTEXIST errno */
++              } else {
++                      tdp->td_flags &= ~DM_TDF_HOLD;
++                      iput(tdp->td_ip);
++                      tdp->td_vcount--;
++              }
++              dm_app_put_tdp(tdp);
++      }
++      return(error);
++}
++
++
++int
++dm_obj_ref_query_rvp(
++      dm_sessid_t     sid,
++      dm_token_t      token,
++      void            __user *hanp,
++      size_t          hlen,
++      int             *rvp)
++{
++      dm_tokdata_t    *tdp;
++      int             error;
++
++      error = dm_app_get_tdp_by_token(sid, hanp, hlen, token, DM_TDT_VNO,
++              DM_RIGHT_NULL, DM_FG_DONTADD|DM_FG_STHREAD, &tdp);
++      if (error != 0)
++              return(error);
++
++      /* If the request is valid but the handle just isn't present in the
++         event or the hold flag isn't set, return zero, else return one.
++      */
++
++      if (tdp) {
++              if (tdp->td_flags & DM_TDF_HOLD) {      /* if held */
++                      *rvp = 1;
++              } else {
++                      *rvp = 0;
++              }
++              dm_app_put_tdp(tdp);
++      } else {
++              *rvp = 0;
++      }
++      return(0);
++}
++
++
++int
++dm_downgrade_right(
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token)
++{
++      dm_fsys_vector_t *fsys_vector;
++      dm_tokdata_t    *tdp;
++      int             error;
++
++      error = dm_app_get_tdp_by_token(sid, hanp, hlen, token, DM_TDT_ANY,
++              DM_RIGHT_EXCL, DM_FG_MUSTEXIST|DM_FG_STHREAD, &tdp);
++      if (error != 0)
++              return(error);
++
++      /* Attempt the downgrade.  Filesystems which support rights but not
++         the downgrading of rights will return ENOSYS.
++      */
++
++      fsys_vector = dm_fsys_vector(tdp->td_ip);
++      error = fsys_vector->downgrade_right(tdp->td_ip, tdp->td_right,
++              (tdp->td_type == DM_TDT_VFS ? DM_FSYS_OBJ : 0));
++
++      /* The tdp is single-threaded, so no mutex lock needed for update. */
++
++      if (error == 0)
++              tdp->td_right = DM_RIGHT_SHARED;
++
++      dm_app_put_tdp(tdp);
++      return(error);
++}
++
++
++int
++dm_query_right(
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token,
++      dm_right_t      __user *rightp)
++{
++      dm_tokdata_t    *tdp;
++      dm_right_t      right;
++      int             error;
++
++      error = dm_app_get_tdp_by_token(sid, hanp, hlen, token, DM_TDT_ANY,
++              DM_RIGHT_NULL, DM_FG_DONTADD|DM_FG_STHREAD, &tdp);
++      if (error != 0)
++              return(error);
++
++      /* Get the current right and copy it to the caller.  The tdp is
++         single-threaded, so no mutex lock is needed.  If the tdp is not in
++         the event we are supposed to return DM_RIGHT_NULL in order to be
++         compatible with Veritas.
++      */
++
++      if (tdp) {
++              right = tdp->td_right;
++              dm_app_put_tdp(tdp);
++      } else {
++              right = DM_RIGHT_NULL;
++      }
++      if (copy_to_user(rightp, &right, sizeof(right)))
++              return(-EFAULT);
++      return(0);
++}
++
++
++int
++dm_release_right(
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token)
++{
++      dm_fsys_vector_t *fsys_vector;
++      dm_tokdata_t    *tdp;
++      int             error;
++
++      error = dm_app_get_tdp_by_token(sid, hanp, hlen, token, DM_TDT_ANY,
++              DM_RIGHT_SHARED, DM_FG_MUSTEXIST|DM_FG_STHREAD, &tdp);
++      if (error != 0)
++              return(error);
++
++      fsys_vector = dm_fsys_vector(tdp->td_ip);
++      error = fsys_vector->release_right(tdp->td_ip, tdp->td_right,
++              (tdp->td_type == DM_TDT_VFS ? DM_FSYS_OBJ : 0));
++
++      /* The tdp is single-threaded, so no mutex lock needed for update. */
++
++      if (error == 0) {
++              tdp->td_right = DM_RIGHT_NULL;
++              if (tdp->td_flags & DM_TDF_RIGHT) {
++                      tdp->td_flags &= ~DM_TDF_RIGHT;
++                      iput(tdp->td_ip);
++                      tdp->td_vcount--;
++              }
++      }
++
++      dm_app_put_tdp(tdp);
++      return(error);
++}
++
++
++int
++dm_request_right(
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token,
++      u_int           flags,
++      dm_right_t      right)
++{
++      dm_fsys_vector_t *fsys_vector;
++      dm_tokdata_t    *tdp;
++      int             error;
++
++      error = dm_app_get_tdp_by_token(sid, hanp, hlen, token, DM_TDT_ANY,
++              DM_RIGHT_NULL, DM_FG_STHREAD, &tdp);
++      if (error != 0)
++              return(error);
++
++      fsys_vector = dm_fsys_vector(tdp->td_ip);
++      error = fsys_vector->request_right(tdp->td_ip, tdp->td_right,
++              (tdp->td_type == DM_TDT_VFS ? DM_FSYS_OBJ : 0), flags, right);
++
++      /* The tdp is single-threaded, so no mutex lock is needed for update.
++
++         If this is the first dm_request_right call for this inode, then we
++         need to bump the inode reference count for two reasons.  First of
++         all, it is supposed to be impossible for the file to disappear or
++         for the filesystem to be unmounted while a right is held on a file;
++         bumping the file's inode reference count ensures this.  Second, if
++         rights are ever actually implemented, it will most likely be done
++         without changes to the on-disk inode, which means that we can't let
++         the inode become unreferenced while a right on it is held.
++      */
++
++      if (error == 0) {
++              if (!(tdp->td_flags & DM_TDF_RIGHT)) {  /* if first call */
++                      tdp->td_flags |= DM_TDF_RIGHT;
++                      tdp->td_vcount++;
++                      (void)fsys_vector->obj_ref_hold(tdp->td_ip);
++              }
++              tdp->td_right = right;
++      }
++
++      dm_app_put_tdp(tdp);
++      return(error);
++}
++
++
++int
++dm_upgrade_right(
++      dm_sessid_t     sid,
++      void            __user *hanp,
++      size_t          hlen,
++      dm_token_t      token)
++{
++      dm_fsys_vector_t *fsys_vector;
++      dm_tokdata_t    *tdp;
++      int             error;
++
++      error = dm_app_get_tdp_by_token(sid, hanp, hlen, token, DM_TDT_ANY,
++              DM_RIGHT_SHARED, DM_FG_MUSTEXIST|DM_FG_STHREAD, &tdp);
++      if (error != 0)
++              return(error);
++
++      /* If the object already has the DM_RIGHT_EXCL right, no need to
++         attempt an upgrade.
++      */
++
++      if (tdp->td_right == DM_RIGHT_EXCL) {
++              dm_app_put_tdp(tdp);
++              return(0);
++      }
++
++      /* Attempt the upgrade.  Filesystems which support rights but not
++         the upgrading of rights will return ENOSYS.
++      */
++
++      fsys_vector = dm_fsys_vector(tdp->td_ip);
++      error = fsys_vector->upgrade_right(tdp->td_ip, tdp->td_right,
++              (tdp->td_type == DM_TDT_VFS ? DM_FSYS_OBJ : 0));
++
++      /* The tdp is single-threaded, so no mutex lock needed for update. */
++
++      if (error == 0)
++              tdp->td_right = DM_RIGHT_EXCL;
++
++      dm_app_put_tdp(tdp);
++      return(error);
++}
+Index: linux-2.6.26/fs/dmapi/dmapi_session.c
+===================================================================
+--- /dev/null
++++ linux-2.6.26/fs/dmapi/dmapi_session.c
+@@ -0,0 +1,1825 @@
++/*
++ * Copyright (c) 2000-2005 Silicon Graphics, Inc.  All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of version 2 of the GNU General Public License as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it would be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
++ *
++ * Further, this software is distributed without any warranty that it is
++ * free of the rightful claim of any third person regarding infringement
++ * or the like.        Any license provided herein, whether implied or
++ * otherwise, applies only to this software file.  Patent licenses, if
++ * any, provided herein do not apply to combinations of this program with
++ * other software, or any other product whatsoever.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write the Free Software Foundation, Inc., 59
++ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
++ *
++ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
++ * Mountain View, CA  94043, or:
++ *
++ * http://www.sgi.com
++ *
++ * For further information regarding this notice, see:
++ *
++ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
++ */
++
++#include <linux/init.h>
++#include <linux/proc_fs.h>
++#include <asm/uaccess.h>
++#ifdef CONFIG_PROC_FS
++#include <linux/module.h>
++#endif
++#include "dmapi.h"
++#include "dmapi_kern.h"
++#include "dmapi_private.h"
++
++dm_session_t  *dm_sessions = NULL;    /* head of session list */
++u_int         dm_sessions_active = 0; /* # sessions currently active */
++dm_sessid_t   dm_next_sessid = 1;     /* next session ID to use */
++lock_t                dm_session_lock = SPIN_LOCK_UNLOCKED;/* lock for session list */
++
++dm_token_t    dm_next_token = 1;      /* next token ID to use */
++dm_sequence_t dm_next_sequence = 1;   /* next sequence number to use */
++lock_t                dm_token_lock = SPIN_LOCK_UNLOCKED;/* dm_next_token/dm_next_sequence lock */
++
++int   dm_max_queued_msgs = 2048;      /* max # undelivered msgs/session */
++
++int   dm_hash_buckets = 1009;         /* prime -- number of buckets */
++
++#define DM_SHASH(sess,inodenum)       \
++              ((sess)->sn_sesshash + do_mod((inodenum), dm_hash_buckets))
++
++
++#ifdef CONFIG_PROC_FS
++static int
++sessions_read_pfs(char *buffer, char **start, off_t offset,
++               int count, int *eof, void *data)
++{
++      int len;
++      dm_session_t    *sessp = (dm_session_t*)data;
++
++#define CHKFULL if(len >= count) break;
++#define ADDBUF(a,b)   len += sprintf(buffer + len, a, b); CHKFULL;
++
++      len=0;
++      while(1){
++              ADDBUF("sessp=0x%p\n", sessp);
++              ADDBUF("sn_next=0x%p\n", sessp->sn_next);
++              ADDBUF("sn_sessid=%d\n", sessp->sn_sessid);
++              ADDBUF("sn_flags=%x\n", sessp->sn_flags);
++              ADDBUF("sn_qlock=%c\n", '?');
++              ADDBUF("sn_readerq=%c\n", '?');
++              ADDBUF("sn_writerq=%c\n", '?');
++              ADDBUF("sn_readercnt=%u\n", sessp->sn_readercnt);
++              ADDBUF("sn_writercnt=%u\n", sessp->sn_writercnt);
++
++              ADDBUF("sn_newq.eq_head=0x%p\n", sessp->sn_newq.eq_head);
++              ADDBUF("sn_newq.eq_tail=0x%p\n", sessp->sn_newq.eq_tail);
++              ADDBUF("sn_newq.eq_count=%d\n", sessp->sn_newq.eq_count);
++
++              ADDBUF("sn_delq.eq_head=0x%p\n", sessp->sn_delq.eq_head);
++              ADDBUF("sn_delq.eq_tail=0x%p\n", sessp->sn_delq.eq_tail);
++              ADDBUF("sn_delq.eq_count=%d\n", sessp->sn_delq.eq_count);
++
++              ADDBUF("sn_evt_writerq.eq_head=0x%p\n", sessp->sn_evt_writerq.eq_head);
++              ADDBUF("sn_evt_writerq.eq_tail=0x%p\n", sessp->sn_evt_writerq.eq_tail);
++              ADDBUF("sn_evt_writerq.eq_count=%d\n", sessp->sn_evt_writerq.eq_count);
++
++              ADDBUF("sn_info=\"%s\"\n", sessp->sn_info);
++
++              break;
++      }
++
++      if (offset >= len) {
++              *start = buffer;
++              *eof = 1;
++              return 0;
++      }
++      *start = buffer + offset;
++      if ((len -= offset) > count)
++              return count;
++      *eof = 1;
++
++      return len;
++}
++#endif
++
++
++/* Link a session to the end of the session list.  New sessions are always
++   added at the end of the list so that dm_enqueue_mount_event() doesn't
++   miss a session.  The caller must have obtained dm_session_lock before
++   calling this routine.
++*/
++
++static void
++link_session(
++      dm_session_t    *s)
++{
++      dm_session_t    *tmp;
++
++      if ((tmp = dm_sessions) == NULL) {
++              dm_sessions = s;
++      } else {
++              while (tmp->sn_next != NULL)
++                      tmp = tmp->sn_next;
++              tmp->sn_next = s;
++      }
++      s->sn_next = NULL;
++      dm_sessions_active++;
++}
++
++
++/* Remove a session from the session list.  The caller must have obtained
++   dm_session_lock before calling this routine.        unlink_session() should only
++   be used in situations where the session is known to be on the dm_sessions
++   list; otherwise it panics.
++*/
++
++static void
++unlink_session(
++      dm_session_t    *s)
++{
++      dm_session_t    *tmp;
++
++      if (dm_sessions == s) {
++              dm_sessions = dm_sessions->sn_next;
++      } else {
++              for (tmp = dm_sessions; tmp; tmp = tmp->sn_next) {
++                      if (tmp->sn_next == s)
++                              break;
++              }
++              if (tmp == NULL) {
++                      panic("unlink_session: corrupt DMAPI session list, "
++                              "dm_sessions %p, session %p\n",
++                              dm_sessions, s);
++              }
++              tmp->sn_next = s->sn_next;
++      }
++      s->sn_next = NULL;
++      dm_sessions_active--;
++}
++
++
++/* Link an event to the end of an event queue.        The caller must have obtained
++   the session's sn_qlock before calling this routine.
++*/
++
++void
++dm_link_event(
++      dm_tokevent_t   *tevp,
++      dm_eventq_t     *queue)
++{
++      if (queue->eq_tail) {
++              queue->eq_tail->te_next = tevp;
++              queue->eq_tail = tevp;
++      } else {
++              queue->eq_head = queue->eq_tail = tevp;
++      }
++      tevp->te_next = NULL;
++      queue->eq_count++;
++}
++
++
++/* Remove an event from an event queue.        The caller must have obtained the
++   session's sn_qlock before calling this routine.  dm_unlink_event() should
++   only be used in situations where the event is known to be on the queue;
++   otherwise it panics.
++*/
++
++void
++dm_unlink_event(
++      dm_tokevent_t   *tevp,
++      dm_eventq_t     *queue)
++{
++      dm_tokevent_t   *tmp;
++
++      if (queue->eq_head == tevp) {
++              queue->eq_head = tevp->te_next;
++              if (queue->eq_head == NULL)
++                      queue->eq_tail = NULL;
++      } else {
++              tmp = queue->eq_head;
++              while (tmp && tmp->te_next != tevp)
++                      tmp = tmp->te_next;
++              if (tmp == NULL) {
++                      panic("dm_unlink_event: corrupt DMAPI queue %p, "
++                              "tevp %p\n", queue, tevp);
++              }
++              tmp->te_next = tevp->te_next;
++              if (tmp->te_next == NULL)
++                      queue->eq_tail = tmp;
++      }
++      tevp->te_next = NULL;
++      queue->eq_count--;
++}
++
++/* Link a regular file event to a hash bucket.        The caller must have obtained
++   the session's sn_qlock before calling this routine.
++   The tokevent must be for a regular file object--DM_TDT_REG.
++*/
++
++static void
++hash_event(
++      dm_session_t    *s,
++      dm_tokevent_t   *tevp)
++{
++      dm_sesshash_t   *sh;
++      dm_ino_t        ino;
++
++      if (s->sn_sesshash == NULL) {
++              s->sn_sesshash = kmalloc(dm_hash_buckets * sizeof(dm_sesshash_t), GFP_KERNEL);
++              if (s->sn_sesshash == NULL) {
++                      printk("%s/%d: kmalloc returned NULL\n", __FUNCTION__, __LINE__);
++                      return;
++              }
++              memset(s->sn_sesshash, 0, dm_hash_buckets * sizeof(dm_sesshash_t));
++      }
++
++      ino = (&tevp->te_tdp->td_handle.ha_fid)->dm_fid_ino;
++      sh = DM_SHASH(s, ino);
++
++#ifdef DM_SHASH_DEBUG
++      if (sh->h_next == NULL) {
++              s->sn_buckets_in_use++;
++              if (s->sn_buckets_in_use > s->sn_max_buckets_in_use)
++                      s->sn_max_buckets_in_use++;
++      }
++      sh->maxlength++;
++      sh->curlength++;
++      sh->num_adds++;
++#endif
++
++      tevp->te_flags |= DM_TEF_HASHED;
++      tevp->te_hashnext = sh->h_next;
++      sh->h_next = tevp;
++}
++
++
++/* Remove a regular file event from a hash bucket.  The caller must have
++   obtained the session's sn_qlock before calling this routine.
++   The tokevent must be for a regular file object--DM_TDT_REG.
++*/
++
++static void
++unhash_event(
++      dm_session_t    *s,
++      dm_tokevent_t   *tevp)
++{
++      dm_sesshash_t   *sh;
++      dm_tokevent_t   *tmp;
++      dm_ino_t        ino;
++
++      if (s->sn_sesshash == NULL)
++              return;
++
++      ino = (&tevp->te_tdp->td_handle.ha_fid)->dm_fid_ino;
++      sh = DM_SHASH(s, ino);
++
++      if (sh->h_next == tevp) {
++              sh->h_next = tevp->te_hashnext; /* leap frog */
++      } else {
++              tmp = sh->h_next;
++              while (tmp->te_hashnext != tevp) {
++                      tmp = tmp->te_hashnext;
++              }
++              tmp->te_hashnext = tevp->te_hashnext; /* leap frog */
++      }
++      tevp->te_hashnext = NULL;
++      tevp->te_flags &= ~DM_TEF_HASHED;
++
++#ifdef DM_SHASH_DEBUG
++      if (sh->h_next == NULL)
++              s->sn_buckets_in_use--;
++      sh->curlength--;
++      sh->num_dels++;
++#endif
++}
++
++
++/* Determine if this is a repeat event.        The caller MUST be holding
++   the session lock.
++   The tokevent must be for a regular file object--DM_TDT_REG.
++   Returns:
++      0 == match not found
++      1 == match found
++*/
++
++static int
++repeated_event(
++      dm_session_t    *s,
++      dm_tokevent_t   *tevp)
++{
++      dm_sesshash_t   *sh;
++      dm_data_event_t *d_event1;
++      dm_data_event_t *d_event2;
++      dm_tokevent_t   *tevph;
++      dm_ino_t        ino1;
++      dm_ino_t        ino2;
++
++      if ((!s->sn_newq.eq_tail) && (!s->sn_delq.eq_tail)) {
++              return(0);
++      }
++      if (s->sn_sesshash == NULL) {
++              return(0);
++      }
++
++      ino1 = (&tevp->te_tdp->td_handle.ha_fid)->dm_fid_ino;
++      sh = DM_SHASH(s, ino1);
++
++      if (sh->h_next == NULL) {
++              /* bucket is empty, no match here */
++              return(0);
++      }
++
++      d_event1 = (dm_data_event_t *)((char *)&tevp->te_msg + tevp->te_msg.ev_data.vd_offset);
++      tevph = sh->h_next;
++      while (tevph) {
++              /* find something with the same event type and handle type */
++              if ((tevph->te_msg.ev_type == tevp->te_msg.ev_type) &&
++                  (tevph->te_tdp->td_type == tevp->te_tdp->td_type)) {
++
++                      ino2 = (&tevp->te_tdp->td_handle.ha_fid)->dm_fid_ino;
++                      d_event2 = (dm_data_event_t *)((char *)&tevph->te_msg + tevph->te_msg.ev_data.vd_offset);
++
++                      /* If the two events are operating on the same file,
++                         and the same part of that file, then we have a
++                         match.
++                      */
++                      if ((ino1 == ino2) &&
++                          (d_event2->de_offset == d_event1->de_offset) &&
++                          (d_event2->de_length == d_event1->de_length)) {
++                              /* found a match */
++#ifdef DM_SHASH_DEBUG
++                              sh->dup_hits++;
++#endif
++                              return(1);
++                      }
++              }
++              tevph = tevph->te_hashnext;
++      }
++
++      /* No match found */
++      return(0);
++}
++
++
++/* Return a pointer to a session given its session ID, or EINVAL if no session
++   has the session ID (per the DMAPI spec).  The caller must have obtained
++   dm_session_lock before calling this routine.
++*/
++
++static int
++dm_find_session(
++      dm_sessid_t     sid,
++      dm_session_t    **sessionpp)
++{
++      dm_session_t    *s;
++
++      for (s = dm_sessions; s; s = s->sn_next) {
++              if (s->sn_sessid == sid) {
++                      *sessionpp = s;
++                      return(0);
++              }
++      }
++      return(-EINVAL);
++}
++
++
++/* Return a pointer to a locked session given its session ID.  '*lcp' is
++   used to obtain the session's sn_qlock.  Caller is responsible for eventually
++   unlocking it.
++*/
++
++int
++dm_find_session_and_lock(
++      dm_sessid_t     sid,
++      dm_session_t    **sessionpp,
++      unsigned long   *lcp)           /* addr of returned lock cookie */
++{
++      int             error;
++
++      for (;;) {
++              *lcp = mutex_spinlock(&dm_session_lock);
++
++              if ((error = dm_find_session(sid, sessionpp)) != 0) {
++                      mutex_spinunlock(&dm_session_lock, *lcp);
++                      return(error);
++              }
++              if (spin_trylock(&(*sessionpp)->sn_qlock)) {
++                      nested_spinunlock(&dm_session_lock);
++                      return(0);      /* success */
++              }
++
++              /* If the second lock is not available, drop the first and
++                 start over.  This gives the CPU a chance to process any
++                 interrupts, and also allows processes which want a sn_qlock
++                 for a different session to proceed.
++              */
++
++              mutex_spinunlock(&dm_session_lock, *lcp);
++      }
++}
++
++
++/* Return a pointer to the event on the specified session's sn_delq which
++   contains the given token.  The caller must have obtained the session's
++   sn_qlock before calling this routine.
++*/
++
++static int
++dm_find_msg(
++      dm_session_t    *s,
++      dm_token_t      token,
++      dm_tokevent_t   **tevpp)
++{
++      dm_tokevent_t   *tevp;
++
++      if (token <= DM_INVALID_TOKEN)
++              return(-EINVAL);
++
++      for (tevp = s->sn_delq.eq_head; tevp; tevp = tevp->te_next) {
++              if (tevp->te_msg.ev_token == token) {
++                      *tevpp = tevp;
++                      return(0);
++              }
++      }
++      return(-ESRCH);
++}
++
++
++/* Given a session ID and token, find the tevp on the specified session's
++   sn_delq which corresponds to that session ID/token pair.  If a match is
++   found, lock the tevp's te_lock and return a pointer to the tevp.
++   '*lcp' is used to obtain the tevp's te_lock.        The caller is responsible
++   for eventually unlocking it.
++*/
++
++int
++dm_find_msg_and_lock(
++      dm_sessid_t     sid,
++      dm_token_t      token,
++      dm_tokevent_t   **tevpp,
++      unsigned long   *lcp)           /* address of returned lock cookie */
++{
++      dm_session_t    *s;
++      int             error;
++
++      if ((error = dm_find_session_and_lock(sid, &s, lcp)) != 0)
++              return(error);
++
++      if ((error = dm_find_msg(s, token, tevpp)) != 0) {
++              mutex_spinunlock(&s->sn_qlock, *lcp);
++              return(error);
++      }
++      nested_spinlock(&(*tevpp)->te_lock);
++      nested_spinunlock(&s->sn_qlock);
++      return(0);
++}
++
++
++/* Create a new session, or resume an old session if one is given. */
++
++int
++dm_create_session(
++      dm_sessid_t     old,
++      char            __user *info,
++      dm_sessid_t     __user *new)
++{
++      dm_session_t    *s;
++      dm_sessid_t     sid;
++      char            sessinfo[DM_SESSION_INFO_LEN];
++      size_t          len;
++      int             error;
++      unsigned long           lc;             /* lock cookie */
++
++      len = strnlen_user(info, DM_SESSION_INFO_LEN-1);
++      if (copy_from_user(sessinfo, info, len))
++              return(-EFAULT);
++      lc = mutex_spinlock(&dm_session_lock);
++      sid = dm_next_sessid++;
++      mutex_spinunlock(&dm_session_lock, lc);
++      if (copy_to_user(new, &sid, sizeof(sid)))
++              return(-EFAULT);
++
++      if (old == DM_NO_SESSION) {
++              s = kmem_cache_alloc(dm_session_cachep, GFP_KERNEL);
++              if (s == NULL) {
++                      printk("%s/%d: kmem_cache_alloc(dm_session_cachep) returned NULL\n", __FUNCTION__, __LINE__);
++                      return -ENOMEM;
++              }
++              memset(s, 0, sizeof(*s));
++
++              sv_init(&s->sn_readerq, SV_DEFAULT, "dmreadq");
++              sv_init(&s->sn_writerq, SV_DEFAULT, "dmwritq");
++              spinlock_init(&s->sn_qlock, "sn_qlock");
++      } else {
++              lc = mutex_spinlock(&dm_session_lock);
++              if ((error = dm_find_session(old, &s)) != 0) {
++                      mutex_spinunlock(&dm_session_lock, lc);
++                      return(error);
++              }
++              unlink_session(s);
++              mutex_spinunlock(&dm_session_lock, lc); 
++#ifdef CONFIG_PROC_FS
++              {
++              char buf[100];
++              sprintf(buf, DMAPI_DBG_PROCFS "/sessions/0x%p", s);
++              remove_proc_entry(buf, NULL);
++              }
++#endif
++      }
++      memcpy(s->sn_info, sessinfo, len);
++      s->sn_info[len-1] = 0;          /* if not NULL, then now 'tis */
++      s->sn_sessid = sid;
++      lc = mutex_spinlock(&dm_session_lock); 
++      link_session(s);
++      mutex_spinunlock(&dm_session_lock, lc);
++#ifdef CONFIG_PROC_FS
++      {
++      char buf[100];
++      struct proc_dir_entry *entry;
++
++      sprintf(buf, DMAPI_DBG_PROCFS "/sessions/0x%p", s);
++      entry = create_proc_read_entry(buf, 0, NULL, sessions_read_pfs, s);
++      entry->owner = THIS_MODULE;
++      }
++#endif
++      return(0);
++}
++
++
++int
++dm_destroy_session(
++      dm_sessid_t     sid)
++{
++      dm_session_t    *s;
++      int             error;
++      unsigned long           lc;             /* lock cookie */
++
++      /* The dm_session_lock must be held until the session is unlinked. */
++
++      lc = mutex_spinlock(&dm_session_lock);
++
++      if ((error = dm_find_session(sid, &s)) != 0) {
++              mutex_spinunlock(&dm_session_lock, lc);
++              return(error);
++      }
++      nested_spinlock(&s->sn_qlock);
++
++      /* The session exists.  Check to see if it is still in use.  If any
++         messages still exist on the sn_newq or sn_delq, or if any processes
++         are waiting for messages to arrive on the session, then the session
++         must not be destroyed.
++      */
++
++      if (s->sn_newq.eq_head || s->sn_readercnt || s->sn_delq.eq_head) {
++              nested_spinunlock(&s->sn_qlock);
++              mutex_spinunlock(&dm_session_lock, lc);
++              return(-EBUSY);
++      }
++
++      /* The session is not in use.  Dequeue it from the session chain. */
++
++      unlink_session(s);
++      nested_spinunlock(&s->sn_qlock);
++      mutex_spinunlock(&dm_session_lock, lc);
++
++#ifdef CONFIG_PROC_FS
++      {
++      char buf[100];
++      sprintf(buf, DMAPI_DBG_PROCFS "/sessions/0x%p", s);
++      remove_proc_entry(buf, NULL);
++      }
++#endif
++
++      /* Now clear the sessions's disposition registration, and then destroy
++         the session structure.
++      */
++
++      dm_clear_fsreg(s);
++
++      spinlock_destroy(&s->sn_qlock);
++      sv_destroy(&s->sn_readerq);
++      sv_destroy(&s->sn_writerq);
++      if (s->sn_sesshash)
++              kfree(s->sn_sesshash);
++      kmem_cache_free(dm_session_cachep, s);
++      return(0);
++}
++
++
++/*
++ *  Return a list of all active sessions.
++ */
++
++int
++dm_getall_sessions(
++      u_int           nelem,
++      dm_sessid_t     __user *sidp,
++      u_int           __user *nelemp)
++{
++      dm_session_t    *s;
++      u_int           sesscnt;
++      dm_sessid_t     *sesslist;
++      unsigned long           lc;             /* lock cookie */
++      int             error;
++      int             i;
++
++      /* Loop until we can get the right amount of temp space, being careful
++         not to hold a mutex during the allocation.  Usually only one trip.
++      */
++
++      for (;;) {
++              if ((sesscnt = dm_sessions_active) == 0) {
++                      /*if (suword(nelemp, 0))*/
++                      if (put_user(0, nelemp))
++                              return(-EFAULT);
++                      return(0);
++              }
++              sesslist = kmalloc(sesscnt * sizeof(*sidp), GFP_KERNEL);
++              if (sesslist == NULL) {
++                      printk("%s/%d: kmalloc returned NULL\n", __FUNCTION__, __LINE__);
++                      return -ENOMEM;
++              }
++
++              lc = mutex_spinlock(&dm_session_lock);
++              if (sesscnt == dm_sessions_active)
++                      break;
++
++              mutex_spinunlock(&dm_session_lock, lc);
++              kfree(sesslist);
++      }
++
++      /* Make a temp copy of the data, then release the mutex. */
++
++      for (i = 0, s = dm_sessions; i < sesscnt; i++, s = s->sn_next)
++              sesslist[i] = s->sn_sessid;
++
++      mutex_spinunlock(&dm_session_lock, lc);
++
++      /* Now copy the data to the user. */
++
++      if(put_user(sesscnt, nelemp)) {
++              error = -EFAULT;
++      } else if (sesscnt > nelem) {
++              error = -E2BIG;
++      } else if (copy_to_user(sidp, sesslist, sesscnt * sizeof(*sidp))) {
++              error = -EFAULT;
++      } else {
++              error = 0;
++      }
++      kfree(sesslist);
++      return(error);
++}
++
++
++/*
++ *  Return the descriptive string associated with a session.
++ */
++
++int
++dm_query_session(
++      dm_sessid_t     sid,
++      size_t          buflen,
++      void            __user *bufp,
++      size_t          __user *rlenp)
++{
++      dm_session_t    *s;             /* pointer to session given by sid */
++      int             len;            /* length of session info string */
++      int             error;
++      char            sessinfo[DM_SESSION_INFO_LEN];
++      unsigned long   lc;             /* lock cookie */
++
++      if ((error = dm_find_session_and_lock(sid, &s, &lc)) != 0)
++              return(error);
++
++      len = strlen(s->sn_info) + 1;   /* NULL terminated when created */
++      memcpy(sessinfo, s->sn_info, len);
++
++      mutex_spinunlock(&s->sn_qlock, lc);
++
++      /* Now that the mutex is released, copy the sessinfo to the user. */
++
++      if (put_user(len, rlenp)) {
++              error = -EFAULT;
++      } else if (len > buflen) {
++              error = -E2BIG;
++      } else if (copy_to_user(bufp, sessinfo, len)) {
++              error = -EFAULT;
++      } else {
++              error = 0;
++      }
++      return(error);
++}
++
++
++/*
++ *  Return all of the previously delivered tokens (that is, their IDs)
++ *  for the given session.
++ */
++
++int
++dm_getall_tokens(
++      dm_sessid_t     sid,            /* session obtaining tokens from */
++      u_int           nelem,          /* size of tokenbufp */
++      dm_token_t      __user *tokenbufp,/* buffer to copy token IDs to */
++      u_int           __user *nelemp) /* return number copied to tokenbufp */
++{
++      dm_session_t    *s;             /* pointer to session given by sid */
++      dm_tokevent_t   *tevp;          /* event message queue traversal */
++      unsigned long   lc;             /* lock cookie */
++      int             tokcnt;
++      dm_token_t      *toklist;
++      int             error;
++      int             i;
++
++      /* Loop until we can get the right amount of temp space, being careful
++         not to hold a mutex during the allocation.  Usually only one trip.
++      */
++
++      for (;;) {
++              if ((error = dm_find_session_and_lock(sid, &s, &lc)) != 0)
++                      return(error);
++              tokcnt = s->sn_delq.eq_count;
++              mutex_spinunlock(&s->sn_qlock, lc);
++
++              if (tokcnt == 0) {
++                      /*if (suword(nelemp, 0))*/
++                      if (put_user(0, nelemp))
++                              return(-EFAULT);
++                      return(0);
++              }
++              toklist = kmalloc(tokcnt * sizeof(*tokenbufp), GFP_KERNEL);
++              if (toklist == NULL) {
++                      printk("%s/%d: kmalloc returned NULL\n", __FUNCTION__, __LINE__);
++                      return -ENOMEM;
++              }
++
++              if ((error = dm_find_session_and_lock(sid, &s, &lc)) != 0) {
++                      kfree(toklist);
++                      return(error);
++              }
++
++              if (tokcnt == s->sn_delq.eq_count)
++                      break;
++
++              mutex_spinunlock(&s->sn_qlock, lc);
++              kfree(toklist);
++      }
++
++      /* Make a temp copy of the data, then release the mutex. */
++
++      tevp = s->sn_delq.eq_head;
++      for (i = 0; i < tokcnt; i++, tevp = tevp->te_next)
++              toklist[i] = tevp->te_msg.ev_token;
++
++      mutex_spinunlock(&s->sn_qlock, lc);
++
++      /* Now copy the data to the user. */
++
++      if (put_user(tokcnt, nelemp)) {
++              error = -EFAULT;
++      } else if (tokcnt > nelem) {
++              error = -E2BIG;
++      } else if (copy_to_user(tokenbufp,toklist,tokcnt*sizeof(*tokenbufp))) {
++              error = -EFAULT;
++      } else {
++              error = 0;
++      }
++      kfree(toklist);
++      return(error);
++}
++
++
++/*
++ *  Return the message identified by token.
++ */
++
++int
++dm_find_eventmsg(
++      dm_sessid_t     sid,
++      dm_token_t      token,
++      size_t          buflen,
++      void            __user *bufp,
++      size_t          __user *rlenp)
++{
++      dm_tokevent_t   *tevp;          /* message identified by token */
++      int             msgsize;        /* size of message to copy out */
++      void            *msg;
++      int             error;
++      unsigned long   lc;             /* lock cookie */
++
++      /* Because some of the events (dm_data_event_t in particular) contain
++         __u64 fields, we need to make sure that the buffer provided by the
++         caller is aligned such that he can read those fields successfully.
++      */
++
++      if (((unsigned long)bufp & (sizeof(__u64) - 1)) != 0)
++              return(-EFAULT);
++
++      /* Allocate the right amount of temp space, being careful not to hold
++         a mutex during the allocation.
++      */
++
++      if ((error = dm_find_msg_and_lock(sid, token, &tevp, &lc)) != 0)
++              return(error);
++      msgsize = tevp->te_allocsize - offsetof(dm_tokevent_t, te_msg);
++      mutex_spinunlock(&tevp->te_lock, lc);
++
++      msg = kmalloc(msgsize, GFP_KERNEL);
++      if (msg == NULL) {
++              printk("%s/%d: kmalloc returned NULL\n", __FUNCTION__, __LINE__);
++              return -ENOMEM;
++      }
++
++      if ((error = dm_find_msg_and_lock(sid, token, &tevp, &lc)) != 0) {
++              kfree(msg);
++              return(error);
++      }
++
++      /* Make a temp copy of the data, then release the mutex. */
++
++      memcpy(msg, &tevp->te_msg, msgsize);
++      mutex_spinunlock(&tevp->te_lock, lc);
++
++      /* Now copy the data to the user. */
++
++      if (put_user(msgsize,rlenp)) {
++              error = -EFAULT;
++      } else if (msgsize > buflen) {          /* user buffer not big enough */
++              error = -E2BIG;
++      } else if (copy_to_user( bufp, msg, msgsize )) {
++              error = -EFAULT;
++      } else {
++              error = 0;
++      }
++      kfree(msg);
++      return(error);
++}
++
++
++int
++dm_move_event(
++      dm_sessid_t     srcsid,
++      dm_token_t      token,
++      dm_sessid_t     targetsid,
++      dm_token_t      __user *rtokenp)
++{
++      dm_session_t    *s1;
++      dm_session_t    *s2;
++      dm_tokevent_t   *tevp;
++      int             error;
++      unsigned long           lc;             /* lock cookie */
++      int             hash_it = 0;
++
++      lc = mutex_spinlock(&dm_session_lock);
++
++      if ((error = dm_find_session(srcsid, &s1)) != 0 ||
++          (error = dm_find_session(targetsid, &s2)) != 0 ||
++          (error = dm_find_msg(s1, token, &tevp)) != 0) {
++              mutex_spinunlock(&dm_session_lock, lc);
++              return(error);
++      }
++      dm_unlink_event(tevp, &s1->sn_delq);
++      if (tevp->te_flags & DM_TEF_HASHED) {
++              unhash_event(s1, tevp);
++              hash_it = 1;
++      }
++      dm_link_event(tevp, &s2->sn_delq);
++      if (hash_it)
++              hash_event(s2, tevp);
++      mutex_spinunlock(&dm_session_lock, lc);
++
++      if (copy_to_user(rtokenp, &token, sizeof(token)))
++              return(-EFAULT);
++      return(0);
++}
++
++
++/* ARGSUSED */
++int
++dm_pending(
++      dm_sessid_t     sid,
++      dm_token_t      token,
++      dm_timestruct_t __user *delay)          /* unused */
++{
++      dm_tokevent_t   *tevp;
++      int             error;
++      unsigned long   lc;             /* lock cookie */
++
++      if ((error = dm_find_msg_and_lock(sid, token, &tevp, &lc)) != 0)
++              return(error);
++
++      tevp->te_flags |= DM_TEF_INTERMED;
++      if (tevp->te_evt_ref > 0)       /* if event generation threads exist */
++              sv_broadcast(&tevp->te_evt_queue);
++
++      mutex_spinunlock(&tevp->te_lock, lc);
++      return(0);
++}
++
++
++int
++dm_get_events(
++      dm_sessid_t     sid,
++      u_int           maxmsgs,
++      u_int           flags,
++      size_t          buflen,
++      void            __user *bufp,
++      size_t          __user *rlenp)
++{
++      dm_session_t    *s;             /* pointer to session given by sid */
++      dm_tokevent_t   *tevp;          /* next event message on queue */
++      int             error;
++      unsigned long   lc1;            /* first lock cookie */
++      unsigned long   lc2 = 0;        /* second lock cookie */
++      int             totalsize;
++      int             msgsize;
++      dm_eventmsg_t   __user *prevmsg;
++      int             prev_msgsize = 0;
++      u_int           msgcnt;
++
++      /* Because some of the events (dm_data_event_t in particular) contain
++         __u64 fields, we need to make sure that the buffer provided by the
++         caller is aligned such that he can read those fields successfully.
++      */
++
++      if (((unsigned long)bufp & (sizeof(__u64) - 1)) != 0)
++              return(-EFAULT);
++
++      /* Find the indicated session and lock it. */
++
++      if ((error = dm_find_session_and_lock(sid, &s, &lc1)) != 0)
++              return(error);
++
++      /* Check for messages on sn_newq.  If there aren't any that haven't
++         already been grabbed by another process, and if we are supposed to
++         to wait until one shows up, then go to sleep interruptibly on the
++         sn_readerq semaphore.  The session can't disappear out from under
++         us as long as sn_readerq is non-zero.
++      */
++
++      for (;;) {
++              int             rc;
++
++              for (tevp = s->sn_newq.eq_head; tevp; tevp = tevp->te_next) {
++                      lc2 = mutex_spinlock(&tevp->te_lock);
++                      if (!(tevp->te_flags & DM_TEF_LOCKED))
++                              break;
++                      mutex_spinunlock(&tevp->te_lock, lc2);
++              }
++              if (tevp)
++                      break;          /* got one! */
++
++              if (!(flags & DM_EV_WAIT)) {
++                      mutex_spinunlock(&s->sn_qlock, lc1);
++                      return(-EAGAIN);
++              }
++              s->sn_readercnt++;
++
++              sv_wait_sig(&s->sn_readerq, 1, &s->sn_qlock, lc1);
++              rc = signal_pending(current);
++
++              lc1 = mutex_spinlock(&s->sn_qlock);
++              s->sn_readercnt--;
++              if (rc) {       /* if signal was received */
++                      mutex_spinunlock(&s->sn_qlock, lc1);
++                      return(-EINTR);
++              }
++      }
++
++      /* At least one message is available for delivery, and we have both the
++         session lock and event lock.  Mark the event so that it is not
++         grabbed by other daemons, then drop both locks prior copying the
++         data to the caller's buffer.  Leaving the event on the queue in a
++         marked state prevents both the session and the event from
++         disappearing out from under us while we don't have the locks.
++      */
++
++      tevp->te_flags |= DM_TEF_LOCKED;
++      mutex_spinunlock(&tevp->te_lock, lc2);  /* reverse cookie order */
++      mutex_spinunlock(&s->sn_qlock, lc1);
++
++      /* Continue to deliver messages until there are no more, the
++         user's buffer becomes full, or we hit his maxmsgs limit.
++      */
++
++      totalsize = 0;          /* total bytes transferred to the user */
++      prevmsg = NULL;
++      msgcnt = 0;
++
++      while (tevp) {
++              /* Compute the number of bytes to be moved, rounding up to an
++                 8-byte boundary so that any subsequent messages will also be
++                 aligned.
++              */
++
++              msgsize = tevp->te_allocsize - offsetof(dm_tokevent_t, te_msg);
++              msgsize = (msgsize + sizeof(__u64) - 1) & ~(sizeof(__u64) - 1);
++              totalsize += msgsize;
++
++              /* If it fits, copy the message into the user's buffer and
++                 update his 'rlenp'.  Update the _link pointer for any
++                 previous message.
++              */
++
++              if (totalsize > buflen) {       /* no more room */
++                      error = -E2BIG;
++              } else if (put_user(totalsize, rlenp)) {
++                      error = -EFAULT;
++              } else if (copy_to_user(bufp, &tevp->te_msg, msgsize)) {
++                      error = -EFAULT;
++              } else if (prevmsg && put_user(prev_msgsize, &prevmsg->_link)) {
++                      error = -EFAULT;
++              } else {
++                      error = 0;
++              }
++
++              /* If an error occurred, just unmark the event and leave it on
++                 the queue for someone else.  Note that other daemons may
++                 have gone to sleep because this event was marked, so wake
++                 them up.  Also, if at least one message has already been
++                 delivered, then an error here is not really an error.
++              */
++
++              lc1 = mutex_spinlock(&s->sn_qlock);
++              lc2 = mutex_spinlock(&tevp->te_lock);
++              tevp->te_flags &= ~DM_TEF_LOCKED;       /* drop the mark */
++
++              if (error) {
++                      if (s->sn_readercnt)
++                              sv_signal(&s->sn_readerq);
++
++                      mutex_spinunlock(&tevp->te_lock, lc2);  /* rev. order */
++                      mutex_spinunlock(&s->sn_qlock, lc1);
++                      if (prevmsg)
++                              return(0);
++                      if (error == -E2BIG && put_user(totalsize,rlenp))
++                              error = -EFAULT;
++                      return(error);
++              }
++
++              /* The message was successfully delivered.  Unqueue it. */
++
++              dm_unlink_event(tevp, &s->sn_newq);
++
++              /* Wake up the first of any processes waiting for room on the
++                 sn_newq.
++              */
++
++              if (s->sn_writercnt)
++                      sv_signal(&s->sn_writerq);
++
++              /* If the message is synchronous, add it to the sn_delq while
++                 still holding the lock.  If it is asynchronous, free it.
++              */
++
++              if (tevp->te_msg.ev_token != DM_INVALID_TOKEN) { /* synch */
++                      dm_link_event(tevp, &s->sn_delq);
++                      mutex_spinunlock(&tevp->te_lock, lc2);
++              } else {
++                      tevp->te_flags |= DM_TEF_FINAL;
++                      if (tevp->te_flags & DM_TEF_HASHED)
++                              unhash_event(s, tevp);
++                      mutex_spinunlock(&tevp->te_lock, lc2);
++                      dm_put_tevp(tevp, NULL);/* can't cause destroy events */
++              }
++
++              /* Update our notion of where we are in the user's buffer.  If
++                 he doesn't want any more messages, then stop.
++              */
++
++              prevmsg = (dm_eventmsg_t __user *)bufp;
++              prev_msgsize = msgsize;
++              bufp = (char __user *)bufp + msgsize;
++
++              msgcnt++;
++              if (maxmsgs && msgcnt >= maxmsgs) {
++                      mutex_spinunlock(&s->sn_qlock, lc1);
++                      break;
++              }
++
++              /* While still holding the sn_qlock,  see if any additional
++                 messages are available for delivery.
++              */
++
++              for (tevp = s->sn_newq.eq_head; tevp; tevp = tevp->te_next) {
++                      lc2 = mutex_spinlock(&tevp->te_lock);
++                      if (!(tevp->te_flags & DM_TEF_LOCKED)) {
++                              tevp->te_flags |= DM_TEF_LOCKED;
++                              mutex_spinunlock(&tevp->te_lock, lc2);
++                              break;
++                      }
++                      mutex_spinunlock(&tevp->te_lock, lc2);
++              }
++              mutex_spinunlock(&s->sn_qlock, lc1);
++      }
++      return(0);
++}
++
++
++/*
++ *  Remove an event message from the delivered queue, set the returned
++ *  error where the event generator wants it, and wake up the generator.
++ *  Also currently have the user side release any locks it holds...
++ */
++
++/* ARGSUSED */
++int
++dm_respond_event(
++      dm_sessid_t     sid,
++      dm_token_t      token,
++      dm_response_t   response,
++      int             reterror,
++      size_t          buflen,         /* unused */
++      void            __user *respbufp) /* unused */
++{
++      dm_session_t    *s;             /* pointer to session given by sid */
++      dm_tokevent_t   *tevp;          /* event message queue traversal */
++      int             error;
++      unsigned long   lc;             /* lock cookie */
++
++      /* Sanity check the input parameters. */
++
++      switch (response) {
++      case DM_RESP_CONTINUE:  /* continue must have reterror == 0 */
++              if (reterror != 0)
++                      return(-EINVAL);
++              break;
++      case DM_RESP_ABORT:     /* abort must have errno set */
++              if (reterror <= 0)
++                      return(-EINVAL);
++              break;
++      case DM_RESP_DONTCARE:
++              reterror = -1;  /* to distinguish DM_RESP_DONTCARE */
++              break;
++      default:
++              return(-EINVAL);
++      }
++
++      /* Hold session lock until the event is unqueued. */
++
++      if ((error = dm_find_session_and_lock(sid, &s, &lc)) != 0)
++              return(error);
++
++      if ((error = dm_find_msg(s, token, &tevp)) != 0) {
++              mutex_spinunlock(&s->sn_qlock, lc);
++              return(error);
++      }
++      nested_spinlock(&tevp->te_lock);
++
++      if ((response == DM_RESP_DONTCARE) &&
++          (tevp->te_msg.ev_type != DM_EVENT_MOUNT)) {
++              error = -EINVAL;
++              nested_spinunlock(&tevp->te_lock);
++              mutex_spinunlock(&s->sn_qlock, lc);
++      } else {
++              dm_unlink_event(tevp, &s->sn_delq);
++              if (tevp->te_flags & DM_TEF_HASHED)
++                      unhash_event(s, tevp);
++              tevp->te_reply = -reterror; /* linux wants negative errno */
++              tevp->te_flags |= DM_TEF_FINAL;
++              if (tevp->te_evt_ref)
++                      sv_broadcast(&tevp->te_evt_queue);
++              nested_spinunlock(&tevp->te_lock);
++              mutex_spinunlock(&s->sn_qlock, lc);
++              error = 0;
++
++              /* Absolutely no locks can be held when calling dm_put_tevp! */
++
++              dm_put_tevp(tevp, NULL);  /* this can generate destroy events */
++      }
++      return(error);
++}
++
++/* The caller must hold sn_qlock.
++   This will return the tokevent locked.
++ */
++static dm_tokevent_t *
++__find_match_event_no_waiters_locked(
++      dm_tokevent_t   *tevp1,
++      dm_eventq_t     *queue)
++{
++      dm_tokevent_t   *tevp2, *next_tevp;
++      dm_tokdata_t    *tdp1 = tevp1->te_tdp;
++      dm_tokdata_t    *tdp2;
++      dm_data_event_t *d_event1;
++      dm_data_event_t *d_event2;
++
++      d_event1 = (dm_data_event_t *)((char *)&tevp1->te_msg + tevp1->te_msg.ev_data.vd_offset);
++
++      for(tevp2 = queue->eq_head; tevp2; tevp2 = next_tevp) {
++              nested_spinlock(&tevp2->te_lock);
++              next_tevp = tevp2->te_next;
++
++              /* Just compare the first tdp's in each--there should
++                 be just one, if it's the match we want.
++               */
++              tdp2 = tevp2->te_tdp;
++              if ((tevp2->te_msg.ev_type == tevp1->te_msg.ev_type) &&
++                  (tevp2->te_tdp->td_type == tevp1->te_tdp->td_type) &&
++                  (tevp2->te_evt_ref == 0) && (tdp2->td_next == NULL) &&
++                  (memcmp(&tdp1->td_handle, &tdp2->td_handle,
++                         sizeof(dm_handle_t)) == 0)) {
++
++                      d_event2 = (dm_data_event_t *)((char *)&tevp2->te_msg + tevp2->te_msg.ev_data.vd_offset);
++
++
++                      if ((d_event2->de_offset == d_event1->de_offset) &&
++                          (d_event2->de_length == d_event1->de_length)) {
++                              /* Match -- return it locked */
++                              return tevp2;
++                      }
++              }
++              nested_spinunlock(&tevp2->te_lock);
++      }
++      return NULL;
++}
++
++/* The caller must hold the sn_qlock.
++   The returned tokevent will be locked with nested_spinlock.
++ */
++static dm_tokevent_t *
++find_match_event_no_waiters_locked(
++      dm_session_t    *s,
++      dm_tokevent_t   *tevp)
++{
++      dm_tokevent_t   *tevp2;
++
++      if ((!s->sn_newq.eq_tail) && (!s->sn_delq.eq_tail))
++              return NULL;
++      if (!tevp->te_tdp)
++              return NULL;
++      if (tevp->te_tdp->td_next) {
++              /* If it has multiple tdp's then don't bother trying to
++                 find a match.
++               */
++              return NULL;
++      }
++      tevp2 = __find_match_event_no_waiters_locked(tevp, &s->sn_newq);
++      if (tevp2 == NULL)
++              tevp2 = __find_match_event_no_waiters_locked(tevp, &s->sn_delq);
++      /* returns a locked tokevent */
++      return tevp2;
++}
++
++
++
++/* Queue the filled in event message pointed to by tevp on the session s, and
++   (if a synchronous event) wait for the reply from the DMAPI application.
++   The caller MUST be holding the session lock before calling this routine!
++   The session lock is always released upon exit.
++   Returns:
++       -1 == don't care
++        0 == success (or async event)
++      > 0 == errno describing reason for failure
++*/
++
++static int
++dm_enqueue(
++      dm_session_t    *s,
++      unsigned long   lc,             /* input lock cookie */
++      dm_tokevent_t   **tevpp,                /* in/out parameter */
++      int             sync,
++      int             flags,
++      int             interruptable)
++{
++      int             is_unmount = 0;
++      int             is_hashable = 0;
++      int             reply;
++      dm_tokevent_t   *tevp = *tevpp;
++
++      /* If the caller isn't planning to stick around for the result
++         and this request is identical to one that is already on the
++         queues then just give the caller an EAGAIN.  Release the
++         session lock before returning.
++
++         We look only at NDELAY requests with an event type of READ,
++         WRITE, or TRUNCATE on objects that are regular files.
++      */
++
++      if ((flags & DM_FLAGS_NDELAY) && DM_EVENT_RDWRTRUNC(tevp) &&
++          (tevp->te_tdp->td_type == DM_TDT_REG)) {
++              if (repeated_event(s, tevp)) {
++                      mutex_spinunlock(&s->sn_qlock, lc);
++                      return -EAGAIN;
++              }
++              is_hashable = 1;
++      }
++
++      /* If the caller is a sync event then look for a matching sync
++         event.  If there is a match and it doesn't currently have
++         event threads waiting on it, then we will drop our own
++         tokevent and jump on the matching event.
++       */
++      if (((flags & DM_FLAGS_NDELAY) == 0) && DM_EVENT_RDWRTRUNC(tevp) &&
++          (tevp->te_tdp->td_type == DM_TDT_REG)) {
++              dm_tokevent_t   *tevp2;
++              if ((tevp2 = find_match_event_no_waiters_locked(s, tevp))) {
++                      ASSERT(tevp2->te_evt_ref == 0);
++                      tevp2->te_evt_ref++;
++                      nested_spinunlock(&tevp2->te_lock);
++                      nested_spinlock(&tevp->te_lock);
++                      tevp->te_evt_ref--;
++                      nested_spinunlock(&tevp->te_lock);
++                      mutex_spinunlock(&s->sn_qlock, lc);
++                      /* All locks have been released */
++                      dm_evt_rele_tevp(tevp, 1);
++                      *tevpp = tevp = tevp2;
++                      goto wait_on_tevp;
++              }
++      }
++
++      if (tevp->te_msg.ev_type == DM_EVENT_UNMOUNT)
++              is_unmount = 1;
++
++      /* Check for room on sn_newq.  If there is no room for new messages,
++         then go to sleep on the sn_writerq semaphore.  The
++         session cannot disappear out from under us as long as sn_writercnt
++         is non-zero.
++      */
++
++      while (s->sn_newq.eq_count >= dm_max_queued_msgs) {     /* no room */
++              s->sn_writercnt++;
++              dm_link_event(tevp, &s->sn_evt_writerq);
++              if (interruptable) {
++                      sv_wait_sig(&s->sn_writerq, 1, &s->sn_qlock, lc);
++                      if (signal_pending(current)) {
++                              s->sn_writercnt--;
++                              return -EINTR;
++                      }
++              } else {
++                      sv_wait(&s->sn_writerq, 1, &s->sn_qlock, lc);
++              }
++              lc = mutex_spinlock(&s->sn_qlock);
++              s->sn_writercnt--;
++              dm_unlink_event(tevp, &s->sn_evt_writerq);
++#ifdef HAVE_DM_QUEUE_FLUSH
++              /* We hold the sn_qlock, from here to after we get into
++               * the sn_newq.  Any thread going through
++               * dm_release_threads() looking for us is already past us
++               * and has set the DM_TEF_FLUSH flag for us or is blocked on
++               * sn_qlock and will find us in sn_newq after we release
++               * the sn_qlock.
++               * We check for dop->flushing anyway, in case the
++               * dm_release_threads() already completed before we
++               * could enter dmapi.
++               */
++              if (!sync) {
++                      /* async events are forced into the newq */
++                      break;
++              }
++              if (tevp->te_flags & DM_TEF_FLUSH) {
++                      mutex_spinunlock(&s->sn_qlock, lc);
++                      return tevp->te_reply;
++              }
++              else {
++                      struct filesystem_dmapi_operations *dops;
++                      dm_tokdata_t    *tdp;
++                      int             errno = 0;
++
++                      nested_spinlock(&tevp->te_lock);
++                      for (tdp = tevp->te_tdp; tdp; tdp = tdp->td_next) {
++                              if (tdp->td_ip) {
++                                      dops = dm_fsys_ops(tdp->td_ip->i_sb);
++                                      ASSERT(dops);
++                                      if (dops->flushing)
++                                              errno = dops->flushing(tdp->td_ip);
++                                      if (errno) {
++                                              nested_spinunlock(&tevp->te_lock);
++                                              mutex_spinunlock(&s->sn_qlock, lc);
++                                              return errno;
++                                      }
++                              }
++                      }
++                      nested_spinunlock(&tevp->te_lock);
++              }
++#endif /* HAVE_DM_QUEUE_FLUSH */
++      }
++
++      /* Assign a sequence number and token to the event and bump the
++         application reference count by one.  We don't need 'te_lock' here
++         because this thread is still the only thread that can see the event.
++      */
++
++      nested_spinlock(&dm_token_lock);
++      tevp->te_msg.ev_sequence = dm_next_sequence++;
++      if (sync) {
++              tevp->te_msg.ev_token = dm_next_token++;
++      } else {
++              tevp->te_msg.ev_token = DM_INVALID_TOKEN;
++      }
++      nested_spinunlock(&dm_token_lock);
++
++      tevp->te_app_ref++;
++
++      /* Room exists on the sn_newq queue, so add this request.  If the
++         queue was previously empty, wake up the first of any processes
++         that are waiting for an event.
++      */
++
++      dm_link_event(tevp, &s->sn_newq);
++      if (is_hashable)
++              hash_event(s, tevp);
++
++      if (s->sn_readercnt)
++              sv_signal(&s->sn_readerq);
++
++      mutex_spinunlock(&s->sn_qlock, lc);
++
++      /* Now that the message is queued, processes issuing asynchronous
++         events or DM_EVENT_UNMOUNT events are ready to continue.
++      */
++
++      if (!sync || is_unmount)
++              return 0;
++
++      /* Synchronous requests wait until a final reply is received.  If the
++         caller supplied the DM_FLAGS_NDELAY flag, the process will return
++         EAGAIN if dm_pending() sets DM_TEF_INTERMED.  We also let users
++         Cntl-C out of a read, write, and truncate requests.
++      */
++
++wait_on_tevp:
++      lc = mutex_spinlock(&tevp->te_lock);
++
++      while (!(tevp->te_flags & DM_TEF_FINAL)) {
++              if ((tevp->te_flags & DM_TEF_INTERMED) &&
++                  (flags & DM_FLAGS_NDELAY)) {
++                      mutex_spinunlock(&tevp->te_lock, lc);
++                      return -EAGAIN;
++              }
++              if (tevp->te_msg.ev_type == DM_EVENT_READ ||
++                  tevp->te_msg.ev_type == DM_EVENT_WRITE ||
++                  tevp->te_msg.ev_type == DM_EVENT_TRUNCATE) {
++                      sv_wait_sig(&tevp->te_evt_queue, 1, &tevp->te_lock, lc);
++                      if (signal_pending(current)){
++                              return -EINTR;
++                      }
++              } else {
++                      sv_wait(&tevp->te_evt_queue, 1, &tevp->te_lock, lc);
++              }
++              lc = mutex_spinlock(&tevp->te_lock);
++#ifdef HAVE_DM_QUEUE_FLUSH
++              /* Did we pop out because of queue flushing? */
++              if (tevp->te_flags & DM_TEF_FLUSH) {
++                      mutex_spinunlock(&tevp->te_lock, lc);
++                      return tevp->te_reply;
++              }
++#endif /* HAVE_DM_QUEUE_FLUSH */
++      }
++
++      /* Return both the tevp and the reply which was stored in the tevp by
++         dm_respond_event.  The tevp structure has already been removed from
++         the reply queue by this point in dm_respond_event().
++      */
++
++      reply = tevp->te_reply;
++      mutex_spinunlock(&tevp->te_lock, lc);
++      return reply;
++}
++
++
++/* The filesystem is guaranteed to stay mounted while this event is
++   outstanding.
++*/
++
++int
++dm_enqueue_normal_event(
++      struct super_block *sb,
++      dm_tokevent_t   **tevpp,
++      int             flags)
++{
++      dm_session_t    *s;
++      int             error;
++      int             sync;
++      unsigned long   lc;             /* lock cookie */
++
++      switch ((*tevpp)->te_msg.ev_type) {
++      case DM_EVENT_READ:
++      case DM_EVENT_WRITE:
++      case DM_EVENT_TRUNCATE:
++      case DM_EVENT_PREUNMOUNT:
++      case DM_EVENT_UNMOUNT:
++      case DM_EVENT_NOSPACE:
++      case DM_EVENT_CREATE:
++      case DM_EVENT_REMOVE:
++      case DM_EVENT_RENAME:
++      case DM_EVENT_SYMLINK:
++      case DM_EVENT_LINK:
++      case DM_EVENT_DEBUT:            /* not currently supported */
++              sync = 1;
++              break;
++
++      case DM_EVENT_DESTROY:
++      case DM_EVENT_POSTCREATE:
++      case DM_EVENT_POSTREMOVE:
++      case DM_EVENT_POSTRENAME:
++      case DM_EVENT_POSTSYMLINK:
++      case DM_EVENT_POSTLINK:
++      case DM_EVENT_ATTRIBUTE:
++      case DM_EVENT_CLOSE:            /* not currently supported */
++      case DM_EVENT_CANCEL:           /* not currently supported */
++              sync = 0;
++              break;
++
++      default:
++              return(-EIO);           /* garbage event number */
++      }
++
++      /* Wait until a session selects disposition for the event.  The session
++         is locked upon return from dm_waitfor_disp_session().
++      */
++
++      if ((error = dm_waitfor_disp_session(sb, *tevpp, &s, &lc)) != 0)
++              return(error);
++
++      return(dm_enqueue(s, lc, tevpp, sync, flags, 0));
++}
++
++
++/* Traverse the session list checking for sessions with the WANTMOUNT flag
++   set.        When one is found, send it the message.  Possible responses to the
++   message are one of DONTCARE, CONTINUE, or ABORT.  The action taken in each
++   case is:
++      DONTCARE (-1)  - Send the event to the next session with WANTMOUNT set
++      CONTINUE ( 0) - Proceed with the mount, errno zero.
++      ABORT    (>0) - Fail the mount, return the returned errno.
++
++   The mount request is sent to sessions in ascending session ID order.
++   Since the session list can change dramatically while this process is
++   sleeping in dm_enqueue(), this routine must use session IDs rather than
++   session pointers when keeping track of where it is in the list.  Since
++   new sessions are always added at the end of the queue, and have increasing
++   session ID values, we don't have to worry about missing any session.
++*/
++
++int
++dm_enqueue_mount_event(
++      struct super_block *sb,
++      dm_tokevent_t   *tevp)
++{
++      dm_session_t    *s;
++      dm_sessid_t     sid;
++      int             error;
++      unsigned long   lc;             /* lock cookie */
++
++      /* Make the mounting filesystem visible to other DMAPI calls. */
++
++      if ((error = dm_add_fsys_entry(sb, tevp)) != 0){
++              return(error);
++      }
++
++      /* Walk through the session list presenting the mount event to each
++         session that is interested until a session accepts or rejects it,
++         or until all sessions ignore it.
++      */
++
++      for (sid = DM_NO_SESSION, error = 1; error > 0; sid = s->sn_sessid) {
++
++              lc = mutex_spinlock(&dm_session_lock);
++              for (s = dm_sessions; s; s = s->sn_next) {
++                      if (s->sn_sessid > sid && s->sn_flags & DM_SN_WANTMOUNT) {
++                              nested_spinlock(&s->sn_qlock);
++                              nested_spinunlock(&dm_session_lock);
++                              break;
++                      }
++              }
++              if (s == NULL) {
++                      mutex_spinunlock(&dm_session_lock, lc);
++                      break;          /* noone wants it; proceed with mount */
++              }
++              error = dm_enqueue(s, lc, &tevp, 1, 0, 0);
++      }
++
++      /* If the mount will be allowed to complete, then update the fsrp entry
++         accordingly.  If the mount is to be aborted, remove the fsrp entry.
++      */
++
++      if (error >= 0) {
++              dm_change_fsys_entry(sb, DM_STATE_MOUNTED);
++              error = 0;
++      } else {
++              dm_remove_fsys_entry(sb);
++      }
++      return(error);
++}
++
++int
++dm_enqueue_sendmsg_event(
++      dm_sessid_t     targetsid,
++      dm_tokevent_t   *tevp,
++      int             sync)
++{
++      dm_session_t    *s;
++      int             error;
++      unsigned long   lc;             /* lock cookie */
++
++      if ((error = dm_find_session_and_lock(targetsid, &s, &lc)) != 0)
++              return(error);
++
++      return(dm_enqueue(s, lc, &tevp, sync, 0, 1));
++}
++
++
++dm_token_t
++dm_enqueue_user_event(
++      dm_sessid_t     sid,
++      dm_tokevent_t   *tevp,
++      dm_token_t      *tokenp)
++{
++      dm_session_t    *s;
++      int             error;
++      unsigned long   lc;             /* lock cookie */
++
++      /* Atomically find and lock the session whose session id is 'sid'. */
++
++      if ((error = dm_find_session_and_lock(sid, &s, &lc)) != 0)
++              return(error);
++
++      /* Assign a sequence number and token to the event, bump the
++         application reference count by one, and decrement the event
++         count because the caller gives up all ownership of the event.
++         We don't need 'te_lock' here because this thread is still the
++         only thread that can see the event.
++      */
++
++      nested_spinlock(&dm_token_lock);
++      tevp->te_msg.ev_sequence = dm_next_sequence++;
++      *tokenp = tevp->te_msg.ev_token = dm_next_token++;
++      nested_spinunlock(&dm_token_lock);
++
++      tevp->te_flags &= ~(DM_TEF_INTERMED|DM_TEF_FINAL);
++      tevp->te_app_ref++;
++      tevp->te_evt_ref--;
++
++      /* Add the request to the tail of the sn_delq.  Now it's visible. */
++
++      dm_link_event(tevp, &s->sn_delq);
++      mutex_spinunlock(&s->sn_qlock, lc);
++
++      return(0);
++}
++
++#ifdef HAVE_DM_QUEUE_FLUSH
++/* If inode is non-null, find any tdp referencing that inode and flush the
++ * thread waiting on that inode and set DM_TEF_FLUSH for that tokevent.
++ * Otherwise, if inode is null, find any tdp referencing the specified fsid
++ * and flush that thread and set DM_TEF_FLUSH for that tokevent.
++ */
++static int
++dm_flush_events(
++      dm_session_t    *s,
++      dm_fsid_t       *fsidp,
++      struct inode    *inode, /* may be null */
++      dm_eventq_t     *queue,
++      int             is_writerq,
++      int             errno)
++{
++      dm_tokevent_t   *tevp, *next_tevp;
++      dm_tokdata_t    *tdp;
++      int             found_events = 0;
++
++      ASSERT(fsidp);
++      for (tevp = queue->eq_head; tevp; tevp = next_tevp) {
++              nested_spinlock(&tevp->te_lock);
++              next_tevp = tevp->te_next;
++
++              for (tdp = tevp->te_tdp; tdp; tdp = tdp->td_next) {
++                      if( inode ) {
++                              if( tdp->td_ip == inode ) {
++                                      break;
++                              }
++                      }
++                      else if(memcmp(fsidp, &tdp->td_handle.ha_fsid, sizeof(*fsidp)) == 0) {
++                              break;
++                      }
++              }
++
++              if (tdp != NULL) {
++                      /* found a handle reference in this event */
++                      ++found_events;
++                      tevp->te_flags |= DM_TEF_FLUSH;
++
++                      /* Set the reply value, unless dm_get_events is
++                         already on this one.
++                       */
++                      if (! (tevp->te_flags & DM_TEF_LOCKED))
++                              tevp->te_reply = errno;
++
++                      /* If it is on the sn_evt_writerq or is being
++                         used by dm_get_events then we're done with it.
++                      */
++                      if (is_writerq || (tevp->te_flags & DM_TEF_LOCKED)) {
++                              nested_spinunlock(&tevp->te_lock);
++                              continue;
++                      }
++
++                      /* If there is a thread waiting on a synchronous
++                         event then be like dm_respond_event.
++                      */
++
++                      if ((tevp->te_evt_ref) &&
++                          (tevp->te_msg.ev_token != DM_INVALID_TOKEN)) {
++
++                              tevp->te_flags |= DM_TEF_FINAL;
++                              dm_unlink_event(tevp, queue);
++                              if (tevp->te_flags & DM_TEF_HASHED)
++                                      unhash_event(s, tevp);
++                              sv_broadcast(&tevp->te_evt_queue);
++                              nested_spinunlock(&tevp->te_lock);
++                              dm_put_tevp(tevp, NULL);
++                              continue;
++                      }
++              }
++              nested_spinunlock(&tevp->te_lock);
++      }
++
++      return(found_events);
++}
++
++
++/* If inode is non-null then find any threads that have a reference to that
++ * inode and flush them with the specified errno.
++ * Otherwise,if inode is null, then find any threads that have a reference
++ * to that sb and flush them with the specified errno.
++ * We look for these threads in each session's sn_evt_writerq, sn_newq,
++ * and sn_delq.
++ */
++int
++dm_release_threads(
++      struct super_block      *sb,
++      struct inode            *inode, /* may be null */
++      int                     errno)
++{
++      dm_sessid_t     sid;
++      dm_session_t    *s;
++      unsigned long   lc;
++      u_int           sesscnt;
++      dm_sessid_t     *sidlist;
++      int             i;
++      int             found_events = 0;
++      dm_fsid_t       fsid;
++      struct filesystem_dmapi_operations *dops;
++
++      ASSERT(sb);
++      dops = dm_fsys_ops(sb);
++      ASSERT(dops);
++      dops->get_fsid(sb, &fsid);
++      dm_release_disp_threads(&fsid, inode, errno);
++
++      /* Loop until we can get the right amount of temp space, being careful
++         not to hold a mutex during the allocation.  Usually only one trip.
++      */
++
++      for (;;) {
++              lc = mutex_spinlock(&dm_session_lock);
++              sesscnt = dm_sessions_active;
++              mutex_spinunlock(&dm_session_lock, lc);
++
++              if (sesscnt == 0)
++                      return 0;
++
++              sidlist = kmalloc(sesscnt * sizeof(sid), GFP_KERNEL);
++
++              lc = mutex_spinlock(&dm_session_lock);
++              if (sesscnt == dm_sessions_active)
++                      break;
++
++              mutex_spinunlock(&dm_session_lock, lc);
++              kfree(sidlist);
++      }
++
++      for (i = 0, s = dm_sessions; i < sesscnt; i++, s = s->sn_next)
++              sidlist[i] = s->sn_sessid;
++
++      mutex_spinunlock(&dm_session_lock, lc);
++
++
++      for (i = 0; i < sesscnt; i++) {
++              sid = sidlist[i];
++              if( dm_find_session_and_lock( sid, &s, &lc ) == 0 ){
++                      found_events = dm_flush_events( s, &fsid, inode,
++                                                      &s->sn_evt_writerq, 1,
++                                                      errno );
++                      if (found_events)
++                              sv_broadcast(&s->sn_writerq);
++
++                      dm_flush_events(s, &fsid, inode, &s->sn_newq, 0, errno);
++                      dm_flush_events(s, &fsid, inode, &s->sn_delq, 0, errno);
++
++                      mutex_spinunlock( &s->sn_qlock, lc );
++              }
++      }
++      kfree(sidlist);
++
++      return 0;
++}
++#endif /* HAVE_DM_QUEUE_FLUSH */
+Index: linux-2.6.26/fs/dmapi/dmapi_sysent.c
+===================================================================
+--- /dev/null
++++ linux-2.6.26/fs/dmapi/dmapi_sysent.c
+@@ -0,0 +1,805 @@
++/*
++ * Copyright (c) 2000-2005 Silicon Graphics, Inc.  All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of version 2 of the GNU General Public License as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it would be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
++ *
++ * Further, this software is distributed without any warranty that it is
++ * free of the rightful claim of any third person regarding infringement
++ * or the like.        Any license provided herein, whether implied or
++ * otherwise, applies only to this software file.  Patent licenses, if
++ * any, provided herein do not apply to combinations of this program with
++ * other software, or any other product whatsoever.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write the Free Software Foundation, Inc., 59
++ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
++ *
++ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
++ * Mountain View, CA  94043, or:
++ *
++ * http://www.sgi.com
++ *
++ * For further information regarding this notice, see:
++ *
++ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
++ */
++
++/* Data Migration API (DMAPI)
++ */
++
++
++/* We're using MISC_MAJOR / MISC_DYNAMIC_MINOR. */
++
++#include <linux/version.h>
++#include <linux/kernel.h>
++#include <linux/miscdevice.h>
++#include <linux/major.h>
++#include <linux/init.h>
++#include <linux/proc_fs.h>
++#include <linux/module.h>
++#include <linux/smp_lock.h>
++
++#include <asm/uaccess.h>
++
++#include "dmapi.h"
++#include "dmapi_kern.h"
++#include "dmapi_private.h"
++
++struct kmem_cache     *dm_fsreg_cachep = NULL;
++struct kmem_cache     *dm_tokdata_cachep = NULL;
++struct kmem_cache     *dm_session_cachep = NULL;
++struct kmem_cache     *dm_fsys_map_cachep = NULL;
++struct kmem_cache     *dm_fsys_vptr_cachep = NULL;
++
++static int
++dmapi_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
++          unsigned long arg)
++{
++      sys_dmapi_args_t kargs;
++      sys_dmapi_args_t *uap = &kargs;
++      int error = 0;
++      int rvp = -ENOSYS;
++      int use_rvp = 0;
++
++      if (!capable(CAP_MKNOD))
++              return -EPERM;
++
++      if( copy_from_user( &kargs, (sys_dmapi_args_t __user *)arg,
++                         sizeof(sys_dmapi_args_t) ) )
++              return -EFAULT;
++
++      unlock_kernel();
++
++      switch (cmd) {
++      case DM_CLEAR_INHERIT:
++              error = dm_clear_inherit(
++                              (dm_sessid_t)   DM_Uarg(uap,1), /* sid */
++                              (void __user *) DM_Parg(uap,2), /* hanp */
++                              (size_t)        DM_Uarg(uap,3), /* hlen */
++                              (dm_token_t)    DM_Uarg(uap,4), /* token */
++                              (dm_attrname_t __user *) DM_Parg(uap,5));/* attrnamep */
++              break;
++      case DM_CREATE_BY_HANDLE:
++              error = dm_create_by_handle(
++                              (dm_sessid_t)   DM_Uarg(uap,1), /* sid */
++                              (void __user *) DM_Parg(uap,2), /* dirhanp */
++                              (size_t)        DM_Uarg(uap,3), /* dirhlen */
++                              (dm_token_t)    DM_Uarg(uap,4), /* token */
++                              (void __user *) DM_Parg(uap,5), /* hanp */
++                              (size_t)        DM_Uarg(uap,6), /* hlen */
++                              (char __user *) DM_Parg(uap,7));/* cname */
++              break;
++      case DM_CREATE_SESSION:
++              error = dm_create_session(
++                              (dm_sessid_t)   DM_Uarg(uap,1), /* oldsid */
++                              (char __user *) DM_Parg(uap,2), /* sessinfop */
++                              (dm_sessid_t __user *) DM_Parg(uap,3));/* newsidp */
++              break;
++      case DM_CREATE_USEREVENT:
++              error = dm_create_userevent(
++                              (dm_sessid_t)   DM_Uarg(uap,1), /* sid */
++                              (size_t)        DM_Uarg(uap,2), /* msglen */
++                              (void __user *) DM_Parg(uap,3), /* msgdatap */
++                              (dm_token_t __user *) DM_Parg(uap,4));/* tokenp */
++              break;
++      case DM_DESTROY_SESSION:
++              error = dm_destroy_session(
++                              (dm_sessid_t)   DM_Uarg(uap,1));/* sid */
++              break;
++      case DM_DOWNGRADE_RIGHT:
++              error = dm_downgrade_right(
++                              (dm_sessid_t)   DM_Uarg(uap,1), /* sid */
++                              (void __user *) DM_Parg(uap,2), /* hanp */
++                              (size_t)        DM_Uarg(uap,3), /* hlen */
++                              (dm_token_t)    DM_Uarg(uap,4));/* token */
++              break;
++      case DM_FD_TO_HANDLE:
++              error = dm_fd_to_hdl(
++                              (int)           DM_Uarg(uap,1), /* fd */
++                              (void __user *) DM_Parg(uap,2), /* hanp */
++                              (size_t __user *) DM_Parg(uap,3));/* hlenp */
++              break;
++      case DM_FIND_EVENTMSG:
++              error = dm_find_eventmsg(
++                              (dm_sessid_t)   DM_Uarg(uap,1), /* sid */
++                              (dm_token_t)    DM_Uarg(uap,2), /* token */
++                              (size_t)        DM_Uarg(uap,3), /* buflen */
++                              (void __user *) DM_Parg(uap,4), /* bufp */
++                              (size_t __user *) DM_Parg(uap,5));/* rlenp */
++              break;
++      case DM_GET_ALLOCINFO:
++              use_rvp = 1;
++              error = dm_get_allocinfo_rvp(
++                              (dm_sessid_t)   DM_Uarg(uap,1), /* sid */
++                              (void __user *) DM_Parg(uap,2), /* hanp */
++                              (size_t)        DM_Uarg(uap,3), /* hlen */
++                              (dm_token_t)    DM_Uarg(uap,4), /* token */
++                              (dm_off_t __user *) DM_Parg(uap,5), /* offp */
++                              (u_int)         DM_Uarg(uap,6), /* nelem */
++                              (dm_extent_t __user *) DM_Parg(uap,7), /* extentp */
++                              (u_int __user *) DM_Parg(uap,8), /* nelemp */
++                                              &rvp);
++              break;
++      case DM_GET_BULKALL:
++              use_rvp = 1;
++              error = dm_get_bulkall_rvp(
++                              (dm_sessid_t)   DM_Uarg(uap,1), /* sid */
++                              (void __user *) DM_Parg(uap,2), /* hanp */
++                              (size_t)        DM_Uarg(uap,3), /* hlen */
++                              (dm_token_t)    DM_Uarg(uap,4), /* token */
++                              (u_int)         DM_Uarg(uap,5), /* mask */
++                              (dm_attrname_t __user *) DM_Parg(uap,6),/* attrnamep */
++                              (dm_attrloc_t __user *) DM_Parg(uap,7),/* locp */
++                              (size_t)        DM_Uarg(uap,8), /* buflen */
++                              (void __user *) DM_Parg(uap,9), /* bufp */
++                              (size_t __user *) DM_Parg(uap,10),/* rlenp */
++                                              &rvp);
++              break;
++      case DM_GET_BULKATTR:
++              use_rvp = 1;
++              error = dm_get_bulkattr_rvp(
++                              (dm_sessid_t)   DM_Uarg(uap,1), /* sid */
++                              (void __user *) DM_Parg(uap,2), /* hanp */
++                              (size_t)        DM_Uarg(uap,3), /* hlen */
++                              (dm_token_t)    DM_Uarg(uap,4), /* token */
++                              (u_int)         DM_Uarg(uap,5), /* mask */
++                              (dm_attrloc_t __user *)DM_Parg(uap,6), /* locp */
++                              (size_t)        DM_Uarg(uap,7), /* buflen */
++                              (void __user *) DM_Parg(uap,8), /* bufp */
++                              (size_t __user *) DM_Parg(uap,9), /* rlenp */
++                                              &rvp);
++              break;
++      case DM_GET_CONFIG:
++              error = dm_get_config(
++                              (void __user *) DM_Parg(uap,1), /* hanp */
++                              (size_t)        DM_Uarg(uap,2), /* hlen */
++                              (dm_config_t)   DM_Uarg(uap,3), /* flagname */
++                              (dm_size_t __user *)DM_Parg(uap,4));/* retvalp */
++              break;
++      case DM_GET_CONFIG_EVENTS:
++              error = dm_get_config_events(
++                              (void __user *) DM_Parg(uap,1), /* hanp */
++                              (size_t)        DM_Uarg(uap,2), /* hlen */
++                              (u_int)         DM_Uarg(uap,3), /* nelem */
++                              (dm_eventset_t __user *) DM_Parg(uap,4),/* eventsetp */
++                              (u_int __user *) DM_Parg(uap,5));/* nelemp */
++              break;
++      case DM_GET_DIOINFO:
++              error = dm_get_dioinfo(
++                              (dm_sessid_t)   DM_Uarg(uap,1), /* sid */
++                              (void __user *) DM_Parg(uap,2), /* hanp */
++                              (size_t)        DM_Uarg(uap,3), /* hlen */
++                              (dm_token_t)    DM_Uarg(uap,4), /* token */
++                              (dm_dioinfo_t __user *)DM_Parg(uap,5));/* diop */
++              break;
++      case DM_GET_DIRATTRS:
++              use_rvp = 1;
++              error = dm_get_dirattrs_rvp(
++                              (dm_sessid_t)   DM_Uarg(uap,1), /* sid */
++                              (void __user *) DM_Parg(uap,2), /* hanp */
++                              (size_t)        DM_Uarg(uap,3), /* hlen */
++                              (dm_token_t)    DM_Uarg(uap,4), /* token */
++                              (u_int)         DM_Uarg(uap,5), /* mask */
++                              (dm_attrloc_t __user *)DM_Parg(uap,6), /* locp */
++                              (size_t)        DM_Uarg(uap,7), /* buflen */
++                              (void __user *) DM_Parg(uap,8), /* bufp */
++                              (size_t __user *) DM_Parg(uap,9), /* rlenp */
++                                              &rvp);
++              break;
++      case DM_GET_DMATTR:
++              error = dm_get_dmattr(
++                              (dm_sessid_t)   DM_Uarg(uap,1), /* sid */
++                              (void __user *) DM_Parg(uap,2), /* hanp */
++                              (size_t)        DM_Uarg(uap,3), /* hlen */
++                              (dm_token_t)    DM_Uarg(uap,4), /* token */
++                              (dm_attrname_t __user *) DM_Parg(uap,5),/* attrnamep */
++                              (size_t)        DM_Uarg(uap,6), /* buflen */
++                              (void __user *) DM_Parg(uap,7), /* bufp */
++                              (size_t __user *)       DM_Parg(uap,8));/* rlenp */
++
++              break;
++      case DM_GET_EVENTLIST:
++              error = dm_get_eventlist(
++                              (dm_sessid_t)   DM_Uarg(uap,1), /* sid */
++                              (void __user *) DM_Parg(uap,2), /* hanp */
++                              (size_t)        DM_Uarg(uap,3), /* hlen */
++                              (dm_token_t)    DM_Uarg(uap,4), /* token */
++                              (u_int)         DM_Uarg(uap,5), /* nelem */
++                              (dm_eventset_t __user *) DM_Parg(uap,6),/* eventsetp */
++                              (u_int __user *) DM_Parg(uap,7));/* nelemp */
++              break;
++      case DM_GET_EVENTS:
++              error = dm_get_events(
++                              (dm_sessid_t)   DM_Uarg(uap,1), /* sid */
++                              (u_int)         DM_Uarg(uap,2), /* maxmsgs */
++                              (u_int)         DM_Uarg(uap,3), /* flags */
++                              (size_t)        DM_Uarg(uap,4), /* buflen */
++                              (void __user *) DM_Parg(uap,5), /* bufp */
++                              (size_t __user *) DM_Parg(uap,6));/* rlenp */
++              break;
++      case DM_GET_FILEATTR:
++              error = dm_get_fileattr(
++                              (dm_sessid_t)   DM_Uarg(uap,1), /* sid */
++                              (void __user *) DM_Parg(uap,2), /* hanp */
++                              (size_t)        DM_Uarg(uap,3), /* hlen */
++                              (dm_token_t)    DM_Uarg(uap,4), /* token */
++                              (u_int)         DM_Uarg(uap,5), /* mask */
++                              (dm_stat_t __user *) DM_Parg(uap,6));/* statp */
++              break;
++      case DM_GET_MOUNTINFO:
++              error = dm_get_mountinfo(
++                              (dm_sessid_t)   DM_Uarg(uap,1), /* sid */
++                              (void __user *) DM_Parg(uap,2), /* hanp */
++                              (size_t)        DM_Uarg(uap,3), /* hlen */
++                              (dm_token_t)    DM_Uarg(uap,4), /* token */
++                              (size_t)        DM_Uarg(uap,5), /* buflen */
++                              (void __user *) DM_Parg(uap,6), /* bufp */
++                              (size_t __user *) DM_Parg(uap,7));/* rlenp */
++              break;
++      case DM_GET_REGION:
++              error = dm_get_region(
++                              (dm_sessid_t)   DM_Uarg(uap,1), /* sid */
++                              (void __user *) DM_Parg(uap,2), /* hanp */
++                              (size_t)        DM_Uarg(uap,3), /* hlen */
++                              (dm_token_t)    DM_Uarg(uap,4), /* token */
++                              (u_int)         DM_Uarg(uap,5), /* nelem */
++                              (dm_region_t __user *) DM_Parg(uap,6), /* regbufp */
++                              (u_int __user *) DM_Parg(uap,7));/* nelemp */
++              break;
++      case DM_GETALL_DISP:
++              error = dm_getall_disp(
++                              (dm_sessid_t)   DM_Uarg(uap,1), /* sid */
++                              (size_t)        DM_Uarg(uap,2), /* buflen */
++                              (void __user *) DM_Parg(uap,3), /* bufp */
++                              (size_t __user *) DM_Parg(uap,4));/* rlenp */
++              break;
++      case DM_GETALL_DMATTR:
++              error = dm_getall_dmattr(
++                              (dm_sessid_t)   DM_Uarg(uap,1), /* sid */
++                              (void __user *) DM_Parg(uap,2), /* hanp */
++                              (size_t)        DM_Uarg(uap,3), /* hlen */
++                              (dm_token_t)    DM_Uarg(uap,4), /* token */
++                              (size_t)        DM_Uarg(uap,5), /* buflen */
++                              (void __user *) DM_Parg(uap,6), /* bufp */
++                              (size_t __user *) DM_Parg(uap,7));/* rlenp */
++              break;
++      case DM_GETALL_INHERIT:
++              error = dm_getall_inherit(
++                              (dm_sessid_t)   DM_Uarg(uap,1), /* sid */
++                              (void __user *) DM_Parg(uap,2), /* hanp */
++                              (size_t)        DM_Uarg(uap,3), /* hlen */
++                              (dm_token_t)    DM_Uarg(uap,4), /* token */
++                              (u_int)         DM_Uarg(uap,5), /* nelem */
++                              (dm_inherit_t __user *)DM_Parg(uap,6), /* inheritbufp*/
++                              (u_int __user *) DM_Parg(uap,7));/* nelemp */
++              break;
++      case DM_GETALL_SESSIONS:
++              error = dm_getall_sessions(
++                              (u_int)         DM_Uarg(uap,1), /* nelem */
++                              (dm_sessid_t __user *) DM_Parg(uap,2), /* sidbufp */
++                              (u_int __user *) DM_Parg(uap,3));/* nelemp */
++              break;
++      case DM_GETALL_TOKENS:
++              error = dm_getall_tokens(
++                              (dm_sessid_t)   DM_Uarg(uap,1), /* sid */
++                              (u_int)         DM_Uarg(uap,2), /* nelem */
++                              (dm_token_t __user *) DM_Parg(uap,3), /* tokenbufp */
++                              (u_int __user *) DM_Parg(uap,4));/* nelemp */
++              break;
++      case DM_INIT_ATTRLOC:
++              error = dm_init_attrloc(
++                              (dm_sessid_t)   DM_Uarg(uap,1), /* sid */
++                              (void __user *) DM_Parg(uap,2), /* hanp */
++                              (size_t)        DM_Uarg(uap,3), /* hlen */
++                              (dm_token_t)    DM_Uarg(uap,4), /* token */
++                              (dm_attrloc_t __user *) DM_Parg(uap,5));/* locp */
++              break;
++      case DM_MKDIR_BY_HANDLE:
++              error = dm_mkdir_by_handle(
++                              (dm_sessid_t)   DM_Uarg(uap,1), /* sid */
++                              (void __user *) DM_Parg(uap,2), /* dirhanp */
++                              (size_t)        DM_Uarg(uap,3), /* dirhlen */
++                              (dm_token_t)    DM_Uarg(uap,4), /* token */
++                              (void __user *) DM_Parg(uap,5), /* hanp */
++                              (size_t)        DM_Uarg(uap,6), /* hlen */
++                              (char __user *) DM_Parg(uap,7));/* cname */
++              break;
++      case DM_MOVE_EVENT:
++              error = dm_move_event(
++                              (dm_sessid_t)   DM_Uarg(uap,1), /* srcsid */
++                              (dm_token_t)    DM_Uarg(uap,2), /* token */
++                              (dm_sessid_t)   DM_Uarg(uap,3), /* targetsid */
++                              (dm_token_t __user *) DM_Parg(uap,4));/* rtokenp */
++              break;
++      case DM_OBJ_REF_HOLD:
++              error = dm_obj_ref_hold(
++                              (dm_sessid_t)   DM_Uarg(uap,1), /* sid */
++                              (dm_token_t)    DM_Uarg(uap,2), /* token */
++                              (void __user *) DM_Parg(uap,3), /* hanp */
++                              (size_t)        DM_Uarg(uap,4));/* hlen */
++              break;
++      case DM_OBJ_REF_QUERY:
++              use_rvp = 1;
++              error = dm_obj_ref_query_rvp(
++                              (dm_sessid_t)   DM_Uarg(uap,1), /* sid */
++                              (dm_token_t)    DM_Uarg(uap,2), /* token */
++                              (void __user *) DM_Parg(uap,3), /* hanp */
++                              (size_t)        DM_Uarg(uap,4), /* hlen */
++                                              &rvp);
++              break;
++      case DM_OBJ_REF_RELE:
++              error = dm_obj_ref_rele(
++                              (dm_sessid_t)   DM_Uarg(uap,1), /* sid */
++                              (dm_token_t)    DM_Uarg(uap,2), /* token */
++                              (void __user *) DM_Parg(uap,3), /* hanp */
++                              (size_t)        DM_Uarg(uap,4));/* hlen */
++              break;
++      case DM_PATH_TO_FSHANDLE:
++              error = dm_path_to_fshdl(
++                              (char __user *) DM_Parg(uap,1), /* path */
++                              (void __user *) DM_Parg(uap,2), /* hanp */
++                              (size_t __user *) DM_Parg(uap,3));/* hlenp */
++              break;
++      case DM_PATH_TO_HANDLE:
++              error = dm_path_to_hdl(
++                              (char __user *) DM_Parg(uap,1), /* path */
++                              (void __user *) DM_Parg(uap,2), /* hanp */
++                              (size_t __user *) DM_Parg(uap,3));/* hlenp */
++              break;
++      case DM_PENDING:
++              error = dm_pending(
++                              (dm_sessid_t)   DM_Uarg(uap,1), /* sid */
++                              (dm_token_t)    DM_Uarg(uap,2), /* token */
++                              (dm_timestruct_t __user *) DM_Parg(uap,3));/* delay */
++              break;
++      case DM_PROBE_HOLE:
++              error = dm_probe_hole(
++                              (dm_sessid_t)   DM_Uarg(uap,1), /* sid */
++                              (void __user *) DM_Parg(uap,2), /* hanp */
++                              (size_t)        DM_Uarg(uap,3), /* hlen */
++                              (dm_token_t)    DM_Uarg(uap,4), /* token */
++                              (dm_off_t)      DM_Uarg(uap,5), /* off */
++                              (dm_size_t)     DM_Uarg(uap,6), /* len */
++                              (dm_off_t __user *) DM_Parg(uap,7), /* roffp */
++                              (dm_size_t __user *) DM_Parg(uap,8));/* rlenp */
++              break;
++      case DM_PUNCH_HOLE:
++              error = dm_punch_hole(
++                              (dm_sessid_t)   DM_Uarg(uap,1), /* sid */
++                              (void __user *) DM_Parg(uap,2), /* hanp */
++                              (size_t)        DM_Uarg(uap,3), /* hlen */
++                              (dm_token_t)    DM_Uarg(uap,4), /* token */
++                              (dm_off_t)      DM_Uarg(uap,5), /* off */
++                              (dm_size_t)     DM_Uarg(uap,6));/* len */
++              break;
++      case DM_QUERY_RIGHT:
++              error = dm_query_right(
++                              (dm_sessid_t)   DM_Uarg(uap,1), /* sid */
++                              (void __user *) DM_Parg(uap,2), /* hanp */
++                              (size_t)        DM_Uarg(uap,3), /* hlen */
++                              (dm_token_t)    DM_Uarg(uap,4), /* token */
++                              (dm_right_t __user *) DM_Parg(uap,5));/* rightp */
++              break;
++      case DM_QUERY_SESSION:
++              error = dm_query_session(
++                              (dm_sessid_t)   DM_Uarg(uap,1), /* sid */
++                              (size_t)        DM_Uarg(uap,2), /* buflen */
++                              (void __user *) DM_Parg(uap,3), /* bufp */
++                              (size_t __user *) DM_Parg(uap,4));/* rlenp */
++              break;
++      case DM_READ_INVIS:
++              use_rvp = 1;
++              error = dm_read_invis_rvp(
++                              (dm_sessid_t)   DM_Uarg(uap,1), /* sid */
++                              (void __user *) DM_Parg(uap,2), /* hanp */
++                              (size_t)        DM_Uarg(uap,3), /* hlen */
++                              (dm_token_t)    DM_Uarg(uap,4), /* token */
++                              (dm_off_t)      DM_Uarg(uap,5), /* off */
++                              (dm_size_t)     DM_Uarg(uap,6), /* len */
++                              (void __user *) DM_Parg(uap,7), /* bufp */
++                                              &rvp);
++              break;
++      case DM_RELEASE_RIGHT:
++              error = dm_release_right(
++                              (dm_sessid_t)   DM_Uarg(uap,1), /* sid */
++                              (void __user *) DM_Parg(uap,2), /* hanp */
++                              (size_t)        DM_Uarg(uap,3), /* hlen */
++                              (dm_token_t)    DM_Uarg(uap,4));/* token */
++              break;
++      case DM_REMOVE_DMATTR:
++              error = dm_remove_dmattr(
++                              (dm_sessid_t)   DM_Uarg(uap,1), /* sid */
++                              (void __user *) DM_Parg(uap,2), /* hanp */
++                              (size_t)        DM_Uarg(uap,3), /* hlen */
++                              (dm_token_t)    DM_Uarg(uap,4), /* token */
++                              (int)           DM_Uarg(uap,5), /* setdtime */
++                              (dm_attrname_t __user *) DM_Parg(uap,6));/* attrnamep */
++              break;
++      case DM_REQUEST_RIGHT:
++              error = dm_request_right(
++                              (dm_sessid_t)   DM_Uarg(uap,1), /* sid */
++                              (void __user *) DM_Parg(uap,2), /* hanp */
++                              (size_t)        DM_Uarg(uap,3), /* hlen */
++                              (dm_token_t)    DM_Uarg(uap,4), /* token */
++                              (u_int)         DM_Uarg(uap,5), /* flags */
++                              (dm_right_t)    DM_Uarg(uap,6));/* right */
++              break;
++      case DM_RESPOND_EVENT:
++              error = dm_respond_event(
++                              (dm_sessid_t)   DM_Uarg(uap,1), /* sid */
++                              (dm_token_t)    DM_Uarg(uap,2), /* token */
++                              (dm_response_t) DM_Uarg(uap,3), /* response */
++                              (int)           DM_Uarg(uap,4), /* reterror */
++                              (size_t)        DM_Uarg(uap,5), /* buflen */
++                              (void __user *) DM_Parg(uap,6));/* respbufp */
++              break;
++      case DM_SEND_MSG:
++              error = dm_send_msg(
++                              (dm_sessid_t)   DM_Uarg(uap,1), /* targetsid */
++                              (dm_msgtype_t)  DM_Uarg(uap,2), /* msgtype */
++                              (size_t)        DM_Uarg(uap,3), /* buflen */
++                              (void __user *) DM_Parg(uap,4));/* bufp */
++              break;
++      case DM_SET_DISP:
++              error = dm_set_disp(
++                              (dm_sessid_t)   DM_Uarg(uap,1), /* sid */
++                              (void __user *) DM_Parg(uap,2), /* hanp */
++                              (size_t)        DM_Uarg(uap,3), /* hlen */
++                              (dm_token_t)    DM_Uarg(uap,4), /* token */
++                              (dm_eventset_t __user *) DM_Parg(uap,5),/* eventsetp */
++                              (u_int)         DM_Uarg(uap,6));/* maxevent */
++              break;
++      case DM_SET_DMATTR:
++              error = dm_set_dmattr(
++                              (dm_sessid_t)   DM_Uarg(uap,1), /* sid */
++                              (void __user *) DM_Parg(uap,2), /* hanp */
++                              (size_t)        DM_Uarg(uap,3), /* hlen */
++                              (dm_token_t)    DM_Uarg(uap,4), /* token */
++                              (dm_attrname_t __user *) DM_Parg(uap,5),/* attrnamep */
++                              (int)           DM_Uarg(uap,6), /* setdtime */
++                              (size_t)        DM_Uarg(uap,7), /* buflen */
++                              (void __user *) DM_Parg(uap,8));/* bufp */
++              break;
++      case DM_SET_EVENTLIST:
++              error = dm_set_eventlist(
++                              (dm_sessid_t)   DM_Uarg(uap,1), /* sid */
++                              (void __user *) DM_Parg(uap,2), /* hanp */
++                              (size_t)        DM_Uarg(uap,3), /* hlen */
++                              (dm_token_t)    DM_Uarg(uap,4), /* token */
++                              (dm_eventset_t __user *) DM_Parg(uap,5),/* eventsetp */
++                              (u_int)         DM_Uarg(uap,6));/* maxevent */
++              break;
++      case DM_SET_FILEATTR:
++              error = dm_set_fileattr(
++                              (dm_sessid_t)   DM_Uarg(uap,1), /* sid */
++                              (void __user *) DM_Parg(uap,2), /* hanp */
++                              (size_t)        DM_Uarg(uap,3), /* hlen */
++                              (dm_token_t)    DM_Uarg(uap,4), /* token */
++                              (u_int)         DM_Uarg(uap,5), /* mask */
++                              (dm_fileattr_t __user *)DM_Parg(uap,6));/* attrp */
++              break;
++      case DM_SET_INHERIT:
++              error = dm_set_inherit(
++                              (dm_sessid_t)   DM_Uarg(uap,1), /* sid */
++                              (void __user *) DM_Parg(uap,2), /* hanp */
++                              (size_t)        DM_Uarg(uap,3), /* hlen */
++                              (dm_token_t)    DM_Uarg(uap,4), /* token */
++                              (dm_attrname_t __user *)DM_Parg(uap,5),/* attrnamep */
++                              (mode_t)        DM_Uarg(uap,6));/* mode */
++              break;
++      case DM_SET_REGION:
++              error = dm_set_region(
++                              (dm_sessid_t)   DM_Uarg(uap,1), /* sid */
++                              (void __user *) DM_Parg(uap,2), /* hanp */
++                              (size_t)        DM_Uarg(uap,3), /* hlen */
++                              (dm_token_t)    DM_Uarg(uap,4), /* token */
++                              (u_int)         DM_Uarg(uap,5), /* nelem */
++                              (dm_region_t __user *) DM_Parg(uap,6), /* regbufp */
++                              (dm_boolean_t __user *) DM_Parg(uap,7));/* exactflagp */
++              break;
++      case DM_SET_RETURN_ON_DESTROY:
++              error = dm_set_return_on_destroy(
++                              (dm_sessid_t)   DM_Uarg(uap,1), /* sid */
++                              (void __user *) DM_Parg(uap,2), /* hanp */
++                              (size_t)        DM_Uarg(uap,3), /* hlen */
++                              (dm_token_t)    DM_Uarg(uap,4), /* token */
++                              (dm_attrname_t __user *) DM_Parg(uap,5),/* attrnamep */
++                              (dm_boolean_t)  DM_Uarg(uap,6));/* enable */
++              break;
++      case DM_SYMLINK_BY_HANDLE:
++              error = dm_symlink_by_handle(
++                              (dm_sessid_t)   DM_Uarg(uap,1), /* sid */
++                              (void __user *) DM_Parg(uap,2), /* dirhanp */
++                              (size_t)        DM_Uarg(uap,3), /* dirhlen */
++                              (dm_token_t)    DM_Uarg(uap,4), /* token */
++                              (void __user *) DM_Parg(uap,5), /* hanp */
++                              (size_t)        DM_Uarg(uap,6), /* hlen */
++                              (char __user *) DM_Parg(uap,7), /* cname */
++                              (char __user *) DM_Parg(uap,8));/* path */
++              break;
++      case DM_SYNC_BY_HANDLE:
++              error = dm_sync_by_handle(
++                              (dm_sessid_t)   DM_Uarg(uap,1), /* sid */
++                              (void __user *) DM_Parg(uap,2), /* hanp */
++                              (size_t)        DM_Uarg(uap,3), /* hlen */
++                              (dm_token_t)    DM_Uarg(uap,4));/* token */
++              break;
++      case DM_UPGRADE_RIGHT:
++              error = dm_upgrade_right(
++                              (dm_sessid_t)   DM_Uarg(uap,1), /* sid */
++                              (void __user *) DM_Parg(uap,2), /* hanp */
++                              (size_t)        DM_Uarg(uap,3), /* hlen */
++                              (dm_token_t)    DM_Uarg(uap,4));/* token */
++              break;
++      case DM_WRITE_INVIS:
++              use_rvp = 1;
++              error = dm_write_invis_rvp(
++                              (dm_sessid_t)   DM_Uarg(uap,1), /* sid */
++                              (void __user *) DM_Parg(uap,2), /* hanp */
++                              (size_t)        DM_Uarg(uap,3), /* hlen */
++                              (dm_token_t)    DM_Uarg(uap,4), /* token */
++                              (int)           DM_Uarg(uap,5), /* flags */
++                              (dm_off_t)      DM_Uarg(uap,6), /* off */
++                              (dm_size_t)     DM_Uarg(uap,7), /* len */
++                              (void __user *) DM_Parg(uap,8), /* bufp */
++                                              &rvp);
++              break;
++      case DM_OPEN_BY_HANDLE:
++              use_rvp = 1;
++              error = dm_open_by_handle_rvp(
++                              (unsigned int)  DM_Uarg(uap,1), /* fd */
++                              (void __user *) DM_Parg(uap,2), /* hanp */
++                              (size_t)        DM_Uarg(uap,3), /* hlen */
++                              (int)           DM_Uarg(uap,4), /* flags */
++                                              &rvp);
++              break;
++      default:
++              error = -ENOSYS;
++              break;
++      }
++
++      lock_kernel();
++
++      /* If it was an *_rvp() function, then
++              if error==0, return |rvp|
++      */
++      if( use_rvp && (error == 0) )
++              return rvp;
++      else
++              return error;
++}
++
++
++
++static int
++dmapi_open(struct inode *inode, struct file *file)
++{
++      return 0;
++}
++
++
++static int
++dmapi_release(struct inode *inode, struct file *file)
++{
++      return 0;
++}
++
++
++/* say hello, and let me know the device is hooked up */
++static ssize_t
++dmapi_dump(struct file *file, char __user *buf, size_t count, loff_t *ppos)
++{
++      char tmp[50];
++      int len;
++      if( *ppos == 0 ){
++              len = sprintf( tmp, "# " DM_VER_STR_CONTENTS "\n" );
++              if( copy_to_user(buf, tmp, len) )
++                      return -EFAULT;
++              *ppos += 1;
++              return len;
++      }
++      return 0;
++}
++
++static struct file_operations dmapi_fops = {
++      .open           = dmapi_open,
++      .ioctl          = dmapi_ioctl,
++      .read           = dmapi_dump,
++      .release        = dmapi_release
++};
++
++static struct miscdevice dmapi_dev = {
++      .minor          = MISC_DYNAMIC_MINOR,
++      .name           = "dmapi",
++      .fops           = &dmapi_fops
++};
++
++
++
++#ifdef CONFIG_PROC_FS
++static int
++dmapi_summary(char *buffer, char **start, off_t offset,
++               int count, int *eof, void *data)
++{
++      int len;
++
++      extern u_int dm_sessions_active;
++      extern dm_sessid_t dm_next_sessid;
++      extern dm_token_t dm_next_token;
++      extern dm_sequence_t dm_next_sequence;
++      extern int dm_fsys_cnt;
++
++#define CHKFULL if(len >= count) break;
++#define ADDBUF(a,b)   len += sprintf(buffer + len, a, b); CHKFULL;
++
++      len=0;
++      while(1){
++              ADDBUF("dm_sessions_active=%u\n", dm_sessions_active);
++              ADDBUF("dm_next_sessid=%d\n", (int)dm_next_sessid);
++              ADDBUF("dm_next_token=%d\n", (int)dm_next_token);
++              ADDBUF("dm_next_sequence=%u\n", (u_int)dm_next_sequence);
++              ADDBUF("dm_fsys_cnt=%d\n", dm_fsys_cnt);
++
++              break;
++      }
++
++      if (offset >= len) {
++              *start = buffer;
++              *eof = 1;
++              return 0;
++      }
++      *start = buffer + offset;
++      if ((len -= offset) > count)
++              return count;
++      *eof = 1;
++
++      return len;
++}
++#endif
++
++
++static void __init
++dmapi_init_procfs(int dmapi_minor)
++{
++#ifdef CONFIG_PROC_FS
++      struct proc_dir_entry *entry;
++
++      if ((entry = proc_mkdir( DMAPI_DBG_PROCFS, NULL)) == NULL )
++              return;
++      entry->owner = THIS_MODULE;
++      entry->mode = S_IFDIR | S_IRUSR | S_IXUSR;
++
++      if ((entry = proc_mkdir( DMAPI_DBG_PROCFS "/fsreg", NULL)) == NULL )
++              return;
++      entry->owner = THIS_MODULE;
++
++      if ((entry = proc_mkdir( DMAPI_DBG_PROCFS "/sessions", NULL)) == NULL )
++              return;
++      entry->owner = THIS_MODULE;
++
++      entry = create_proc_read_entry( DMAPI_DBG_PROCFS "/summary",
++                      0, NULL, dmapi_summary, NULL);
++      entry->owner = THIS_MODULE;
++#endif
++}
++
++#if 0
++static void __exit
++dmapi_cleanup_procfs(void)
++{
++#ifdef CONFIG_PROC_FS
++      remove_proc_entry( DMAPI_DBG_PROCFS "/summary", NULL);
++      remove_proc_entry( DMAPI_DBG_PROCFS "/fsreg", NULL);
++      remove_proc_entry( DMAPI_DBG_PROCFS "/sessions", NULL);
++      remove_proc_entry( DMAPI_DBG_PROCFS, NULL);
++#endif
++}
++#endif
++
++int __init dmapi_init(void)
++{
++      int ret;
++
++      dm_tokdata_cachep = kmem_cache_create("dm_tokdata",
++                              sizeof(struct dm_tokdata), 0, 0, NULL);
++      if (dm_tokdata_cachep == NULL)
++              goto out;
++
++      dm_fsreg_cachep = kmem_cache_create("dm_fsreg",
++                              sizeof(struct dm_fsreg), 0, 0, NULL);
++      if (dm_fsreg_cachep == NULL)
++              goto out_free_tokdata_cachep;
++
++      dm_session_cachep = kmem_cache_create("dm_session",
++                              sizeof(struct dm_session), 0, 0, NULL);
++      if (dm_session_cachep == NULL)
++              goto out_free_fsreg_cachep;
++
++      dm_fsys_map_cachep = kmem_cache_create("dm_fsys_map",
++                              sizeof(dm_vector_map_t), 0, 0, NULL);
++      if (dm_fsys_map_cachep == NULL)
++              goto out_free_session_cachep;
++      dm_fsys_vptr_cachep = kmem_cache_create("dm_fsys_vptr",
++                              sizeof(dm_fsys_vector_t), 0, 0, NULL);
++      if (dm_fsys_vptr_cachep == NULL)
++              goto out_free_fsys_map_cachep;
++
++      ret = misc_register(&dmapi_dev);
++      if (ret) {
++              printk(KERN_ERR "dmapi_init: misc_register returned %d\n", ret);
++              goto out_free_fsys_vptr_cachep;
++      }
++
++      dmapi_init_procfs(dmapi_dev.minor);
++      return 0;
++
++ out_free_fsys_vptr_cachep:
++      kmem_cache_destroy(dm_fsys_vptr_cachep);
++ out_free_fsys_map_cachep:
++      kmem_cache_destroy(dm_fsys_map_cachep);
++ out_free_session_cachep:
++      kmem_cache_destroy(dm_session_cachep);
++ out_free_fsreg_cachep:
++      kmem_cache_destroy(dm_fsreg_cachep);
++ out_free_tokdata_cachep:
++      kmem_cache_destroy(dm_tokdata_cachep);
++ out:
++      return -ENOMEM;
++}
++
++#if 0
++void __exit dmapi_uninit(void)
++{
++      misc_deregister(&dmapi_dev);
++      dmapi_cleanup_procfs();
++      kmem_cache_destroy(dm_tokdata_cachep);
++      kmem_cache_destroy(dm_fsreg_cachep);
++      kmem_cache_destroy(dm_session_cachep);
++      kmem_cache_destroy(dm_fsys_map_cachep);
++      kmem_cache_destroy(dm_fsys_vptr_cachep);
++}
++#endif
++
++module_init(dmapi_init);
++/*module_exit(dmapi_uninit);*/ /* Some other day */
++
++MODULE_AUTHOR("Silicon Graphics, Inc.");
++MODULE_DESCRIPTION("SGI Data Migration Subsystem");
++MODULE_LICENSE("GPL");
++
++EXPORT_SYMBOL(dm_send_mount_event);
++EXPORT_SYMBOL(dm_send_namesp_event);
++EXPORT_SYMBOL(dm_send_unmount_event);
++EXPORT_SYMBOL(dm_send_data_event);
++EXPORT_SYMBOL(dm_send_destroy_event);
++EXPORT_SYMBOL(dm_ip_to_handle);
++EXPORT_SYMBOL(dmapi_register);
++EXPORT_SYMBOL(dmapi_unregister);
++EXPORT_SYMBOL(dmapi_registered);
++EXPORT_SYMBOL(dm_release_threads);
+Index: linux-2.6.26/fs/dmapi/Makefile
+===================================================================
+--- /dev/null
++++ linux-2.6.26/fs/dmapi/Makefile
+@@ -0,0 +1,53 @@
++#
++# Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
++#
++# This program is free software; you can redistribute it and/or modify it
++# under the terms of version 2 of the GNU General Public License as
++# published by the Free Software Foundation.
++#
++# This program is distributed in the hope that it would be useful, but
++# WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
++#
++# Further, this software is distributed without any warranty that it is
++# free of the rightful claim of any third person regarding infringement
++# or the like.        Any license provided herein, whether implied or
++# otherwise, applies only to this software file.  Patent licenses, if
++# any, provided herein do not apply to combinations of this program with
++# other software, or any other product whatsoever.
++#
++# You should have received a copy of the GNU General Public License along
++# with this program; if not, write the Free Software Foundation, Inc., 59
++# Temple Place - Suite 330, Boston MA 02111-1307, USA.
++#
++# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
++# Mountain View, CA  94043, or:
++#
++# http://www.sgi.com
++#
++# For further information regarding this notice, see:
++#
++# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
++#
++
++ifeq ($(CONFIG_DMAPI_DEBUG),y)
++      EXTRA_CFLAGS += -DDEBUG
++      EXTRA_CFLAGS += -g
++endif
++
++obj-$(CONFIG_DMAPI)           += dmapi.o
++
++dmapi-y                               += dmapi_sysent.o \
++                                 dmapi_attr.o \
++                                 dmapi_config.o \
++                                 dmapi_bulkattr.o \
++                                 dmapi_dmattr.o \
++                                 dmapi_event.o \
++                                 dmapi_handle.o \
++                                 dmapi_hole.o \
++                                 dmapi_io.o \
++                                 dmapi_mountinfo.o \
++                                 dmapi_region.o \
++                                 dmapi_register.o \
++                                 dmapi_right.o \
++                                 dmapi_session.o
+Index: linux-2.6.26/fs/dmapi/Status
+===================================================================
+--- /dev/null
++++ linux-2.6.26/fs/dmapi/Status
+@@ -0,0 +1,128 @@
++Jan21,04 - dm_get_bulkall is now implemented.  roehrich
++
++for linux:
++
++
++68 external interfaces in libdm
++
++   56 of those interfaces go through to dmi(), the kernel side of DMAPI
++
++
++
++Functions known to work
++----------------------------------------------
++
++dm_create_session
++dm_create_userevent
++dm_destroy_session
++dm_getall_sessions
++dm_getall_tokens
++dm_get_allocinfo
++dm_get_bulkall
++dm_get_bulkattr
++dm_get_config_events
++dm_get_dmattr
++dm_get_eventlist
++dm_get_events
++dm_get_fileattr
++dm_get_region
++dm_handle_free
++dm_init_attrloc
++dm_init_service
++dm_obj_ref_hold
++dm_obj_ref_query
++dm_obj_ref_rele
++dm_path_to_fshandle
++dm_path_to_handle
++dm_punch_hole
++dm_query_session
++dm_read_invis
++dm_remove_dmattr
++dm_respond_event
++dm_send_msg
++dm_set_disp
++dm_set_dmattr
++dm_set_eventlist
++dm_set_fileattr
++dm_set_region
++dm_sync_by_handle
++dm_write_invis
++35
++
++Functions that seem to work (would like more rigorous test case)
++------------------------------------------
++
++dm_pending
++dm_probe_hole         - one test case of test_hole.c fails
++dm_request_right
++3
++
++Functions untested but probably work
++----------------------------------------------
++
++dm_find_eventmsg
++dm_handle_cmp
++dm_handle_to_fshandle
++dm_handle_to_ino
++dm_release_right
++5
++
++Functions that do not work
++-----------------------------------------
++
++dm_get_dioinfo                - directio not implemented
++1
++
++Functions not supported in SGI DMAPI
++-------------------------------------------------------------
++
++dm_clear_inherit
++dm_create_by_handle
++dm_getall_inherit
++dm_mkdir_by_handle
++dm_set_inherit
++dm_symlink_by_handle
++
++
++
++
++Functions that seem to work (would like more rigorous test case)
++----------------------------------------------------------------
++
++dm_get_config
++dm_downgrade_right
++dm_get_mountinfo
++dm_set_return_on_destory
++dm_upgrade_right
++
++
++
++Functions that do not work
++-----------------------------------------------------------------
++
++dm_fd_to_handle               - Irix getf not implemented on linux
++dm_get_dirattrs               - null pointer reference
++dm_handle_to_path
++dm_getall_dmattr      - needs a copy_from_user in place of useracc
++
++
++Functions that are untested, but probably work
++-----------------------------------------------------------------
++
++dm_getall_disp
++dm_handle_hash
++dm_handle_is_valid
++dm_handle_to_fsid
++dm_handle_to_igen
++dm_make_fshandle
++dm_make_handle
++dm_move_event
++dm_query_right
++
++
++
++Other things not working
++----------------------------------
++
++- read/write events for memory-mapped I/O?
++
+Index: linux-2.6.26/fs/dmapi/sv.h
+===================================================================
+--- /dev/null
++++ linux-2.6.26/fs/dmapi/sv.h
+@@ -0,0 +1,89 @@
++/*
++ * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of version 2 of the GNU General Public License as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it would be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
++ *
++ * Further, this software is distributed without any warranty that it is
++ * free of the rightful claim of any third person regarding infringement
++ * or the like.  Any license provided herein, whether implied or
++ * otherwise, applies only to this software file.  Patent licenses, if
++ * any, provided herein do not apply to combinations of this program with
++ * other software, or any other product whatsoever.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write the Free Software Foundation, Inc., 59
++ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
++ *
++ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
++ * Mountain View, CA  94043, or:
++ *
++ * http://www.sgi.com
++ *
++ * For further information regarding this notice, see:
++ *
++ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
++ */
++#ifndef __DMAPI_SV_H__
++#define __DMAPI_SV_H__
++
++#include <linux/wait.h>
++#include <linux/sched.h>
++#include <linux/spinlock.h>
++
++/*
++ * Synchronisation variables.
++ *
++ * (Parameters "pri", "svf" and "rts" are not implemented)
++ */
++
++typedef struct sv_s {
++      wait_queue_head_t waiters;
++} sv_t;
++
++#define SV_FIFO               0x0             /* sv_t is FIFO type */
++#define SV_LIFO               0x2             /* sv_t is LIFO type */
++#define SV_PRIO               0x4             /* sv_t is PRIO type */
++#define SV_KEYED      0x6             /* sv_t is KEYED type */
++#define SV_DEFAULT      SV_FIFO
++
++
++static inline void _sv_wait(sv_t *sv, spinlock_t *lock, int state,
++                           unsigned long timeout)
++{
++      DECLARE_WAITQUEUE(wait, current);
++
++      add_wait_queue_exclusive(&sv->waiters, &wait);
++      __set_current_state(state);
++      spin_unlock(lock);
++
++      schedule_timeout(timeout);
++
++      remove_wait_queue(&sv->waiters, &wait);
++}
++
++#define init_sv(sv,type,name,flag) \
++      init_waitqueue_head(&(sv)->waiters)
++#define sv_init(sv,flag,name) \
++      init_waitqueue_head(&(sv)->waiters)
++#define sv_destroy(sv) \
++      /*NOTHING*/
++#define sv_wait(sv, pri, lock, s) \
++      _sv_wait(sv, lock, TASK_UNINTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT)
++#define sv_wait_sig(sv, pri, lock, s)   \
++      _sv_wait(sv, lock, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT)
++#define sv_timedwait(sv, pri, lock, s, svf, ts, rts) \
++      _sv_wait(sv, lock, TASK_UNINTERRUPTIBLE, timespec_to_jiffies(ts))
++#define sv_timedwait_sig(sv, pri, lock, s, svf, ts, rts) \
++      _sv_wait(sv, lock, TASK_INTERRUPTIBLE, timespec_to_jiffies(ts))
++#define sv_signal(sv) \
++      wake_up(&(sv)->waiters)
++#define sv_broadcast(sv) \
++      wake_up_all(&(sv)->waiters)
++
++#endif /* __DMAPI_SV_H__ */