/*
 * Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska Högskolan
 * (Royal Institute of Technology, Stockholm, Sweden).
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *      This product includes software developed by the Kungliga Tekniska
 *      Högskolan and its contributors.
 * 
 * 4. Neither the name of the Institute nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

/*
 * XFS operations.
 */

#include <xfs/xfs_locl.h>
#include <xfs/xfs_message.h>
#include <xfs/xfs_dev.h>
#include <xfs/xfs_common.h>
#include <xfs/xfs_fs.h>
#include <xfs/xfs_deb.h>
#include <xfs/xfs_syscalls.h>

RCSID("$Id: xfs_vnodeops.c,v 1.6 1999/02/01 00:13:52 assar Exp $");

static int
xfs_open_valid(struct vnode *vp, struct cred *cred, u_int tok)
{
  struct xfs *xfsp = XFS_FROM_VNODE(vp);
  struct xfs_node *xn = VNODE_TO_XNODE(vp);
  int error = 0;
  
  XFSDEB(XDEBVFOPS, ("xfs_open_valid\n"));

  do {
    if (!XFS_TOKEN_GOT(xn, tok))
      {
	struct xfs_message_open msg;

	msg.header.opcode = XFS_MSG_OPEN;
	msg.cred.uid = cred->cr_uid;
	msg.cred.pag = xfs_get_pag(cred);
	msg.handle = xn->handle;
	msg.tokens = tok;
	error = xfs_message_rpc(xfsp->fd, &msg.header, sizeof(msg));
	if (error == 0)
	  error = ((struct xfs_message_wakeup *) &msg)->error;
      }
    else
      {
	goto done;
      }
  } while (error == 0);

 done:
  return error;
}

static int
xfs_attr_valid(struct vnode *vp, struct cred *cred, u_int tok)
{
  struct xfs *xfsp = XFS_FROM_VNODE(vp);
  struct xfs_node *xn = VNODE_TO_XNODE(vp);
  int error = 0;
  
  pag_t pag = xfs_get_pag(cred);

  do {
    if (!XFS_TOKEN_GOT(xn, tok))
      {
	struct xfs_message_getattr msg;
	msg.header.opcode = XFS_MSG_GETATTR;
	msg.cred.uid = cred->cr_uid;
	msg.cred.pag = pag;
	msg.handle = xn->handle;
	error = xfs_message_rpc(xfsp->fd, &msg.header, sizeof(msg));
	if (error == 0)
	  error = ((struct xfs_message_wakeup *) &msg)->error;
      }
    else
      {
	goto done;
      }
  } while (error == 0);

 done:
  return error;
}

static int
xfs_fetch_rights(struct vnode *vp, struct cred *cred)
{
    struct xfs *xfsp = XFS_FROM_VNODE(vp);
    struct xfs_node *xn = VNODE_TO_XNODE(vp);
    int error = 0;

    pag_t pag = xfs_get_pag(cred);

    struct xfs_message_getattr msg;

    msg.header.opcode = XFS_MSG_GETATTR;
    msg.cred.uid = cred->cr_uid;
    msg.cred.pag = pag;
    msg.handle = xn->handle;
    error = xfs_message_rpc(xfsp->fd, &msg.header, sizeof(msg));
    if (error == 0)
	error = ((struct xfs_message_wakeup *) & msg)->error;

    return (error);
}

static int
xfs_data_valid(struct vnode *vp, struct cred *cred, u_int tok)
{
  struct xfs *xfsp = XFS_FROM_VNODE(vp);
  struct xfs_node *xn = VNODE_TO_XNODE(vp);
  int error = 0;
  
  do {
    if (!XFS_TOKEN_GOT(xn, tok))
      {
	struct xfs_message_getdata msg;
	msg.header.opcode = XFS_MSG_GETDATA;
	msg.cred.uid = cred->cr_uid;
	msg.cred.pag = xfs_get_pag(cred);
	msg.handle = xn->handle;
	msg.tokens = tok;
	error = xfs_message_rpc(xfsp->fd, &msg.header, sizeof(msg));
	if (error == 0)
	  error = ((struct xfs_message_wakeup *) &msg)->error;
      }
    else
      {
	goto done;
      }
  } while (error == 0);

 done:
  return error;
}

static int
do_fsync(struct xfs *xfsp,
	 struct xfs_node *xn,
	 struct cred *cred,
	 u_int flag)
{
    int error;
    struct xfs_message_putdata msg;

    msg.header.opcode = XFS_MSG_PUTDATA;
    msg.cred.uid = cred->cr_uid;
    msg.cred.pag = xfs_get_pag(cred);
    msg.handle = xn->handle;

    msg.flag = flag;
    error = xfs_message_rpc(xfsp->fd, &msg.header, sizeof(msg));
    if (error == 0)
	error = ((struct xfs_message_wakeup *) & msg)->error;

    if (error == 0)
	xn->flags &= ~XFS_DATA_DIRTY;

    return error;
}

static int
xfs_open_common(struct vnode **vpp,
		mode_t mode,
		struct cred *cred)
{
  int error = 0;
  
  XFSDEB(XDEBVNOPS, ("xfs_open\n"));
  
  if (mode & VWRITE)
    error = xfs_open_valid(*vpp, cred, XFS_OPEN_NW);
  else
    error = xfs_open_valid(*vpp, cred, XFS_OPEN_NR);
  
  return error;
}

static int
xfs_close_common(struct vnode *vp,
		 int flag,
		 lastclose_t lastclose,
		 off_t offset,
		 struct cred *cred)
{
  struct xfs *xfsp = XFS_FROM_VNODE(vp);
  struct xfs_node *xn = VNODE_TO_XNODE(vp);
  int error = 0;

  XFSDEB(XDEBVNOPS, ("xfs_close\n"));
  
  if (flag & FWRITE && xn->flags & XFS_DATA_DIRTY)
    error = do_fsync (xfsp, xn, cred, XFS_WRITE);
  
  return error;
}

static int
xfs_read_common(struct vnode *vp,
		struct uio *uio,
		int ioflag,
		struct cred *cred)
{
    int error = 0;

    XFSDEB(XDEBVNOPS, ("xfs_read\n"));

    error = xfs_data_valid(vp, cred, XFS_DATA_R);

    if (error == 0) {
	struct vnode *t = DATA_FROM_VNODE(vp);
	ASSERT(t != NULL);
	VOP_RWLOCK(t, 0);
#if IRIX_64
	VOP_READ(t, uio, ioflag, cred, NULL, error);
#else
	error = VOP_READ(t, uio, ioflag, cred);
#endif
	VOP_RWUNLOCK(t, 0);
    }

    return error;
}

static int
xfs_write_common(struct vnode *vp,
		 struct uio *uio,
		 int ioflag,
		 struct cred *cred)
{
    int error = 0;

    XFSDEB(XDEBVNOPS, ("xfs_write\n"));

    error = xfs_data_valid(vp, cred, XFS_DATA_W);

