/* $NetBSD: nilfs_fs.h,v 1.5 2024/12/26 21:16:26 andvar Exp $ */

/*
* Copyright (c) 2008, 2009 Reinoud Zandijk
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
*
* NilFS on disc structures
*
* Original definitions written by Koji Sato <[email protected]>
*                    and Ryusuke Konishi <[email protected]>
*/

#ifndef _NILFS_FS_H
#define _NILFS_FS_H

/*
* NiLFS stores ext2fs compatible flags in its Inode. NetBSD uses a comparable
* mechanism with file flags to be mutated with chflags(2).
*
* For completion, i mention all ext2-fs flags currently stored in NiLFS
* inodes.
*/
#define NILFS_SECRM_FL           0x00000001 /* no mapping;    delete securely */
#define NILFS_UNRM_FL            0x00000002 /* no mapping;    allow undelete  */
#define NILFS_SYNC_FL            0x00000008 /* no mapping;    sychrone update */
#define NILFS_IMMUTABLE_FL       0x00000010 /* SF_IMMUTABLE | UF_IMMUTABLE    */
#define NILFS_APPEND_FL          0x00000020 /* SF_APPEND    | UF_APPEND       */
#define NILFS_NODUMP_FL          0x00000040 /* UF_NODUMP                      */
#define NILFS_NOATIME_FL         0x00000080 /* no mapping;    no atime update */
/* intermediate bits are reserved for compression settings */
#define NILFS_NOTAIL_FL          0x00008000 /* no mapping;    dont merge tail */
#define NILFS_DIRSYNC_FL         0x00010000 /* no mapping;    dirsync         */

#define NILFS_FL_USER_VISIBLE    0x0003DFFF /* flags visible to user          */
#define NILFS_FL_USER_MODIFIABLE 0x000380FF /* flags modifiable by user       */



/*
* NiLFS stores files in hierarchical B-trees in tupels of (dkey, dptr).
* Entries in a level N btree point to a btree of level N-1. As dkey value the
* first block number to be found in the level N-1 btree is taken.
*
* To conserve disk space and to reduce an extra lookup, small B-tree's of
* level 0 consisting of only the first [0..NILFS_DIRECT_KEY_MAX> entries are
* stored directly into the inode without dkey. Otherwise the entries point to
* the B-tree's of level N-1.
*
* In all B-trees, but of the system DAT-file, the dptr values are virtual
* block numbers. The dptr values in the B-tree of the system DAT-file are
* physical block numbers since the DAT performs virtual to physical block
* mapping.
*/

#define NILFS_INODE_BMAP_SIZE    7

#define NILFS_BMAP_SIZE         (NILFS_INODE_BMAP_SIZE * sizeof(uint64_t))
#define NILFS_BMAP_INVALID_PTR  0

#define NILFS_DIRECT_NBLOCKS    (NILFS_BMAP_SIZE / sizeof(uint64_t) - 1)
#define NILFS_DIRECT_KEY_MIN    0
#define NILFS_DIRECT_KEY_MAX    (NILFS_DIRECT_NBLOCKS - 1)

#define NILFS_BMAP_SMALL_LOW    NILFS_DIRECT_KEY_MIN
#define NILFS_BMAP_SMALL_HIGH   NILFS_DIRECT_KEY_MAX
#define NILFS_BMAP_LARGE_LOW    NILFS_BTREE_ROOT_NCHILDREN_MAX
#define NILFS_BMAP_LARGE_HIGH   NILFS_BTREE_KEY_MAX


/*
* B-tree header found on all btree blocks and in the direct-entry. Its size
* should be 64 bits. In a direct entry, it is followed by 64 bits block
* numbers for the translation of block [0..NILFS_DIRECT_KEY_MAX>. In large
* bmaps its followed by pairs of 64 bit dkey and 64 bit dptr.
*/

struct nilfs_btree_node {
       uint8_t  bn_flags;              /* btree flags                       */
       uint8_t  bn_level;              /* level of btree                    */
       uint16_t bn_nchildren;          /* number of children in this record */
       uint32_t bn_pad;                /* pad to 64 bits                    */
};


