root/usr/src/uts/common/sys/fs/hsfs_node.h
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * High Sierra filesystem structure definitions
 */
/*
 * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#ifndef _SYS_FS_HSFS_NODE_H
#define _SYS_FS_HSFS_NODE_H

#ifdef  __cplusplus
extern "C" {
#endif

#include <sys/taskq.h>

struct  hs_direntry {
        uint_t          ext_lbn;        /* LBN of start of extent */
        uint_t          ext_size;       /* no. of data bytes in extent */
        struct timeval  cdate;          /* creation date */
        struct timeval  mdate;          /* last modification date */
        struct timeval  adate;          /* last access date */
        enum vtype      type;           /* file type */
        mode_t          mode;           /* mode and type of file (UNIX) */
        uint_t          nlink;          /* no. of links to file */
        uid_t           uid;            /* owner's user id */
        gid_t           gid;            /* owner's group id */
        ino64_t         inode;          /* inode number from rrip data */
        dev_t           r_dev;          /* major/minor device numbers */
        uint_t          xar_prot :1;    /* 1 if protection in XAR */
        uchar_t         xar_len;        /* no. of Logical blocks in XAR */
        uchar_t         intlf_sz;       /* intleaving size */
        uchar_t         intlf_sk;       /* intleaving skip factor */
        ushort_t        sym_link_flag;  /* flags for sym link */
        char            *sym_link;      /* path of sym link for readlink() */
};

struct  ptable {
        uchar_t filler[7];              /* filler */
        uchar_t dname_len;              /* length of directory name */
        uchar_t dname[HS_DIR_NAMELEN+1];        /* directory name */
};

struct ptable_idx {
        struct ptable_idx *idx_pptbl_idx; /* parent's path table index entry */
        struct ptable   *idx_mptbl;     /* path table entry for myself */
        ushort_t idx_nochild;           /* no. of children */
        ushort_t idx_childid;           /* directory no of first child */
};

/*
 * hsnode structure:
 *
 * hs_offset, hs_ptbl_idx, base  apply to VDIR type only
 *
 * nodeid uniquely identifies an hsnode, ISO9660 means
 * nodeid can be very big.
 * For directories it is the disk address of
 * the data extent of the dir (the directory itself,
 * ".", and ".." all point to same data extent).
 * For non-directories, it is the disk address of the
 * directory entry for the file; note that this does
 * not permit hard links, as it assumes a single dir
 * entry per file.
 */

struct  hsnode {
        struct hsnode   *hs_hash;       /* next hsnode in hash list */
        struct hsnode   *hs_freef;      /* next hsnode in free list */
        struct hsnode   *hs_freeb;      /* previous hsnode in free list */
        struct vnode    *hs_vnode;      /* the real vnode for the file */
        struct hs_direntry hs_dirent;   /* the directory entry for this file */
        ino64_t         hs_nodeid;      /* "inode" number for hsnode */
        uint_t          hs_dir_lbn;     /* LBN of directory entry */
        uint_t          hs_dir_off;     /* offset in LBN of directory entry */
        struct ptable_idx       *hs_ptbl_idx;   /* path table index */
        uint_t          hs_offset;      /* start offset in dir for searching */
        long            hs_mapcnt;      /* mappings to file pages */
        uint_t          hs_seq;         /* sequence number */
        uint_t          hs_flags;       /* (see below) */
        u_offset_t      hs_prev_offset; /* Last read end offset (readahead) */
        int             hs_num_contig;  /* Count of contiguous reads */
        int             hs_ra_bytes;    /* Bytes to readahead */
        kmutex_t        hs_contents_lock;       /* protects hsnode contents */
                                                /*      except hs_offset */
};

/* hs_flags */
#define HREF    1                       /* hsnode is referenced */

/* hs_modes */

#define HFDIR   0040000                 /* directory */
#define HFREG   0100000                 /* regular file */

struct  hsfid {
        ushort_t        hf_len;         /* length of fid */
        ushort_t        hf_dir_off;     /* offset in LBN of directory entry */
        uint_t          hf_dir_lbn;     /* LBN of directory */
        uint32_t        hf_ino;         /* The inode number or HS_DUMMY_INO */
};


/*
 * All of the fields in the hs_volume are read-only once they have been
 * initialized.
 */
struct  hs_volume {
        ulong_t         vol_size;       /* no. of Logical blocks in Volume */
        uint_t          lbn_size;       /* no. of bytes in a block */
        uint_t          lbn_shift;      /* shift to convert lbn to bytes */
        uint_t          lbn_secshift;   /* shift to convert lbn to sec */
        uint_t          lbn_maxoffset;  /* max lbn-relative offset and mask */
        uchar_t         file_struct_ver; /* version of directory structure */
        uid_t           vol_uid;        /* uid of volume */
        gid_t           vol_gid;        /* gid of volume */
        uint_t          vol_prot;       /* protection (mode) of volume */
        struct timeval  cre_date;       /* volume creation time */
        struct timeval  mod_date;       /* volume modification time */
        struct  hs_direntry root_dir;   /* dir entry for Root Directory */
        ushort_t        ptbl_len;       /* number of bytes in Path Table */
        uint_t          ptbl_lbn;       /* logical block no of Path Table */
        ushort_t        vol_set_size;   /* number of CD in this vol set */
        ushort_t        vol_set_seq;    /* the sequence number of this CD */
        char            vol_id[32];             /* volume id in PVD */
};