    if (error == 0) {
	struct xfs_node *xn = VNODE_TO_XNODE(vp);
	struct vnode *t = DATA_FROM_VNODE(vp);
	struct vattr sub_attr;
	int error2 = 0;

	ASSERT(t != NULL);
	VOP_RWLOCK(t, 1);
#if IRIX_64
	VOP_WRITE(t, uio, ioflag, cred, NULL, error);
	VOP_GETATTR(t, &sub_attr, 0, cred, error2);
#else
	error  = VOP_WRITE(t, uio, ioflag, cred);
	error2 = VOP_GETATTR(t, &sub_attr, 0, cred);
#endif
	VOP_RWUNLOCK(t, 1);
	VNODE_TO_XNODE(vp)->flags |= XFS_DATA_DIRTY;

	if (error2 == 0) {
	    xn->attr.va_size  = sub_attr.va_size;
	    xn->attr.va_mtime = sub_attr.va_mtime;
	}
    }

    return error;
}

static int
xfs_ioctl_common(struct vnode *vp,
		 int cmd,
		 void *arg,
		 int flag,
		 struct cred *cred,
		 int *result)
{
  XFSDEB(XDEBVNOPS, ("xfs_ioctl\n"));
  return ENOSYS;
}

static int
xfs_setfl_common(struct vnode *vp,
		 int oflags,
		 int nflags,
		 struct cred *cred)
{
  XFSDEB(XDEBVNOPS, ("xfs_setfl\n"));
  return fs_setfl (vp, oflags, nflags, cred);
}

static int
xfs_getattr_common(struct vnode *vp,
		   struct vattr *vap,
		   int flags,
		   struct cred *cred)     
{
  int error = 0;
  
  struct xfs_node *xn = VNODE_TO_XNODE(vp);

  XFSDEB(XDEBVNOPS, ("xfs_getattr\n"));
  
  error = xfs_attr_valid(vp, cred, XFS_ATTR_R);
  if (error == 0) {
      *vap = xn->attr;
  }
  
  return error;
}

static int
xfs_setattr_common(struct vnode *vp,
		   struct vattr *vap,
		   int flags,
		   struct cred *cred)
{
  struct xfs *xfsp = XFS_FROM_VNODE(vp);
  struct xfs_node *xn = VNODE_TO_XNODE(vp);
  int error = 0;
  
  XFSDEB(XDEBVNOPS, ("xfs_setattr\n"));
  if (XFS_TOKEN_GOT(xn, XFS_ATTR_W)) {
      /* Update attributes and mark them dirty. */
      VNODE_TO_XNODE(vp)->flags |= XFS_ATTR_DIRTY;
      error = ENOSYS;		/* XXX not yet implemented */
      goto done;
  } else {
      struct xfs_message_putattr msg;
      msg.header.opcode = XFS_MSG_PUTATTR;
      msg.cred.uid = cred->cr_uid;
      msg.cred.pag = xfs_get_pag(cred);
      msg.handle = xn->handle;
      vattr2xfs_attr (vap, &msg.attr);
      error = xfs_message_rpc(xfsp->fd, &msg.header, sizeof(msg));
      if (error == 0)
	error = ((struct xfs_message_wakeup *) &msg)->error;
      XFS_TOKEN_CLEAR(xn, XFS_ATTR_VALID, XFS_ATTR_MASK);
  }

 done:
  return error;
}

static int
check_rights (u_char rights, int mode)
{
    int error = 0;

    if (mode & VREAD)
	if ((rights & XFS_RIGHT_R) == 0)
	    error = EACCES;
    if (mode & VWRITE)
	if ((rights & XFS_RIGHT_W) == 0)
	    error = EACCES;
    if (mode & VEXEC)
	if ((rights & XFS_RIGHT_X) == 0)
	    error = EACCES;
    return error;
}

static int
xfs_access_common(struct vnode *vp,
		  int mode,
		  int flags,
		  struct cred *cred)     
{
  int error = 0;
  pag_t pag = xfs_get_pag(cred);

  XFSDEB(XDEBVNOPS, ("xfs_access mode = 0%o\n", mode));

  error = xfs_attr_valid(vp, cred, XFS_ATTR_R);
  if (error == 0) {
      struct xfs_node *xn = VNODE_TO_XNODE(vp);
      int i;

      error = check_rights (xn->anonrights, mode);
	
      if (error == 0)
	  goto done;

      XFSDEB(XDEBVNOPS, ("xfs_access anonaccess failed\n"));

      if (error != 0)
	  xfs_fetch_rights(vp, cred); /* ignore error */
	
      error = EACCES;
	
      for (i = 0; i < MAXRIGHTS; i++)
	  if (xn->id[i] == pag) {
	      error = check_rights (xn->rights[i], mode);
	      break;
	  }
  }

done:
    XFSDEB(XDEBVNOPS, ("xfs_access(0%o) = %d\n", mode, error));
    return error;

}

static int
xfs_lookup_common(struct vnode *dvp,
		  char *nm,
		  struct vnode **vpp,
		  struct pathname *pnp,
		  int flags,
		  struct vnode *rdir,
		  struct cred *cred)
{
  struct xfs_message_getnode msg;
  struct xfs *xfsp = XFS_FROM_VNODE(dvp);
  int error = 0;

  struct xfs_node *d = VNODE_TO_XNODE(dvp);
  struct vnode *v;
  
  XFSDEB(XDEBVNOPS, ("xfs_lookup\n"));
  
  do {
#ifdef notdef_but_correct
    error = xfs_access(dvp, VEXEC, cred);
    if (error != 0)
      goto done;
#endif
    v = xfs_dnlc_lookup(dvp, nm);
    if (!v)
      {
	msg.header.opcode = XFS_MSG_GETNODE;
	msg.cred.uid = cred->cr_uid;
	msg.cred.pag = xfs_get_pag(cred);
	msg.parent_handle = d->handle;
	strncpy(msg.name, nm, sizeof(msg.name));
	error = xfs_message_rpc(xfsp->fd, &msg.header, sizeof(msg));
	if (error == 0)
	  error = ((struct xfs_message_wakeup *) &msg)->error;
      }
    else
      {
	*vpp = v;
	VN_HOLD(v);
	goto done;
      }
  } while (error == 0);

 done:
  XFSDEB(XDEBVNOPS, ("xfs_lookup() = %d\n", error));
  return error;
}

static int
xfs_create_common(struct vnode *dvp,
		  char *nm,
		  struct vattr *va,
		  int exclusive,
		  int mode,
		  struct vnode **vpp,
		  struct cred *cred)     
{
  struct xfs *xfsp = XFS_FROM_VNODE(dvp);
  struct xfs_node *xn = VNODE_TO_XNODE(dvp);
  int error = 0;
  int do_trunc = 0;
  
  XFSDEB(XDEBVNOPS, ("xfs_create\n"));
  {
    struct xfs_message_create msg;
    msg.header.opcode = XFS_MSG_CREATE;
    msg.parent_handle = xn->handle;
    strncpy(msg.name, nm, 256);
    vattr2xfs_attr (va, &msg.attr);
#if 0
    msg.exclusive = exclusive;
#endif
    msg.mode = mode;
    msg.cred.uid = cred->cr_uid;
    msg.cred.pag = xfs_get_pag(cred);
    error = xfs_message_rpc(xfsp->fd, &msg.header, sizeof(msg));
    if (error == 0)
      error = ((struct xfs_message_wakeup *) &msg)->error;
  }