/* btree flags stored in nilfs_btree_node->bn_flags */
#define NILFS_BTREE_NODE_ROOT   0x01
#define NILFS_BMAP_LARGE        0x01    /* equivalent to BTREE_NODE_ROOT */

/* btree levels stored in nilfs_btree_node->bn_level */
#define NILFS_BTREE_LEVEL_DATA          0
#define NILFS_BTREE_LEVEL_NODE_MIN      (NILFS_BTREE_LEVEL_DATA + 1)
#define NILFS_BTREE_LEVEL_MAX           14

/*
* Calculate number of entries that fit into the `direct' space
*/
#define NILFS_BTREE_ROOT_SIZE           NILFS_BMAP_SIZE
#define NILFS_BTREE_ROOT_NCHILDREN_MAX                                  \
       ((NILFS_BTREE_ROOT_SIZE - sizeof(struct nilfs_btree_node)) /    \
        (sizeof(uint64_t /* dkey */) + sizeof(uint64_t /* dptr */)))
#define NILFS_BTREE_ROOT_NCHILDREN_MIN  0

/*
* Calculate number of entries that fit into a non LEVEL_DATA nodes. Each of
* those nodes are padded with one extra 64 bit (extension?)
*/
#define NILFS_BTREE_NODE_EXTRA_PAD_SIZE (sizeof(uint64_t))
#define NILFS_BTREE_NODE_NCHILDREN_MAX(nodesize)                        \
       (((nodesize) - sizeof(struct nilfs_btree_node) -                \
               NILFS_BTREE_NODE_EXTRA_PAD_SIZE) /                      \
        (sizeof(uint64_t /* dkey */) + sizeof(uint64_t /* dptr */)))
#define NILFS_BTREE_NODE_NCHILDREN_MIN(nodesize)                        \
       ((NILFS_BTREE_NODE_NCHILDREN_MAX(nodesize) - 1) / 2 + 1)
#define NILFS_BTREE_KEY_MIN     ( (uint64_t) 0)
#define NILFS_BTREE_KEY_MAX     (~(uint64_t) 0)


/*
* NiLFS inode structure. There are a few dedicated inode numbers that are
* defined here first.
*/

#define NILFS_ROOT_INO           2         /* Root file inode                */
#define NILFS_DAT_INO            3         /* DAT file                       */
#define NILFS_CPFILE_INO         4         /* checkpoint file                */
#define NILFS_SUFILE_INO         5         /* segment usage file             */
#define NILFS_IFILE_INO          6         /* ifile                          */
#define NILFS_ATIME_INO          7         /* Atime file (reserved)          */
#define NILFS_XATTR_INO          8         /* Xattribute file (reserved)     */
#define NILFS_SKETCH_INO         10        /* Sketch file (obsolete)         */
#define NILFS_USER_INO           11        /* First user's file inode number */

struct nilfs_inode {
        uint64_t i_blocks;             /* size in device blocks             */
        uint64_t i_size;               /* size in bytes                     */
        uint64_t i_ctime;              /* creation time in seconds part     */
        uint64_t i_mtime;              /* modification time in seconds part */
        uint32_t i_ctime_nsec;         /* creation time nanoseconds part    */
        uint32_t i_mtime_nsec;         /* modification time in nanoseconds  */
        uint32_t i_uid;                /* user id                           */
        uint32_t i_gid;                /* group id                          */
        uint16_t i_mode;               /* file mode                         */
        uint16_t i_links_count;        /* number of references to the inode */
        uint32_t i_flags;              /* NILFS_*_FL flags                  */
        uint64_t i_bmap[NILFS_INODE_BMAP_SIZE]; /* btree direct/large       */
#define i_device_code     i_bmap[0]     /* 64 bits composed of major+minor   */
        uint64_t i_xattr;              /* reserved for extended attributes  */
        uint32_t i_generation;         /* file generation for NFS           */
        uint32_t i_pad;                /* make it 64 bits aligned           */
};


/*
* In NiLFS each checkpoint/snapshot has a super root.
*
* The super root holds the inodes of the three system files: `dat', `cp' and
* 'su' files. All other FS state is defined by those.
*
* It is crc checksum'ed and time stamped.
*/