/*
 * The hsnode table is no longer fixed in size but grows
 * and shrinks dynamically. However a cache of nodes is still maintained
 * for efficiency. This cache size (nhsnode) is a tunable which
 * is either specified in /etc/system or calculated as the number
 * that will fit into the number of bytes defined by HS_HSNODESPACE (below).
 */
#define HS_HASHSIZE     32              /* hsnode hash table size */
#define HS_HSNODESPACE  16384           /* approx. space used for hsnodes */

/*
 * We usually use the starting extent LBA for the inode numbers of files and
 * directories. As this will not work for zero sized files, we assign a dummy
 * inode number to all zero sized files. We use the number 16 as this is the
 * LBA for the PVD, this number cannot be a valid starting extent LBA for a
 * file. In case that the node number is the HS_DUMMY_INO, we use the LBA and
 * offset of the directory entry of this file (which is what we used before
 * we started to support correct hard links).
 */
#define HS_DUMMY_INO    16      /* dummy inode number for empty files */

/*
 * Hsfs I/O Scheduling parameters and data structures.
 * Deadline for reads is set at 5000 usec.
 */
#define HSFS_READ_DEADLINE 5000
#define HSFS_NORMAL 0x0

/*
 * This structure holds information for a read request that is enqueued
 * for processing by the scheduling function. An AVL tree is used to
 * access the read requests in a sorted manner.
 */
struct hio {
        struct buf      *bp;            /* The buf for this read */
        struct hio      *contig_chain;  /* Next adjacent read if any */
        offset_t        io_lblkno;      /* Starting disk block of io */
        u_offset_t      nblocks;        /* # disk blocks */
        uint64_t        io_timestamp;   /* usec timestamp for deadline */
        ksema_t         *sema;          /* Completion flag */
        avl_node_t      io_offset_node; /* Avl tree requirements */
        avl_node_t      io_deadline_node;
};

/*
 * This structure holds information about all the read requests issued
 * during a read-ahead invocation. This is then enqueued on a task-queue
 * for processing by a background thread that takes this read-ahead to
 * completion and cleans up.
 */
struct hio_info {
        struct buf      *bufs;  /* array of bufs issued for this R/A */
        caddr_t         *vas;   /* The kmem_alloced chunk for the bufs */
        ksema_t         *sema;  /* Semaphores used in the bufs */
        uint_t          bufsused; /* # of bufs actually used */
        uint_t          bufcnt;   /* Tot bufs allocated. */
        struct page     *pp;      /* The list of I/O locked pages */
        struct hsfs     *fsp; /* The filesystem structure */
};

/*
 * This is per-filesystem structure that stores toplevel data structures for
 * the I/O scheduler.
 */
struct hsfs_queue {
        /*
         * A dummy hio holding the LBN of the last read processed. Easy
         * to use in AVL_NEXT for Circular Look behavior.
         */
        struct hio      *next;

        /*
         * A pre-allocated buf for issuing coalesced reads. The scheduling
         * function is mostly single threaded by necessity.
         */
        struct buf      *nbuf;
        kmutex_t        hsfs_queue_lock; /* Protects the AVL trees */

        /*
         * Makes most of the scheduling function Single-threaded.
         */
        kmutex_t        strategy_lock;
        avl_tree_t      read_tree;       /* Reads ordered by LBN */
        avl_tree_t      deadline_tree;   /* Reads ordered by timestamp */
        taskq_t         *ra_task;        /* Read-ahead Q */
        int             max_ra_bytes;    /* Max read-ahead quantum */

        /* Device Max Transfer size in DEV_BSIZE */
        uint_t          dev_maxtransfer;
};

/*
 * High Sierra filesystem structure.
 * There is one of these for each mounted High Sierra filesystem.
 */