  if (error == EEXIST) {
      do_trunc = 1;
      error = 0;
  }

  if (error == 0)
    error = xfs_lookup_common(dvp, nm, vpp, /*pnp*/ NULL, /*flags*/ 0,
			      /*rdir*/ NULL, cred);

  if (error = 0 && do_trunc)
      error = xfs_setattr_common (*vpp, va, 0, cred);

  return error;
}

static int
xfs_remove_common(struct vnode *dvp,
		  char *nm,
		  struct cred *cred)
{
  struct xfs *xfsp = XFS_FROM_VNODE(dvp);
  struct xfs_node *xn = VNODE_TO_XNODE(dvp);
  struct xfs_message_remove msg;
  int error;

  XFSDEB(XDEBVNOPS, ("xfs_remove: %s\n", nm));

  msg.header.opcode = XFS_MSG_REMOVE;
  msg.parent_handle = xn->handle;
  strncpy(msg.name, nm, 256);
  msg.cred.uid = cred->cr_uid;
  msg.cred.pag = xfs_get_pag(cred);
  error = xfs_message_rpc(xfsp->fd, &msg.header, sizeof(msg));
  if (error == 0)
      error = ((struct xfs_message_wakeup *) &msg)->error;

  return error;
}

static int
xfs_link_common(struct vnode *vp,
		struct vnode *tdvp,
		char *tnm,
		struct cred *cred)     
{
    struct xfs *xfsp = XFS_FROM_VNODE(vp);
    struct xfs_node *xn = VNODE_TO_XNODE(tdvp);
    struct xfs_node *xn2 = VNODE_TO_XNODE(vp);
    struct xfs_message_link msg;
    int error = 0;

    XFSDEB(XDEBVNOPS, ("xfs_link: (%s)\n", tnm));

    msg.header.opcode = XFS_MSG_LINK;
    msg.parent_handle = xn->handle;
    msg.from_handle   = xn2->handle;
    strncpy(msg.name, tnm, 256);
    msg.cred.uid = cred->cr_uid;
    msg.cred.pag = xfs_get_pag(cred);

    error = xfs_message_rpc(xfsp->fd, &msg.header, sizeof(msg));
    if (error == 0)
	error = ((struct xfs_message_wakeup *) & msg)->error;

    return error;
}

static int
xfs_rename_common(struct vnode *sdvp,
		  char *onm,
		  struct vnode *tdvp,
		  char *nnm,
		  struct pathname *npnp,
		  struct cred *cred)     
{
  struct xfs_message_rename msg;
  struct vnode **vpp;
  int error = 0;

  XFSDEB(XDEBVNOPS, ("xfs_rename\n"));

  error = xfs_lookup_common(tdvp, nnm, vpp, /*pnp*/ NULL, /*flags*/ 0,
			    /*rdir*/ NULL, cred);
  if (error != ENOENT) {
      /* the filename being moved to already exists */
      struct xfs_message_remove remmsg;
      
      remmsg.header.opcode = XFS_MSG_REMOVE;
      remmsg.parent_handle = VNODE_TO_XNODE(tdvp)->handle;
      strncpy(remmsg.name, nnm, 256);
      remmsg.cred.uid = cred->cr_uid;
      remmsg.cred.pag = xfs_get_pag(cred);
      error = xfs_message_rpc(XFS_FROM_VNODE(tdvp)->fd, &remmsg.header,
			      sizeof(remmsg));
      if (error == 0)
	  error = ((struct xfs_message_wakeup *) & remmsg)->error;
      if (error != 0)
	  return error;
  }

  msg.header.opcode = XFS_MSG_RENAME;
  msg.old_parent_handle = VNODE_TO_XNODE(sdvp)->handle;
  strncpy(msg.old_name, onm, 256);
  msg.new_parent_handle = VNODE_TO_XNODE(tdvp)->handle;
  strncpy(msg.new_name, nnm, 256);
  msg.cred.uid = cred->cr_uid;
  msg.cred.pag = xfs_get_pag(cred);
  error = xfs_message_rpc(XFS_FROM_VNODE(sdvp)->fd, &msg.header,
			  sizeof(msg));
  if (error == 0)
      error = ((struct xfs_message_wakeup *) & msg)->error;
  
  return error;
}

static int
xfs_mkdir_common(struct vnode *dvp,
		 char *nm,
		 struct vattr *va,
		 struct vnode **vpp,
		 struct cred *cred)     
{
  struct xfs *xfsp = XFS_FROM_VNODE(dvp);
  struct xfs_node *xn = VNODE_TO_XNODE(dvp);
  int error = 0;
  
  XFSDEB(XDEBVNOPS, ("xfs_mkdir\n"));
  {
    struct xfs_message_mkdir msg;
    msg.header.opcode = XFS_MSG_MKDIR;
    msg.parent_handle = xn->handle;
    strncpy(msg.name, nm, 256);
    vattr2xfs_attr (va, &msg.attr);
    msg.cred.uid = cred->cr_uid;
    msg.cred.pag = xfs_get_pag(cred);
    error = xfs_message_rpc(xfsp->fd, &msg.header, sizeof(msg));
    if (error == 0)
      error = ((struct xfs_message_wakeup *) &msg)->error;
  }
  if (error == 0)
      error = xfs_lookup_common(dvp, nm, vpp, /*pnp*/ NULL, /*flags*/ 0,
				/*rdir*/ NULL, cred);
  return error;
}

static int
xfs_rmdir_common(struct vnode *dvp,
		 char *nm,
		 struct vnode *foo,
		 struct cred *cred)     
{
    struct xfs_message_rmdir msg;
    struct xfs *xfsp  = XFS_FROM_VNODE(dvp);
    struct xfs_node *xn = VNODE_TO_XNODE(dvp);
    int error = 0;

    XFSDEB(XDEBVNOPS, ("xfs_rmdir\n"));

    msg.header.opcode = XFS_MSG_RMDIR;
    msg.parent_handle = xn->handle;
    strncpy(msg.name, nm, 256);
    msg.cred.uid = cred->cr_uid;
    msg.cred.pag = xfs_get_pag(cred);
    error = xfs_message_rpc(xfsp->fd, &msg.header, sizeof(msg));
    if (error == 0)
	error = ((struct xfs_message_wakeup *) &msg)->error;

    return error;
}