struct nilfs_super_root {
        uint32_t sr_sum;               /* check-sum                         */
        uint16_t sr_bytes;             /* byte count of this structure      */
        uint16_t sr_flags;             /* reserved for flags                */
        uint64_t sr_nongc_ctime;       /* timestamp, not for cleaner(?)     */
        struct nilfs_inode sr_dat;     /* DAT, virt->phys translation inode */
        struct nilfs_inode sr_cpfile;  /* CP, checkpoints inode             */
        struct nilfs_inode sr_sufile;  /* SU, segment usage inode           */
};

#define NILFS_SR_MDT_OFFSET(inode_size, i)  \
        ((uint32_t)&((struct nilfs_super_root *)0)->sr_dat + \
                          (inode_size) * (i))
#define NILFS_SR_DAT_OFFSET(inode_size)     NILFS_SR_MDT_OFFSET(inode_size, 0)
#define NILFS_SR_CPFILE_OFFSET(inode_size)  NILFS_SR_MDT_OFFSET(inode_size, 1)
#define NILFS_SR_SUFILE_OFFSET(inode_size)  NILFS_SR_MDT_OFFSET(inode_size, 2)
#define NILFS_SR_BYTES                  (sizeof(struct nilfs_super_root))



/*
* NiLFS has a superblock that describes the basic structure and mount
* history. It also records some sizes of structures found on the disc for
* sanity checks.
*
* The superblock is stored at two places: NILFS_SB_OFFSET_BYTES and
* NILFS_SB2_OFFSET_BYTES.
*/

#define NILFS_DFL_MAX_MNT_COUNT  50      /* default 50 mounts before fsck */
#define NILFS_EIO_RETRY_COUNT    4      /* then give up, not used yet     */

/* File system states stored on disc in superblock's sbp->s_state */
#define NILFS_VALID_FS           0x0001  /* cleanly unmounted and all is ok  */
#define NILFS_ERROR_FS           0x0002  /* there were errors detected, fsck */
#define NILFS_RESIZE_FS          0x0004  /* resize required, XXX unknown flag*/
#define NILFS_MOUNT_STATE_BITS  "\20\1VALID_FS\2ERROR_FS\3RESIZE_FS"

/* Mount option flags passed in Linux; Not used but here for reference */
#define NILFS_MOUNT_ERROR_MODE   0x0070  /* error mode mask */
#define NILFS_MOUNT_ERRORS_CONT  0x0010  /* continue on errors */
#define NILFS_MOUNT_ERRORS_RO    0x0020  /* remount fs ro on errors */
#define NILFS_MOUNT_ERRORS_PANIC 0x0040  /* panic on errors */
#define NILFS_MOUNT_SNAPSHOT     0x0080  /* snapshot flag */
#define NILFS_MOUNT_BARRIER      0x1000  /* use block barriers XXX what is this? */
#define NILFS_MOUNT_STRICT_ORDER 0x2000  /* apply strict in-order; */
                                        /* semantics also for data */

struct nilfs_super_block {
        uint32_t s_rev_level;             /* major disk format revision     */
        uint16_t s_minor_rev_level;       /* minor disc format revision     */
        uint16_t s_magic;                 /* magic value for identification */

        uint16_t s_bytes;                 /* byte count of CRC calculation
                                             for this structure. s_reserved
                                             is excluded! */
        uint16_t s_flags;                 /* linux mount flags, XXX can they
                                             be ignored? */
        uint32_t s_crc_seed;              /* seed value of CRC calculation  */
        uint32_t s_sum;                   /* check sum of super block       */

        /* Block size represented as follows
                       blocksize = 1 << (s_log_block_size + 10) */
        uint32_t s_log_block_size;
        uint64_t s_nsegments;             /* number of segm. in filesystem  */
        uint64_t s_dev_size;              /* block device size in bytes     */
        uint64_t s_first_data_block;      /* 1st seg disk block number      */
        uint32_t s_blocks_per_segment;    /* number of blocks per segment   */
        uint32_t s_r_segments_percentage; /* reserved segments percentage   */

        uint64_t s_last_cno;              /* last checkpoint number         */
        uint64_t s_last_pseg;             /* addr part. segm. written last  */
        uint64_t s_last_seq;              /* seq.number of seg written last */
        uint64_t s_free_blocks_count;     /* free blocks count              */