enum hs_vol_type {
        HS_VOL_TYPE_HS = 0, HS_VOL_TYPE_ISO = 1, HS_VOL_TYPE_ISO_V2 = 2,
        HS_VOL_TYPE_JOLIET = 3
};
#define HSFS_MAGIC 0x03095500
struct hsfs {
        struct hsfs     *hsfs_next;     /* ptr to next entry in linked list */
        long            hsfs_magic;     /* should be HSFS_MAGIC */
        struct vfs      *hsfs_vfs;      /* vfs for this fs */
        struct vnode    *hsfs_rootvp;   /* vnode for root of filesystem */
        struct vnode    *hsfs_devvp;    /* device mounted on */
        enum hs_vol_type hsfs_vol_type; /* see above */
        struct hs_volume hsfs_vol;      /* File Structure Volume Descriptor */
        struct ptable   *hsfs_ptbl;     /* pointer to incore Path Table */
        int             hsfs_ptbl_size; /* size of incore path table */
        struct ptable_idx *hsfs_ptbl_idx; /* pointer to path table index */
        int             hsfs_ptbl_idx_size;     /* no. of path table index */
        ulong_t         hsfs_ext_impl;  /* ext. information bits */
        ushort_t        hsfs_sua_off;   /* the SUA offset */
        ushort_t        hsfs_namemax;   /* maximum file name length */
        ushort_t        hsfs_namelen;   /* "official" max. file name length */
        ulong_t         hsfs_err_flags; /* ways in which fs is non-conformant */
        char            *hsfs_fsmnt;    /* name mounted on */
        ulong_t         hsfs_flags;     /* hsfs-specific mount flags */
        krwlock_t       hsfs_hash_lock; /* protect hash table & hst_nohsnode */
        struct hsnode   *hsfs_hash[HS_HASHSIZE]; /* head of hash lists */
        uint32_t        hsfs_nohsnode;  /* no. of allocated hsnodes */
        kmutex_t        hsfs_free_lock; /* protects free list */
        struct hsnode   *hsfs_free_f;   /* first entry of free list */
        struct hsnode   *hsfs_free_b;   /* last entry of free list */

        /*
         * Counters exported through kstats.
         */
        uint64_t        physical_read_bytes;
        uint64_t        cache_read_pages;
        uint64_t        readahead_bytes;
        uint64_t        coalesced_bytes;
        uint64_t        total_pages_requested;
        kstat_t         *hsfs_kstats;

        struct hsfs_queue *hqueue;      /* I/O Scheduling parameters */
};

/*
 * Error types: bit offsets into hsfs_err_flags.
 * Also serves as index into hsfs_error[], so must be
 * kept in sync with that data structure.
 */
#define HSFS_ERR_TRAILING_JUNK          0
#define HSFS_ERR_LOWER_CASE_NM          1
#define HSFS_ERR_BAD_ROOT_DIR           2
#define HSFS_ERR_UNSUP_TYPE             3
#define HSFS_ERR_BAD_FILE_LEN           4
#define HSFS_ERR_BAD_JOLIET_FILE_LEN    5
#define HSFS_ERR_TRUNC_JOLIET_FILE_LEN  6
#define HSFS_ERR_BAD_DIR_ENTRY          7
#define HSFS_ERR_NEG_SUA_LEN            8
#define HSFS_ERR_BAD_SUA_LEN            9

#define HSFS_HAVE_LOWER_CASE(fsp) \
        ((fsp)->hsfs_err_flags & (1 << HSFS_ERR_LOWER_CASE_NM))


/*
 * File system parameter macros
 */
#define hs_blksize(HSFS, HSP, OFF)      /* file system block size */ \
        ((HSP)->hs_vn.v_flag & VROOT ? \
            ((OFF) >= \
                ((HSFS)->hsfs_rdirsec & ~((HSFS)->hsfs_spcl - 1))*HS_SECSIZE ?\
                ((HSFS)->hsfs_rdirsec & ((HSFS)->hsfs_spcl - 1))*HS_SECSIZE :\
                (HSFS)->hsfs_clsize): \
            (HSFS)->hsfs_clsize)
#define hs_blkoff(OFF)          /* offset within block */ \
        ((OFF) & (HS_SECSIZE - 1))

/*
 * Conversion macros
 */
#define VFS_TO_HSFS(VFSP)       ((struct hsfs *)(VFSP)->vfs_data)
#define HSFS_TO_VFS(FSP)        ((FSP)->hsfs_vfs)

#define VTOH(VP)                ((struct hsnode *)(VP)->v_data)
#define HTOV(HP)                (((HP)->hs_vnode))

/*
 * Convert between Logical Block Number and Sector Number.
 */
#define LBN_TO_SEC(lbn, vfsp)   ((lbn)>>((struct hsfs *)((vfsp)->vfs_data))->  \
                                hsfs_vol.lbn_secshift)

#define SEC_TO_LBN(sec, vfsp)   ((sec)<<((struct hsfs *)((vfsp)->vfs_data))->  \
                                hsfs_vol.lbn_secshift)

#define LBN_TO_BYTE(lbn, vfsp)  ((lbn)<<((struct hsfs *)((vfsp)->vfs_data))->  \
                                hsfs_vol.lbn_shift)
#define BYTE_TO_LBN(boff, vfsp) ((boff)>>((struct hsfs *)((vfsp)->vfs_data))-> \
                                hsfs_vol.lbn_shift)

#ifdef  __cplusplus
}
#endif

#endif  /* _SYS_FS_HSFS_NODE_H */