static int
xfs_readdir_common(struct vnode *vp,
		   struct uio *uiop,
		   struct cred *cred,
		   int *eofp)		/* XXX */
{
  int error = 0;

  XFSDEB(XDEBVNOPS, ("xfs_readdir\n"));

  error = xfs_data_valid(vp, cred, XFS_DATA_R);
  if (error == 0) {
      struct vnode *t      = DATA_FROM_VNODE(vp);

      ASSERT(t != NULL);

      if(ABI_IS_64BIT(GETDENTS_ABI(curprocp->p_abi, uiop))) {
	  VOP_RWLOCK(t, 0);
#if IRIX_64
	  VOP_READ(t, uiop, 0, cred, NULL, error);
#else
	  error = VOP_READ(t, uiop, 0, cred);
#endif
	  VOP_RWUNLOCK(t, 0);
      } else {
	  struct uio tmp_uio;
	  struct iovec iovec;
	  char *buf;
	  size_t count = uiop->uio_resid;

	  buf = xfs_alloc (count);
	  iovec.iov_base     = buf;
	  iovec.iov_len      = count;
	  tmp_uio.uio_iov    = &iovec;
	  tmp_uio.uio_iovcnt = 1;
	  tmp_uio.uio_offset = uiop->uio_offset;
	  tmp_uio.uio_segflg = UIO_SYSSPACE;
	  tmp_uio.uio_fmode  = uiop->uio_fmode;
	  tmp_uio.uio_limit  = uiop->uio_limit;
	  tmp_uio.uio_resid  = count;
	  VOP_RWLOCK(t, 0);
#if IRIX_64
	  VOP_READ(t, &tmp_uio, 0, cred, NULL, error);
#else
	  error = VOP_READ(t, &tmp_uio, 0, cred);
#endif
	  VOP_RWUNLOCK(t, 0);

	  if (error == 0) {
	      char *ptr;
	      struct dirent64 *d;
	      size_t len = count - tmp_uio.uio_resid;
	      
	      for (ptr = buf;
		   ptr < buf + len;
		   ptr += d->d_reclen) {
		  char tmp_buf[1024];
		  struct irix5_dirent *d5 = (struct irix5_dirent *)tmp_buf;

		  d = (struct dirent64 *)ptr;

		  d5->d_ino    = d->d_ino;
		  d5->d_off    = d->d_off;
		  d5->d_reclen = DIRENTSIZE(strlen(d->d_name));
		  strcpy (d5->d_name, d->d_name);

		  error = uiomove (d5, d5->d_reclen, UIO_READ, uiop);
		  if (error) {
		      XFSDEB(XDEBVNOPS, ("xfs_readdir: uiomove failed: %d\n",
					 error));
		      break;
		  }
	      }
	  }
	  xfs_free (buf, count);
      }
  }

  return error;
}

static int
xfs_symlink_common(struct vnode *dvp,
		   char *lnm,
		   struct vattr *tva,
		   char *tnm,
		   struct cred *cred)
{
    struct xfs *xfsp  = XFS_FROM_VNODE(dvp);
    struct xfs_node *xn = VNODE_TO_XNODE(dvp);
    struct xfs_message_symlink msg;
    int error = 0;
 
    XFSDEB(XDEBVNOPS, ("xfs_symlink\n"));
   
    msg.header.opcode = XFS_MSG_SYMLINK;
    msg.parent_handle = xn->handle;
    strncpy(msg.name, lnm, 256);
    strncpy(msg.contents, tnm, sizeof(msg.contents));
    vattr2xfs_attr (tva, &msg.attr);
    msg.cred.uid = cred->cr_uid;
    msg.cred.pag = xfs_get_pag(cred);

    error = xfs_message_rpc(xfsp->fd, &msg.header, sizeof(msg));
    if (error == 0)
	error = ((struct xfs_message_wakeup *) & msg)->error;

    return error;
}

static int
xfs_readlink_common(struct vnode *vp,
		    struct uio *uiop,
		    struct cred *cred)
{
  int error = 0;

  XFSDEB(XDEBVNOPS, ("xfs_readlink\n"));

  error = xfs_data_valid(vp, cred, XFS_DATA_R);
  if (error == 0)
    {
      struct vnode *t = DATA_FROM_VNODE(vp);
      ASSERT(t != NULL);
      VOP_RWLOCK(t, 0);
#if IRIX_64
      VOP_READ(t, uiop, 0, cred, NULL, error);
#else
      error = VOP_READ(t, uiop, 0, cred);
#endif
      VOP_RWUNLOCK(t, 0);
    }

  return error;
}

static int
xfs_fsync_common(struct vnode *vp,
		 int syncflag,
		 struct cred *cred)
{
  struct xfs *xfsp = XFS_FROM_VNODE(vp);
  struct xfs_node *xn = VNODE_TO_XNODE(vp);
  int error = 0;
  
  XFSDEB(XDEBVNOPS, ("xfs_fsync\n"));

  if (xn->flags & XFS_DATA_DIRTY)
      error = do_fsync (xfsp, xn, cred, XFS_WRITE);
  return error;
}

static int
xfs_inactive_common(struct vnode *vp,
		    struct cred *cred)
{
  struct xfs_message_inactivenode msg;
  struct xfs *xfsp = XFS_FROM_VNODE(vp);
  struct xfs_node *xn = VNODE_TO_XNODE(vp);

  XFSDEB(XDEBVNOPS, ("xfs_inactive\n"));

  msg.header.opcode = XFS_MSG_INACTIVENODE;
  msg.handle = xn->handle;
  msg.flag   = XFS_NOREFS; /* | XFS_DELETE; */
#if 0
  free_xfs_node(VNODE_TO_XNODE(vp));
#endif
  xfs_message_send(xfsp->fd, &msg.header, sizeof(msg));
  return 0;
}

static int
xfs_fid_common(struct vnode *vp,
	       struct fid **fid)
{
  XFSDEB(XDEBVNOPS, ("xfs_fid\n"));
  return ENOSYS;
}

static int
xfs_fid_common2(struct vnode *vp,
		struct fid *fid)
{
  XFSDEB(XDEBVNOPS, ("xfs_fid2\n"));
  return ENOSYS;
}

static void
xfs_rwlock_common(struct vnode *vp,
		  vrwlock_t write_lock)
{
  XFSDEB(XDEBVNOPS, ("xfs_rwlock\n"));
}

static void
xfs_rwunlock_common(struct vnode *vp,
		    vrwlock_t write_lock)
{
  XFSDEB(XDEBVNOPS, ("xfs_rwunlock\n"));
}

static int
xfs_seek_common(struct vnode *vp,
		off_t offset,
		off_t *roffset)
{
  XFSDEB(XDEBVNOPS, ("xfs_seek\n"));
  return 0;
}

static int
xfs_cmp_common(struct vnode *vp1,
	       struct vnode *vp2)
{
  XFSDEB(XDEBVNOPS, ("xfs_cmp\n"));
  return vp1 == vp2;
}

static int
xfs_frlock_common(struct vnode *vp,
		  int foo,
		  struct flock *fl,
		  int bar,
		  off_t off,
		  struct cred *cred)
{
  XFSDEB(XDEBVNOPS, ("xfs_frlock\n"));
  return ENOSYS;
}

static int
xfs_realvp_common(struct vnode *vp,
		  struct vnode **vpp)
{
  XFSDEB(XDEBVNOPS, ("xfs_realvp\n"));
  return ENOSYS;
}

static int
xfs_bmap_common (struct vnode *vp,
		 off_t off,
		 ssize_t sz,
		 int flags,
		 struct cred *cred,
		 struct bmapval *bv,
		 int *foo)
{
  XFSDEB(XDEBVNOPS, ("xfs_bmap\n"));
  return ENOSYS;

}

static void
xfs_strategy_common (struct vnode *vp,
		     struct buf *buf)
{
  XFSDEB(XDEBVNOPS, ("xfs_strategy\n"));
}