        uint64_t s_ctime;                 /* creation time (execution time
                                             of newfs) */
        uint64_t s_mtime;                 /* mount time                     */
        uint64_t s_wtime;                 /* write time                     */
        uint16_t s_mnt_count;             /* mount count                    */
        uint16_t s_max_mnt_count;         /* maximal mount count            */
        uint16_t s_state;                 /* file system state              */
        uint16_t s_errors;                /* behaviour on detecting errors  */
        uint64_t s_lastcheck;             /* time of last checked           */

        uint32_t s_checkinterval;         /* max. time between checks       */
        uint32_t s_creator_os;            /* OS that created it             */
        uint16_t s_def_resuid;            /* default uid for reserv. blocks */
        uint16_t s_def_resgid;            /* default gid for reserv. blocks */
        uint32_t s_first_ino;             /* first non-reserved inode       */

        uint16_t s_inode_size;            /* size of an inode               */
        uint16_t s_dat_entry_size;        /* size of a dat entry            */
        uint16_t s_checkpoint_size;       /* size of a checkpoint           */
        uint16_t s_segment_usage_size;    /* size of a segment usage        */

        uint8_t  s_uuid[16];              /* 128-bit uuid for volume        */
        char     s_volume_name[80];       /* volume name                    */

        uint32_t s_c_interval;            /* commit interval of segment     */
        uint32_t s_c_block_max;           /* threshold of data amount for
                                             the segment construction */
        uint32_t s_reserved[192];         /* padding to end of the block    */
};

#define NILFS_SUPER_MAGIC        0x3434    /* NILFS filesystem  magic number */
#define NILFS_SB_OFFSET_BYTES    1024      /* byte offset of nilfs superblock */
#define NILFS_SB2_OFFSET_BYTES(devsize) ((((devsize) >> 12) - 1) << 12)


/* codes for operating systems in superblock */
#define NILFS_OS_LINUX           0
#define NILFS_OS_UNK1            1      /* ext2 */
#define NILFS_OS_UNK2            2      /* ext2 */
#define NILFS_OS_UNK3            3      /* ext2 */
#define NILFS_OS_NETBSD         10      /* temp */

/* NiLFS revision levels */
#define NILFS_CURRENT_REV        2         /* current major revision */
#define NILFS_MINOR_REV          0         /* minor revision */

/* Bytes count of super_block for CRC-calculation */
#define NILFS_SB_BYTES  \
        ((uint32_t)&((struct nilfs_super_block *)0)->s_reserved)

/* Maximal count of links to a file */
#define NILFS_LINK_MAX           32000


/*
* Structure of a directory entry, same as ext2.
*
* The `file_type' is chosen there since filenames are limited to 256 bytes
* and the name_len in ext2 is a two byter.
*
* Note that they can't span blocks; the rec_len fills out.
*/

#define NILFS_NAME_LEN 255
struct nilfs_dir_entry {
        uint64_t inode;                    /* inode number */
        uint16_t rec_len;                  /* directory entry length */
        uint8_t  name_len;                 /* name length */
        uint8_t  file_type;
        char     name[NILFS_NAME_LEN];     /* file name */
        char     pad;
};

/*
* NILFS directory file types.  Only the low 3 bits are used.  The
* other bits are reserved for now.
*/
enum {
        NILFS_FT_UNKNOWN,
        NILFS_FT_REG_FILE,
        NILFS_FT_DIR,
        NILFS_FT_CHRDEV,
        NILFS_FT_BLKDEV,
        NILFS_FT_FIFO,
        NILFS_FT_SOCK,
        NILFS_FT_SYMLINK,
        NILFS_FT_MAX
};

/*
* NILFS_DIR_PAD defines the directory entries boundaries
*
* NOTE: It must be a multiple of 8
*/
#define NILFS_DIR_PAD               8
#define NILFS_DIR_ROUND             (NILFS_DIR_PAD - 1)
#define NILFS_DIR_REC_LEN(name_len) (((name_len) + 12 + NILFS_DIR_ROUND) & \
                                       ~NILFS_DIR_ROUND)

