⛏️ index : haiku.git

/*-
 * SPDX-License-Identifier: BSD-3-Clause
 *
 * Copyright (c) 1989, 1993
 *	The Regents of the University of California.  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. Neither the name of the University 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 REGENTS 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 REGENTS 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.
 */
#ifndef FAT_VNODE_H
#define FAT_VNODE_H


// Modified to support the Haiku FAT driver.

#ifdef FS_SHELL
#include "fssh_api_wrapper.h"
#else
#include <fs_interface.h>
#include <lock.h>
#endif

#include "sys/buf.h"
#include "sys/bufobj.h"
#include "sys/lockmgr.h"
#include "sys/namei.h"
#include "sys/ucred.h"

#include "fs/msdosfs/direntry.h"
#include "fs/msdosfs/denode.h"

#include "dosfs.h"


// In the Haiku port, one struct vnode per volume is set up to represent its device file.
// It will have type VBLK. All other struct vnodes (those that actually represent
// files on the volume) will have type VREG or VDIR.
enum vtype { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO, VBAD, VMARKER };
#define VLASTTYPE VMARKER

enum vstate { VSTATE_UNINITIALIZED, VSTATE_CONSTRUCTED, VSTATE_DESTROYING, VSTATE_DEAD };
#define VLASTSTATE VSTATE_DEAD

/*
 * Reading or writing any of these items requires holding the appropriate lock.
 *
 * Lock reference:
 *	u - Only a reference to the vnode is needed to read.
 *	v - vnode lock
 *
 */
struct vnode {
	/*
	 * Fields which define the identity of the vnode.
	 */
	enum vtype v_type : 8; /* u vnode type */
	enum vstate v_state : 8; /* u vnode state */
	void* v_data; /* u private data for fs */

	/*
	 * Filesystem instance stuff
	 */
	struct mount* v_mount; /* u ptr to vfs we are in */

	/*
	 * Type specific fields, only one applies to any given vnode.
	 */
	union {
		struct cdev* v_rdev; /* v device (VCHR, VBLK) */
	};

	/*
	 * Locking
	 */
	struct lock v_lock; /* u (if fs don't have one) */
	struct lock* v_vnlock; /* u pointer to vnode lock */

	/*
	 * The machinery of being a vnode
	 */
	struct bufobj v_bufobj; /* * Buffer cache object */

	/*
	 * Hooks for various subsystems and features.
	 */
	u_short v_vflag; /* v vnode flags */

	// Members added for Haiku port
	ino_t v_parent; /* v inode of parent directory */
	const char* v_mime; /* v mime type for VREG nodes, otherwise NULL */
	void* v_cache; /* v file cache for VREG nodes, otherwise NULL */
	void* v_file_map; /* v file map for VREG nodes, otherwise NULL */
	bool v_resizing; /* v disable IO (see comment in dosfs_wstat) */
	bool v_sync; /* v use synchronous IO */
};


/*
 * Vnode flags.
 *	VV flags are protected by the vnode lock and live in v_vflag
 */
#define VV_ROOT 0x0001 /* root of its filesystem */

/*
 * Flags for ioflag.
 */
#define IO_SYNC 0x0080 /* do I/O synchronously */

/*
 * Flags for accmode_t.
 */
#define VEXEC 000000000100 /* execute/search permission */
#define VWRITE 000000000200 /* write permission */
#define VREAD 000000000400 /* read permission */

#define VREF(vp) vref(vp)

#define VN_LOCK_AREC(vp) lockallowrecurse((vp)->v_vnlock)


/*! Verify vp is exclusively (i.e. write) locked.

*/
static inline void
assert_vop_elocked(struct vnode* vp, const char* str)
{
	if (vp == NULL)
		return;
	ASSERT_WRITE_LOCKED_RW_LOCK(&vp->v_vnlock->haikuRW);
}


#define ASSERT_VOP_ELOCKED(vp, str) assert_vop_elocked((vp), (str))
// In FreeBSD, this verifies that vp is either write-locked or read-locked. In Haiku, there is no
// equivalent assert.
#define ASSERT_VOP_LOCKED(vp, str) ((void)0)

#define DOINGASYNC(vp) (((vp)->v_mount->mnt_flag & MNT_ASYNC) != 0)