static int
xfs_map_common(struct vnode *vp,
	       off_t off,
	       struct pregion *pregion,
	       char **a,
	       size_t sz,
	       u_int prot,
	       u_int max_prot,
	       u_int map_flag,
	       struct cred *cred)
{
  int error = 0;
  struct xfs_node *xn = VNODE_TO_XNODE(vp);
  struct vattr *va = &xn->attr;

  XFSDEB(XDEBVNOPS, ("xfs_map\n"));

  error = fs_map_subr (vp, va->va_size, va->va_mode, off, pregion,
		       *a, sz, prot, max_prot, map_flag, cred);

  XFSDEB(XDEBVNOPS, ("xfs_map: error = %d\n", error));
}

#if 0
  if ((prot & PROT_WRITE) && (flags & MAP_SHARED))
    error = xfs_data_valid(vp, cred, XFS_DATA_W);
  else
    error = xfs_data_valid(vp, cred, XFS_DATA_R);
  
  if (error != 0)
    /* Can't map today */;
  else if (off + len > VNODE_TO_XNODE(vp)->attr.va_size)
    error = EINVAL;
#if 0
  else if ((prot & PROT_WRITE) && (flags & MAP_SHARED))
    error = EROFS;		/* XXX This is currently not supported */
#endif
  else
    {
      struct vnode *t = DATA_FROM_VNODE(vp);
      ASSERT(t != NULL);
      VOP_RWLOCK(t, 1);
#if IRIX_64
      VOP_MAP(t, off, as, addrp, len, prot, maxprot, flags, cred, error);
#else
      error = VOP_MAP(t, off, as, addrp, len, prot, maxprot, flags, cred);
#endif
      /* XXX Patch vnode so that we can intercept get/putpage and inactive. */
      VOP_RWUNLOCK(t, 1);
    }

  return error;
  XFSDEB(XDEBVNOPS, ("xfs_map\n"));
  return ENOSYS;

}
#endif

static int
xfs_addmap_common(struct vnode *vp,
	   off_t off,
	   struct pregion *as,
	   addr_t addr,
	   size_t len,
	   u_int prot,
	   u_int maxprot,
	   u_int flags,
	   struct cred *cred)
{
  XFSDEB(XDEBVNOPS, ("xfs_addmap\n"));
  return 0;
}

static int
xfs_delmap_common(struct vnode *vp,
	   off_t off,
	   struct pregion *as,
	   addr_t addr,
	   u_int len,
	   u_int prot,
	   u_int maxprot,
	   u_int flags,
	   struct cred *cred)
{
  XFSDEB(XDEBVNOPS, ("xfs_delmap\n"));
  return 0;
}


static int
xfs_poll_common(struct vnode *vp,
	 short events,
	 int anyyet,
	 short *revents,
	 struct pollhead **ph)
{
  XFSDEB(XDEBVNOPS, ("xfs_poll\n"));
  return fs_poll(vp, events, anyyet, revents, ph);
}

static int
xfs_dump_common(struct vnode *dumpvp,
	 caddr_t addr,
	 daddr_t darr,
	 u_int foo)
{
  XFSDEB(XDEBVNOPS, ("xfs_dump\n"));
  return ENOSYS;
}

static int
xfs_pathconf_common(struct vnode *vp,
	     int cmd,
	     u_long *valp,
	     struct cred *cred)
{
  XFSDEB(XDEBVNOPS, ("xfs_pathconf\n"));
  return fs_pathconf (vp, cmd, valp, cred);
}

static int
xfs_allocstore_common(struct vnode *vp,
	       off_t off,
	       size_t sz,
	       struct cred *cred)
{
  XFSDEB(XDEBVNOPS, ("xfs_allocstore\n"));
  return ENOSYS;
}

static int
xfs_fcntl_common(struct vnode *vp,
	  int cmd,
	  void *arg,
	  int foo,
	  off_t off,
	  struct cred *cred,
	  union rval *result)
{
  XFSDEB(XDEBVNOPS, ("xfs_fcntl\n"));
  return ENOSYS;
}

static int
xfs_reclaim_common (struct vnode *vp,
	     int foo)
{
  struct xfs_message_inactivenode msg;
  struct xfs *xfsp = XFS_FROM_VNODE(vp);
  struct xfs_node *xn = VNODE_TO_XNODE(vp);

  XFSDEB(XDEBVNOPS, ("xfs_reclaim\n"));

  msg.header.opcode = XFS_MSG_INACTIVENODE;
  msg.handle = xn->handle;
  msg.flag   = XFS_NOREFS | XFS_DELETE;
#if 1
  free_xfs_node(VNODE_TO_XNODE(vp));
#endif
  xfs_message_send(xfsp->fd, &msg.header, sizeof(msg));
  return 0;
}

static int
xfs_attr_get_common (struct vnode *vp,
		     char *a,
		     char *b,
		     int *c,
		     int d,
		     struct cred *cred)
{
  XFSDEB(XDEBVNOPS, ("xfs_attr_get\n"));
  return ENOSYS;
}

static int
xfs_attr_set_common (struct vnode *vp,
		     char *a,
		     char *b,
		     int c,
		     int d,
		     struct cred *cred)
{
  XFSDEB(XDEBVNOPS, ("xfs_attr_set\n"));
  return ENOSYS;
}

static int
xfs_attr_remove_common (struct vnode *vp,
			char *a,
			int b,
			struct cred *cred)
{
  XFSDEB(XDEBVNOPS, ("xfs_attr_remove\n"));
  return ENOSYS;
}

static int
xfs_attr_list_common (struct vnode *vp,
		      char *a,
		      int b,
		      int c,
		      struct attrlist_cursor_kern *k,
		      struct cred *cred)
{
  XFSDEB(XDEBVNOPS, ("xfs_attr_list\n"));
  return ENOSYS;
}

#if IRIX_64

static int
xfs_open(bhv_desc_t *bh,
	 vnode_t **vpp,
	 mode_t mode,
	 struct cred *cred)
{
    return xfs_open_common (vpp, mode, cred);
}

static int
xfs_close (bhv_desc_t *bh,
	   int flag,
	   lastclose_t lastclose,
	   off_t offset,
	   struct cred *cred,
	   struct flid *flid)
{
    return xfs_close_common (BHV_TO_VNODE(bh), flag, lastclose,
			     offset, cred);
}

static int
xfs_read (bhv_desc_t *bh,
	  struct uio *uio,
	  int ioflag,
	  struct cred *cred,
	  struct flid *flid)
{
    return xfs_read_common (BHV_TO_VNODE(bh), uio, ioflag, cred);
}

static int
xfs_write (bhv_desc_t *bh,
	   struct uio *uio,
	   int ioflag,
	   struct cred *cred,
	   struct flid *flid)
{
    return xfs_write_common (BHV_TO_VNODE(bh), uio, ioflag, cred);
}

static int
xfs_ioctl(bhv_desc_t *bh,
	  int cmd,
	  void *arg,
	  int flag,
	  struct cred *cred,
	  int *result)
{
    return xfs_ioctl_common (BHV_TO_VNODE(bh), cmd, arg, flag, cred, result);
}

static int
xfs_setfl(bhv_desc_t *bh,
	  int oflags,
	  int nflags,
	  struct cred *cred)
{
    return xfs_setfl_common (BHV_TO_VNODE(bh), oflags, nflags, cred);
}