/*
* NiLFS devides the disc into fixed length segments. Each segment is filled
* with one or more partial segments of variable lengths.
*
* Each partial segment has a segment summary header followed by updates of
* files and optionally a super root.
*/

struct nilfs_finfo {
        uint64_t fi_ino;               /* inode number                     */
        uint64_t fi_cno;               /* checkpoint associated with this  */
        uint32_t fi_nblocks;           /* size in blocks of this finfo     */
        uint32_t fi_ndatablk;          /* number of data blocks            */
        /* For the DAT file */
        /*     fi_ndatablk               * nilfs_binfo.bi_dat.bi_blkoff */
        /*     fi_nblocks - fi_ndatablks * nilfs_binfo.bi_dat           */
        /* Other files */
        /*     fi_ndatablk               * nilfs_binfo.bi_v             */
        /*     fi_nblocks - fi_ndatablks * nilfs_binfo.bi_v.bi_vblocknr */
};


/*
* Virtual to physical block translation information. For data blocks it maps
* logical block number bi_blkoff to virtual block nr bi_vblocknr. For non
* datablocks it is the virtual block number assigned to an inserted btree
* level and thus has no bi_blkoff. The physical block number is the next
* available data block in the partial segment after all the finfo's.
*/
struct nilfs_binfo_v {
        uint64_t bi_vblocknr;          /* assigned virtual block number     */
        uint64_t bi_blkoff;            /* for file's logical block number   */
};


/*
* DAT allocation. For data blocks just the logical block number that maps on
* the next available data block in the partial segment after the finfo's.
* Intermediate btree blocks are looked up by their blkoffset dkey and their
* level and given the next available data block.
*/
struct nilfs_binfo_dat {
        uint64_t bi_blkoff;            /* DAT file's logical block number */
        uint8_t bi_level;              /* btree level */
        uint8_t bi_pad[7];
};


/* Convenience union for both types of binfo's */
union nilfs_binfo {
        struct nilfs_binfo_v bi_v;
        struct nilfs_binfo_dat bi_dat;
};


/* The (partial) segment summary itself */
struct nilfs_segment_summary {
        uint32_t ss_datasum;           /* CRC of complete data block        */
        uint32_t ss_sumsum;            /* CRC of segment summary only       */
        uint32_t ss_magic;             /* magic to identify segment summary */
        uint16_t ss_bytes;             /* size of segment summary structure */
        uint16_t ss_flags;             /* NILFS_SS_* flags                  */
        uint64_t ss_seq;               /* sequence number of this segm. sum */
        uint64_t ss_create;            /* creation timestamp in seconds     */
        uint64_t ss_next;              /* blocknumber of next segment       */
        uint32_t ss_nblocks;           /* number of blocks follow           */
        uint32_t ss_nfinfo;            /* number of finfo structures follow */
        uint32_t ss_sumbytes;          /* total size of segment summary     */
        uint32_t ss_pad;
        uint64_t ss_cno;               /* latest checkpoint number known    */
        /* stream of finfo structures */
};

#define NILFS_SEGSUM_MAGIC       0x1eaffa11  /* segment summary magic number */

/* Segment summary flags */
#define NILFS_SS_LOGBGN 0x0001  /* begins a logical segment */
#define NILFS_SS_LOGEND 0x0002  /* ends a logical segment */
#define NILFS_SS_SR     0x0004  /* has super root */
#define NILFS_SS_SYNDT  0x0008  /* includes data only updates */
#define NILFS_SS_GC     0x0010  /* segment written for cleaner operation */
#define NILFS_SS_FLAG_BITS "\20\1LOGBGN\2LOGEND\3SR\4SYNDT\5GC"

/* Segment summary constraints */
#define NILFS_SEG_MIN_BLOCKS     16        /* minimum number of blocks in a
                                             full segment */
#define NILFS_PSEG_MIN_BLOCKS    2         /* minimum number of blocks in a
                                             partial segment */
#define NILFS_MIN_NRSVSEGS       8         /* minimum number of reserved
                                             segments */