// FreeBSD would generate vnode_if.h, vnode_if_typedef.h, and vnode_if_newproto.h at build time
// and #include them here (the latter two indirectly via the first).
// For the Haiku port, vnode_if.h was generated manually by running a script:
// sys/tools/vnode_if.awk sys/kern/vnode_if.src -h
// and vnode_if_typedef.h by running:
// sys/tools/vnode_if.awk sys/kern/vnode_if.src -q
// and vnode_if_newproto.h by running:
// sys/tools/vnode_if.awk sys/kern/vnode_if.src -p
// Modified excerpts from these headers are pasted below.

// This struct is referenced by the ported code but has no effect in the Haiku port.
struct vop_vector {
};


static inline int
VOP_ACCESS(struct vnode* vp, accmode_t accmode, struct ucred* cred, thread_id td)
{
	struct mount* bsdVolume = (struct mount*)vp->v_mount;

	int mode = 0;
	if ((accmode & VREAD) != 0)
		mode |= R_OK;
	if ((accmode & VWRITE) != 0)
		mode |= W_OK;
	if ((accmode & VEXEC) != 0)
		mode |= X_OK;

	return B_TO_POSIX_ERROR(_dosfs_access(bsdVolume, vp, mode));
}


static inline int
VOP_UNLOCK(struct vnode* vp)
{
	lockmgr(vp->v_vnlock, LK_RELEASE, NULL);

	return 0;
}


// End of vnode_if.h content

typedef int (*vn_get_ino_t)(struct mount*, void*, int, struct vnode**);

typedef int vfs_hash_cmp_t(struct vnode* vp, void* arg);

int vfs_hash_get(struct mount* mp, uint64 hash, int flags, thread_id td, struct vnode** vpp,
	vfs_hash_cmp_t* fn, void* arg);

int vfs_hash_insert(struct vnode* vp, uint64 hash, int flags, thread_id td, struct vnode** vpp,
	vfs_hash_cmp_t* fn, void* arg);
void vfs_hash_rehash(struct vnode* vp, uint64 hash);
void vfs_hash_remove(struct vnode* vp);

struct componentname;

void cache_enter(struct vnode* dvp, struct vnode* vp, struct componentname* cnp);

int getnewvnode(const char* tag, struct mount* mp, struct vop_vector* vops, struct vnode** vpp);


/*! In FreeBSD, this tells the VFS to add vp to its list of mp's nodes.
	In Haiku, the equivalent actions are done automatically as part of get_vnode / publish_vnode.
*/
static inline int
insmntque(struct vnode* vp, struct mount* mp)
{
	return 0;
}


/*! In FreeBSD, this generates a serial number based on system time. The driver uses it to
	initialize denode::de_modrev. However, in the Haiku port, de_modrev is ignored.
*/
static inline u_quad_t
init_va_filerev(void)
{
	return 0;
}


/*! Put a ref to vp and write-unlock it.

*/
static inline void
vput(struct vnode* vp)
{
	// The driver might call vput to balance a getnewvnode() call. The getnewvnode stand-in
	// written for the Haiku port, which leaves the node in VSTATE_UNINITIALIZED, doesn't get a
	// ref to the node though.
	if (vp->v_state != VSTATE_UNINITIALIZED)
		put_vnode(vp->v_mount->mnt_fsvolume, VTODE(vp)->de_inode);

	rw_lock_write_unlock(&vp->v_vnlock->haikuRW);
}


/*! Put a ref to vp.

*/
static inline void
vrele(struct vnode* vp)
{
	put_vnode(vp->v_mount->mnt_fsvolume, VTODE(vp)->de_inode);
}


/*! Get a ref to vp.

*/
static inline void
vref(struct vnode* vp)
{
	acquire_vnode(vp->v_mount->mnt_fsvolume, VTODE(vp)->de_inode);
}


/*! Get the node ref count from the VFS. Not implemented in Haiku port (function is used in
	driver but only for debug output).
*/
static __inline int
vrefcnt(struct vnode* vp)
{
	return -1;
}


int vget(struct vnode* vp, int flags);


/*! Prepare the VFS to discard vp.

*/
static inline void
vgone(struct vnode* vp)
{
	remove_vnode(vp->v_mount->mnt_fsvolume, VTODE(vp)->de_inode);
}


int vtruncbuf(struct vnode* vp, off_t length, int blksize);
int vn_fsync_buf(struct vnode* vp, int waitfor);

int vn_vget_ino_gen(struct vnode* vp, vn_get_ino_t alloc, void* alloc_arg, int lkflags,
	struct vnode** rvp);
void vfs_timestamp(struct timespec* tsp);


static inline void
vn_set_state(struct vnode* vp, enum vstate state)
{
	vp->v_state = state;
}


#endif // FAT_VNODE_H