static int
xfs_getattr(bhv_desc_t *bh,
	    struct vattr *vap,
	    int flags,
	    struct cred *cred)
{
    return xfs_getattr_common (BHV_TO_VNODE(bh), vap, flags, cred);
}

static int
xfs_setattr(bhv_desc_t *bh,
	    struct vattr *vap,
	    int flags,
	    struct cred *cred)
{
    return xfs_setattr_common (BHV_TO_VNODE(bh), vap, flags, cred);
}

static int
xfs_access(bhv_desc_t *bh,
	   int mode,
	   int flags,
	   struct cred *cred)     
{
    return xfs_access_common (BHV_TO_VNODE(bh), mode, flags, cred);
}

static int
xfs_lookup(bhv_desc_t *bh,
	   char *nm,
	   struct vnode **vpp,
	   struct pathname *pnp,
	   int flags,
	   struct vnode *rdir,
	   struct cred *cred)
{
    return xfs_lookup_common (BHV_TO_VNODE(bh), nm, vpp, pnp,
			      flags, rdir, cred);
}

static int
xfs_create(bhv_desc_t *bh,
	   char *nm,
	   struct vattr *va,
	   int exclusive,
	   int mode,
	   struct vnode **vpp,
	   struct cred *cred)
{
    return xfs_create_common (BHV_TO_VNODE(bh), nm, va,
			      exclusive, mode, vpp, cred);
}

static int
xfs_remove(bhv_desc_t *bh,
	   char *nm,
	   struct cred *cred)
{
    return xfs_remove_common (BHV_TO_VNODE(bh), nm, cred);
}

static int
xfs_link(bhv_desc_t *bh,
	 struct vnode *tdvp,
	 char *tnm,
	 struct cred *cred)     
{
    return xfs_link_common (BHV_TO_VNODE(bh), tdvp, tnm, cred);
}

static int
xfs_rename(bhv_desc_t *bh,
	   char *onm,
	   struct vnode *tdvp,
	   char *nnm,
	   struct pathname *npnp,
	   struct cred *cred)
{
    return xfs_rename_common (BHV_TO_VNODE(bh), onm, tdvp, nnm, npnp, cred);
}

static int
xfs_mkdir(bhv_desc_t *bh,
	  char *nm,
	  struct vattr *va,
	  struct vnode **vpp,
	  struct cred *cred)
{
    return xfs_mkdir_common (BHV_TO_VNODE(bh), nm, va, vpp, cred);
}

static int
xfs_rmdir(bhv_desc_t *bh,
	  char *nm,
	  struct vnode *foo,
	  struct cred *cred)     
{
    return xfs_rmdir_common (BHV_TO_VNODE(bh), nm, foo, cred);
}

static int
xfs_readdir(bhv_desc_t *bh,
	    struct uio *uiop,
	    struct cred *cred,
	    int *eofp)		/* XXX */
{
    return xfs_readdir_common (BHV_TO_VNODE(bh), uiop, cred, eofp);
}

static int
xfs_symlink(bhv_desc_t *bh,
	    char *lnm,
	    struct vattr *tva,
	    char *tnm,
	    struct cred *cred)
{
    return xfs_symlink_common (BHV_TO_VNODE(bh), lnm, tva, tnm, cred);
}

static int
xfs_readlink(bhv_desc_t *bh,
	     struct uio *uiop,
	     struct cred *cred)
{
    return xfs_readlink_common (BHV_TO_VNODE(bh), uiop, cred);
}

static int
xfs_fsync(bhv_desc_t *bh,
	  int syncflag,
	  struct cred *cred)
{
    return xfs_fsync_common (BHV_TO_VNODE(bh), syncflag, cred);
}

static int
xfs_inactive(bhv_desc_t *bh,
	     struct cred *cred)
{
    return xfs_inactive_common (BHV_TO_VNODE(bh), cred);
}

static int
xfs_fid(bhv_desc_t *bh,
	struct fid **fid)
{
    return xfs_fid_common (BHV_TO_VNODE(bh), fid);
}

static int
xfs_fid2(bhv_desc_t *bh,
	 struct fid *fid)
{
    return xfs_fid2_common (BHV_TO_VNODE(bh), fid);
}

static void
xfs_rwlock(bhv_desc_t *bh,
	   vrwlock_t write_lock)
{
    xfs_rwlock_common (BHV_TO_VNODE(bh), write_lock);
}

static void
xfs_rwunlock(bhv_desc_t *bh,
	     vrwlock_t write_lock)
{
    xfs_rwunlock_common (BHV_TO_VNODE(bh), write_lock);
}

static int
xfs_seek(bhv_desc_t *bh,
	 off_t offset,
	 off_t *roffset)
{
    return xfs_seek_common (BHV_TO_VNODE(bh), offset, roffset);
}

static int
xfs_cmp(bhv_desc_t *bh1,
	vnode_t *vp2)
{
    return xfs_cmp_common (BHV_TO_VNODE(bh1), vp2);
}

static int
xfs_frlock(bhv_desc_t *bh,
	   int foo,
	   struct flock *fl,
	   int bar,
	   off_t off,
	   struct cred *cred)
{
    return xfs_frlock_common (BHV_TO_VNODE(bh), foo, fl, bar, off, cred);
}

static int
xfs_realvp(bhv_desc_t *bh,
	   struct vnode **vpp)
{
    return xfs_realvp_common (BHV_TO_VNODE(bh), vpp);
}

static int
xfs_bmap (bhv_desc_t *bh,
	  off_t off,
	  ssize_t sz,
	  int flags,
	  struct cred *cred,
	  struct bmapval *bv,
	  int *foo)
{
    return xfs_bmap_common (BHV_TO_VNODE(bh), off, sz, flags, cred, bv, foo);
}

static void
xfs_strategy (bhv_desc_t *bh,
	      struct buf *buf)
{
    xfs_strategy_common (BHV_TO_VNODE(bh), buf);
}

static int
xfs_map(bhv_desc_t *bh,
	off_t off,
	void *pregion,
	char **a,
	size_t sz,
	u_int prot,
	u_int max_prot,
	u_int map_flag,
	struct cred *cred)
{
    return xfs_map_common (BHV_TO_VNODE(bh), off, pregion, a, sz, prot,
			   max_prot, map_flag, cred);
}

static int
xfs_addmap(bhv_desc_t *bh,
	   off_t off,
	   void *as,
	   addr_t addr,
	   size_t len,
	   u_int prot,
	   u_int maxprot,
	   u_int flags,
	   struct cred *cred)
{
    return xfs_addmap_common (BHV_TO_VNODE(bh), off, as, addr, len, prot,
			      maxprot, flags, cred);
}

static int
xfs_delmap(bhv_desc_t *bh,
	   off_t off,
	   void *as,
	   addr_t addr,
	   size_t len,
	   u_int prot,
	   u_int maxprot,
	   u_int flags,
	   struct cred *cred)
{
    return xfs_delmap_common (BHV_TO_VNODE(bh), off, as, addr, len, prot,
			      maxprot, flags, cred);
}

static int
xfs_poll(bhv_desc_t *bh,
	 short events,
	 int anyyet,
	 short *revents,
	 struct pollhead **ph)
{
    return xfs_poll_common (BHV_TO_VNODE(bh), events, anyyet, revents, ph);
}

