/*
 * Copyright (c) 1995 - 2000 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.
 */

#include <xfs/xfs_locl.h>

RCSID("$Id: xfs_vfsops-osf.c,v 1.21 2000/03/19 00:22:29 assar Exp $");

/*
 * XFS vfs operations.
 */

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

static int
xfs_mount(struct mount * mp,
	  char *user_path,
	  caddr_t user_data,
	  struct nameidata * ndp)
{
    return xfs_mount_common(mp, user_path, user_data, ndp, NULL);
}

static int
xfs_start(struct mount * mp, int flags)
{
    XFSDEB(XDEBVFOPS, ("xfs_start mp = %lx, flags = %d\n",
		       (unsigned long)mp, flags));
    return 0;
}

static int
xfs_unmount(struct mount * mp, int mntflags)
{
    XFSDEB(XDEBVFOPS, ("xfs_umount: mp = %lx, mntflags = %d\n",
		       (unsigned long)mp, mntflags));
    return xfs_unmount_common(mp, mntflags);
}

static int
xfs_root(struct mount * mp, struct vnode ** vpp)
{
    XFSDEB(XDEBVFOPS, ("xfs_root mp = %lx\n", (unsigned long)mp));

    return xfs_root_common (mp, vpp, u.u_procp, u.u_procp->p_rcred);
}

static int
xfs_quotactl(struct mount *mp, int cmd, uid_t uid, caddr_t arg)
{
    XFSDEB(XDEBVFOPS, ("xfs_quotactl: mp = %lx, cmd = %d, uid = %u, "
		       "arg = %lx\n", 
		       (unsigned long)mp, cmd, uid,
		       (unsigned long)arg));
    return (EOPNOTSUPP);
}

static int
xfs_statfs(struct mount *mp)
{
    XFSDEB(XDEBVFOPS, ("xfs_statfs: mp = %lx\n",
		       (unsigned long)mp));
    return 0;
}

static int
xfs_sync(struct mount *mp, int waitfor)
{
    XFSDEB(XDEBVFOPS, ("xfs_sync: mp = %lx, waitfor = %d\n",
		       (unsigned long)mp, waitfor));
    return 0;
}

static int
xfs_vget(struct mount * mp,
	 ino_t ino,
	 struct vnode ** vpp)
{
    XFSDEB(XDEBVFOPS, ("xfs_vget\n"));
    return EOPNOTSUPP;
}

static int
xfs_fhtovp(struct mount *mp,
	   struct fid *fhp,
	   struct vnode **vpp)
{
    XFSDEB(XDEBVFOPS, ("xfs_fhtovp\n"));
    return EOPNOTSUPP;
}

static int
xfs_vptofh(struct vnode * vp,
	   struct fid * fhp)
{
    XFSDEB(XDEBVFOPS, ("xfs_vptofh\n"));
    return EOPNOTSUPP;
}

extern struct vnodeops dead_vnodeops;
extern struct vfs_ubcops xfs_ubcops;

int
make_dead_vnode(struct mount *mp, struct vnode **vpp)
{
    int error;

    XFSDEB(XDEBNODE, ("make_dead_vnode mp = %lx\n",
		      (unsigned long)mp));

    error = getnewvnode(VT_NON, &dead_vnodeops, vpp);
    if (error) {
	return error;
    }
    insmntque(*vpp, DEADMOUNT, 0);

    return 0;
}

static int
xfs_init(void)
{
    XFSDEB(XDEBVFOPS, ("xfs_init\n"));
    return 0;
}

struct vfsops xfs_vfsops = {
        xfs_mount,
        xfs_start,
        xfs_unmount,
        xfs_root,
        xfs_quotactl,
        xfs_statfs,
        xfs_sync,
        xfs_fhtovp,
        xfs_vptofh,
        xfs_init
};


extern struct vfsops xfs_vfsops;

int
xfs_install_fs(void)
{
    if (vn_maxprivate < sizeof(struct xfs_node))
	return ENOMEM;
    return vfssw_add_fsname(MOUNT_XFS, &xfs_vfsops, "xfs");
}

int
xfs_uninstall_fs(void)
{
    return vfssw_del(MOUNT_XFS);
}

int
xfs_fhlookup (struct proc *proc,
	      struct xfs_fhandle_t *fhp,
	      struct vnode **vpp)
{
    int error;
    struct ucred *cred = proc->p_rcred; 
    struct mount *mp;
    fid_t fid;
    fhandle_t *fh = (fhandle_t *)fhp;

    XFSDEB(XDEBVFOPS, ("xfs_fhlookup\n"));

    error = xfs_suser (proc);
    if (error)
	return EPERM;

    if (fhp->len < sizeof (*fh))
	return EINVAL;

    mp = getvfs(&fh->fh_fsid);
    if(mp == NULL) {
	XFSDEB(XDEBVFOPS, ("getvfs(%d) = NULL\n", fh->fh_fsid));
	return ESTALE;
    }

    VFS_FHTOVP(mp, &fh->fh_fid, vpp, error);
    XFSDEB(XDEBVFOPS, ("VFS_FHTOVP() = %d\n", error));
    /* getvfs returned the mount structure locked */
    UNMOUNT_READ_UNLOCK(mp);
    if (error)
	return (ESTALE);
    VREF(*vpp);
    return (0);

#if 0 
	bzero(&fh);
	fh.fh_fsid = fsid;
	fh.fh_fid.fid_len = sizeof(fh.fh_fid);
	bcopy(&fileid, fh.fh_fid.fid_data, sizeof(fileid));
    
    error = vn_fhtovp(&fh, 0, vpp);
    XFSDEB(XFSDEBVFSOPS, ("vn_fhtovp() = %d\n", error));
    return error;
#endif
}

int
xfs_fhopen (struct proc *proc,
	    struct xfs_fhandle_t *fhp,
	    int user_flags,
	    register_t *retval)
{
    int error;
    struct vnode *vp;
    struct ucred *cred = proc->p_rcred;
    int flags = FFLAGS(user_flags);
    int index;
    struct file *fp;
    extern struct fileops vnops;
    struct ufile_state *ufp;
#ifndef U_FD_SET
    struct ufile_entry *fe;
#endif

    XFSDEB(XDEBVFOPS, ("xfs_fhopen: flags = %x\n", user_flags));

    error = xfs_fhlookup (proc, fhp, &vp);
    if (error)
	return error;

    VOP_OPEN(&vp, flags, cred, error);
    if (error)
	goto out;

    error = vn_writechk(vp, 1);
    if(error)
	goto out;

#ifdef U_FD_SET
    error = falloc(&fp, &index);
#else
    error = falloc(&fp, &index, &fe);
#endif
    if (error)
	goto out;
    ufp = &u.u_file_state;
    FP_UNREF_MT(fp,ufp);
#ifdef U_FD_SET
    U_FD_SET(index, fp, ufp);
#else
    u_set_fe(index, fe, fp, ufp);
#endif

    /* ??? */
    if (flags & FREAD) {
	VN_LOCK(vp);
        vp->v_rdcnt++;
	VN_UNLOCK(vp);
    }

    fp->f_flag = flags & FMASK;
    fp->f_type = DTYPE_VNODE;
    fp->f_ops  = &vnops;
    fp->f_data = (caddr_t)vp;
    xfs_vfs_unlock(vp, proc);

    XFSDEB(XDEBVFOPS, ("xfs_fhopen: fileno = %d\n", index));
    *retval = index;
    return 0;
out:
    XFSDEB(XDEBVFOPS, ("xfs_fhopen: errno = %d\n", error));
    vput(vp);
    return error;
}