/*
* Structure of DAT/inode file.
*
* A DAT file is divided into groups. The maximum number of groups is the
* number of block group descriptors that fit into one block; this descriptor
* only gives the number of free entries in the associated group.
*
* Each group has a block sized bitmap indicating if an entry is taken or
* empty. Each bit stands for a DAT entry.
*
* The inode file has exactly the same format only the entries are inode
* entries.
*/

struct nilfs_block_group_desc {
        uint32_t bg_nfrees;            /* num. free entries in block group  */
};


/* DAT entry in a super root's DAT file */
struct nilfs_dat_entry {
        uint64_t de_blocknr;           /* block number                      */
        uint64_t de_start;             /* valid from checkpoint             */
        uint64_t de_end;               /* valid till checkpoint             */
        uint64_t de_rsv;               /* reserved for future use           */
};


/*
* Structure of CP file.
*
* A snapshot is just a checkpoint only its protected against removal by the
* cleaner. The snapshots are kept on a double linked list of checkpoints.
*/

struct nilfs_snapshot_list {
        uint64_t ssl_next;             /* checkpoint nr. forward */
        uint64_t ssl_prev;             /* checkpoint nr. back    */
};


/* checkpoint entry structure */
struct nilfs_checkpoint {
        uint32_t cp_flags;             /* NILFS_CHECKPOINT_* flags          */
        uint32_t cp_checkpoints_count; /* ZERO, not used anymore?           */
        struct nilfs_snapshot_list cp_snapshot_list; /* list of snapshots   */
        uint64_t cp_cno;               /* checkpoint number                 */
        uint64_t cp_create;            /* creation timestamp                */
        uint64_t cp_nblk_inc;          /* number of blocks incremented      */
        uint64_t cp_inodes_count;      /* number of inodes in this cp.      */
        uint64_t cp_blocks_count;      /* reserved (might be deleted)       */
        struct nilfs_inode cp_ifile_inode;     /* inode file inode          */
};

/* checkpoint flags */
#define NILFS_CHECKPOINT_SNAPSHOT 1
#define NILFS_CHECKPOINT_INVALID  2
#define NILFS_CHECKPOINT_SKETCH   4
#define NILFS_CHECKPOINT_MINOR    8
#define NILFS_CHECKPOINT_BITS "\20\1SNAPSHOT\2INVALID\3SKETCH\4MINOR"


/* header of the checkpoint file */
struct nilfs_cpfile_header {
        uint64_t ch_ncheckpoints;      /* number of checkpoints             */
        uint64_t ch_nsnapshots;        /* number of snapshots               */
        struct nilfs_snapshot_list ch_snapshot_list;   /* snapshot list     */
};

/* to accommodate with the header */
#define NILFS_CPFILE_FIRST_CHECKPOINT_OFFSET    \
       ((sizeof(struct nilfs_cpfile_header) +                          \
         sizeof(struct nilfs_checkpoint) - 1) /                        \
                       sizeof(struct nilfs_checkpoint))


/*
* Structure of SU file.
*
* The segment usage file sums up how each of the segments are used. They are
* indexed by their segment number.
*/

/* segment usage entry */
struct nilfs_segment_usage {
        uint64_t su_lastmod;           /* last modified timestamp           */
        uint32_t su_nblocks;           /* number of blocks in segment       */
        uint32_t su_flags;             /* NILFS_SEGMENT_USAGE_* flags       */
};

/* segment usage flag */
#define NILFS_SEGMENT_USAGE_ACTIVE          1
#define NILFS_SEGMENT_USAGE_DIRTY           2
#define NILFS_SEGMENT_USAGE_ERROR           4
#define NILFS_SEGMENT_USAGE_BITS "\20\1ACTIVE\2DIRTY\3ERROR"


/* header of the segment usage file */
struct nilfs_sufile_header {
        uint64_t sh_ncleansegs;        /* number of segments marked clean   */
        uint64_t sh_ndirtysegs;        /* number of segments marked dirty   */
        uint64_t sh_last_alloc;        /* last allocated segment number     */
        /* ... */
};

/* to accommodate with the header */
#define NILFS_SUFILE_FIRST_SEGMENT_USAGE_OFFSET \
        ((sizeof(struct nilfs_sufile_header) + \
          sizeof(struct nilfs_segment_usage) - 1) / \
                           sizeof(struct nilfs_segment_usage))


#endif