static int
xfs_dump(bhv_desc_t *bh,
	 caddr_t addr,
	 daddr_t darr,
	 u_int foo)
{
    return xfs_dump_common (BHV_TO_VNODE(bh), addr, darr, foo);
}

static int
xfs_pathconf(bhv_desc_t *bh,
	     int cmd,
	     u_long *valp,
	     struct cred *cred)
{
    return xfs_pathconf_common (BHV_TO_VNODE(bh), cmd, valp, cred);
}

static int
xfs_allocstore(bhv_desc_t *bh,
	       off_t off,
	       size_t sz,
	       struct cred *cred)
{
    return xfs_allocstore_common (BHV_TO_VNODE(bh), off, sz, cred);
}

static int
xfs_fcntl(bhv_desc_t *bh,
	  int cmd,
	  void *arg,
	  int foo,
	  off_t off,
	  struct cred *cred,
	  union rval *result)
{
    return xfs_fcntl_common (BHV_TO_VNODE(bh), cmd, arg, foo, off, cred,
			     result);
}

static int
xfs_reclaim (bhv_desc_t *bh, int foo)
{
    return xfs_reclaim_common (BHV_TO_VNODE(bh), foo);
}

static int
xfs_attr_get (bhv_desc_t *bh,
	      char *a,
	      char *b,
	      int *c,
	      int d,
	      struct cred *cred)
{
    return xfs_attr_get_common (BHV_TO_VNODE(bh), a, b, c, d, cred);
}

static int
xfs_attr_set (bhv_desc_t *bh,
	      char *a,
	      char *b,
	      int c,
	      int d,
	      struct cred *cred)
{
    return xfs_attr_set_common (BHV_TO_VNODE(bh), a, b, c, d, cred);
}

static int
xfs_attr_remove (bhv_desc_t *bh,
		 char *a,
		 int b,
		 struct cred *cred)
{
    return xfs_attr_remove_common (BHV_TO_VNODE(bh), a, b, cred);
}

static int
xfs_attr_list (bhv_desc_t *bh,
	       char *a,
	       int b,
	       int c,
	       struct attrlist_cursor_kern *k,
	       struct cred *cred)
{
    return xfs_attr_list_common (BHV_TO_VNODE(bh), a, b, c, k, cred);
}

static int
xfs_mount (bhv_desc_t *bh,
	   struct mounta *uap,
	   char *path,
	   struct vfsops *vfsops)
{
  XFSDEB(XDEBVNOPS, ("xfs_mount\n"));
  return ENOSYS;
}

struct vnodeops xfs_vnodeops = {
	VNODE_POSITION_BASE,
        xfs_open,
        xfs_close,
        xfs_read,
        xfs_write,
        xfs_ioctl,
	xfs_setfl,
        xfs_getattr,
        xfs_setattr,
        xfs_access,
        xfs_lookup,
        xfs_create,
        xfs_remove,
        xfs_link,
        xfs_rename,
        xfs_mkdir,
        xfs_rmdir,
        xfs_readdir,
        xfs_symlink,
        xfs_readlink,
        xfs_fsync,
        xfs_inactive,
	xfs_fid,
	xfs_fid2,
	xfs_rwlock,
	xfs_rwunlock,
	xfs_seek,
	xfs_cmp,
	xfs_frlock,
	xfs_realvp,
        xfs_bmap,
        xfs_strategy,
        xfs_map,
	xfs_addmap,
	xfs_delmap,
	xfs_poll,
        xfs_dump,
	xfs_pathconf,
	xfs_allocstore,
	xfs_fcntl,
	xfs_reclaim,
	xfs_attr_get,
	xfs_attr_set,
	xfs_attr_remove,
	xfs_attr_list,
	xfs_mount
};

#else /* !IRIX_64 */

static int
xfs_open(struct vnode **vpp,
	 mode_t mode,
	 struct cred *cred)
{
    return xfs_open_common (vpp, mode, cred);
}

static int
xfs_close(struct vnode *vp,
	  int flag,
	  lastclose_t lastclose,
	  off_t offset,
	  struct cred *cred)
{
    return xfs_close_common (vp, flag, lastclose, offset, cred);
}

static int
xfs_read(struct vnode *vp,
	 struct uio *uio,
	 int ioflag,
	 struct cred *cred)
{
    return xfs_read_common (vp, uio, ioflag, cred);
}

static int
xfs_write(struct vnode *vp,
	  struct uio *uio,
	  int ioflag,
	  struct cred *cred)
{
    return xfs_write_common (vp, uio, ioflag, cred);
}

static int
xfs_ioctl(struct vnode *vp,
	  int cmd,
	  void *arg,
	  int flag,
	  struct cred *cred,
	  int *result)
{
    return xfs_ioctl_common (vp, cmd, arg, flag, cred, result);
}

static int
xfs_setfl(struct vnode *vp,
	  int oflags,
	  int nflags,
	  struct cred *cred)
{
    return xfs_setfl_common (vp, oflags, nflags, cred);
}

static int
xfs_getattr(struct vnode *vp,
	    struct vattr *vap,
	    int flags,
	    struct cred *cred)
{
    return xfs_getattr_common (vp, vap, flags, cred);
}

static int
xfs_setattr(struct vnode *vp,
	    struct vattr *vap,
	    int flags,
	    struct cred *cred)
{
    return xfs_setattr_common (vp, vap, flags, cred);
}

static int
xfs_access(struct vnode *vp,
	   int mode,
	   int flags,
	   struct cred *cred)     
{
    return xfs_access_common (vp, mode, flags, cred);
}

static int
xfs_lookup(struct vnode *dvp,
	   char *nm,
	   struct vnode **vpp,
	   struct pathname *pnp,
	   int flags,
	   struct vnode *rdir,
	   struct cred *cred)
{
    return xfs_lookup_common (dvp, nm, vpp, pnp, flags, rdir, cred);
}

static int
xfs_create(struct vnode *dvp,
	   char *nm,
	   struct vattr *va,
	   enum vcexcl exclusive,
	   int mode,
	   struct vnode **vpp,
	   struct cred *cred)
{
    return xfs_create_common (dvp, nm, va, exclusive, mode, vpp, cred);
}

static int
xfs_remove(struct vnode *dvp,
	   char *nm,
	   struct cred *cred)
{
    return xfs_remove_common (dvp, nm, cred);
}

static int
xfs_link(struct vnode *vp,
	 struct vnode *tdvp,
	 char *tnm,
	 struct cred *cred)     
{
    return xfs_link_common (vp, tdvp, tnm, cred);
}

static int
xfs_rename(struct vnode *sdvp,
	   char *onm,
	   struct vnode *tdvp,
	   char *nnm,
	   struct pathname *npnp,
	   struct cred *cred)
{
    return xfs_rename_common (sdvp, onm, tdvp, nnm, npnp, cred);
}

static int
xfs_mkdir(struct vnode *dvp,
	  char *nm,
	  struct vattr *va,
	  struct vnode **vpp,
	  struct cred *cred)
{
    return xfs_mkdir_common (dvp, nm, va, vpp, cred);
}

static int
xfs_rmdir(struct vnode *dvp,
	  char *nm,
	  struct vnode *foo,
	  struct cred *cred)     
{
    return xfs_rmdir_common (dvp, nm, foo, cred);
}

static int
xfs_readdir(struct vnode *vp,
	    struct uio *uiop,
	    struct cred *cred,
	    int *eofp)		/* XXX */
{
    return xfs_readdir_common (vp, uiop, cred, eofp);
}

static int
xfs_symlink(struct vnode *dvp,
	    char *lnm,
	    struct vattr *tva,
	    char *tnm,
	    struct cred *cred)
{
    return xfs_symlink_common (dvp, lnm, tva, tnm, cred);
}

static int
xfs_readlink(struct vnode *vp,
	     struct uio *uiop,
	     struct cred *cred)
{
    return xfs_readlink_common (vp, uiop, cred);
}

static int
xfs_fsync(struct vnode *vp,
	  int syncflag,
	  struct cred *cred)
{
    return xfs_fsync_common (vp, syncflag, cred);
}

static void
xfs_inactive(struct vnode *vp,
	     struct cred *cred)
{
    xfs_inactive_common (vp, cred);
}

static int
xfs_fid(struct vnode *vp,
	struct fid **fid)
{
    return xfs_fid_common (vp, fid);
}

static int
xfs_fid2(struct vnode *vp,
	 struct fid *fid)
{
    return xfs_fid2_common (vp, fid);
}

static void
xfs_rwlock(struct vnode *vp,
	   vrwlock_t write_lock)
{
    xfs_rwlock_common (vp, write_lock);
}

static void
xfs_rwunlock(struct vnode *vp,
	     vrwlock_t write_lock)
{
    xfs_rwunlock_common (vp, write_lock);
}

static int
xfs_seek(struct vnode *vp,
	 off_t offset,
	 off_t *roffset)
{
    return xfs_seek_common (vp, offset, roffset);
}

static int
xfs_cmp(struct vnode *vp1,
	struct vnode *vp2)
{
    return xfs_cmp_common (vp1, vp2);
}

static int
xfs_frlock(struct vnode *vp,
	   int foo,
	   struct flock *fl,
	   int bar,
	   off_t off,
	   struct cred *cred)
{
    return xfs_frlock_common (vp, foo, fl, bar, off, cred);
}

static int
xfs_realvp(struct vnode *vp,
	   struct vnode **vpp)
{
    return xfs_realvp_common (vp, vpp);
}

static int
xfs_bmap (struct vnode *vp,
	  off_t off,
	  ssize_t sz,
	  int flags,
	  struct cred *cred,
	  struct bmapval *bv,
	  int *foo)
{
    return xfs_bmap_common (vp, off, sz, flags, cred, bv, foo);
}

static void
xfs_strategy (struct vnode *vp,
	      struct buf *buf)
{
    xfs_strategy_common (vp, buf);
}

static int
xfs_map(struct vnode *vp,
	off_t off,
	struct pregion *pregion,
	char **a,
	size_t sz,
	u_int prot,
	u_int max_prot,
	u_int map_flag,
	struct cred *cred)
{
    return xfs_map_common (vp, off, pregion, a, sz, prot, max_prot,
			   map_flag, cred);
}

static int
xfs_addmap(struct vnode *vp,
	   off_t off,
	   struct pregion *as,
	   addr_t addr,
	   size_t len,
	   u_int prot,
	   u_int maxprot,
	   u_int flags,
	   struct cred *cred)
{
    return xfs_addmap_common (vp, off, as, addr, len, prot, maxprot,
			      flags, cred);
}

static int
xfs_delmap(struct vnode *vp,
	   off_t off,
	   struct pregion *as,
	   addr_t addr,
	   size_t len,
	   u_int prot,
	   u_int maxprot,
	   u_int flags,
	   struct cred *cred)
{
    return xfs_delmap_common (vp, off, as, addr, len, prot, maxprot,
			      flags, cred);
}

static int
xfs_poll(struct vnode *vp,
	 short events,
	 int anyyet,
	 short *revents,
	 struct pollhead **ph)
{
    return xfs_poll_common (vp, events, anyyet, revents, ph);
}

static int
xfs_dump(struct vnode *dumpvp,
	 caddr_t addr,
	 daddr_t darr,
	 u_int foo)
{
    return xfs_dump_common (dumpvp, addr, darr, foo);
}

static int
xfs_pathconf(struct vnode *vp,
	     int cmd,
	     u_long *valp,
	     struct cred *cred)
{
    return xfs_pathconf_common (vp, cmd, valp, cred);
}

static int
xfs_allocstore(struct vnode *vp,
	       off_t off,
	       size_t sz,
	       struct cred *cred)
{
    return xfs_allocstore_common (vp, off, sz, cred);
}

static int
xfs_fcntl(struct vnode *vp,
	  int cmd,
	  void *arg,
	  int foo,
	  off_t off,
	  struct cred *cred,
	  union rval *result)
{
    return xfs_fcntl_common (vp, cmd, arg, foo, off, cred, result);
}

static int
xfs_reclaim (struct vnode *vp,
	     int foo)
{
    return xfs_reclaim_common (vp, foo);
}

static int
xfs_attr_get (struct vnode *vp,
	      char *a,
	      char *b,
	      int *c,
	      int d,
	      struct cred *cred)
{
    return xfs_attr_get_common (vp, a, b, c, d, cred);
}

static int
xfs_attr_set (struct vnode *vp,
	      char *a,
	      char *b,
	      int c,
	      int d,
	      struct cred *cred)
{
    return xfs_attr_set_common (vp, a, b, c, d, cred);
}

static int
xfs_attr_remove (struct vnode *vp,
		 char *a,
		 int b,
		 struct cred *cred)
{
    return xfs_attr_remove_common (vp, a, b, cred);
}

static int
xfs_attr_list (struct vnode *vp,
	       char *a,
	       int b,
	       int c,
	       struct attrlist_cursor_kern *k,
	       struct cred *cred)
{
    return xfs_attr_list_common (vp, a, b, c, k, cred);
}

struct vnodeops xfs_vnodeops = {
        xfs_open,
        xfs_close,
        xfs_read,
        xfs_write,
        xfs_ioctl,
	xfs_setfl,
        xfs_getattr,
        xfs_setattr,
        xfs_access,
        xfs_lookup,
        xfs_create,
        xfs_remove,
        xfs_link,
        xfs_rename,
        xfs_mkdir,
        xfs_rmdir,
        xfs_readdir,
        xfs_symlink,
        xfs_readlink,
        xfs_fsync,
        xfs_inactive,
	xfs_fid,
	xfs_fid2,
	xfs_rwlock,
	xfs_rwunlock,
	xfs_seek,
	xfs_cmp,
	xfs_frlock,
	xfs_realvp,
        xfs_bmap,
        xfs_strategy,
        xfs_map,
	xfs_addmap,
	xfs_delmap,
	xfs_poll,
        xfs_dump,
	xfs_pathconf,
	xfs_allocstore,
	xfs_fcntl,
	xfs_reclaim,
	xfs_attr_get,
	xfs_attr_set,
	xfs_attr_remove,
	xfs_attr_list
};

#endif
