root/usr/src/uts/common/sys/fssnap.h
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (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
 */
/*
 * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#ifndef _SYS_FSSNAP_H
#define _SYS_FSSNAP_H

#include <sys/sysmacros.h>
#include <sys/devops.h>

#ifdef  __cplusplus
extern "C" {
#endif

#include <sys/buf.h>
#include <sys/taskq.h>
#include <sys/fs/ufs_inode.h>

/* snapshot backend interfaces, macros, and data structures */

#if defined(_KERNEL)

/*
 * defines for the number of threads used to handle tasks, the maximum
 * number of chunks in memory at a time, and the maximum number of tasks to
 * allow before the taskqs start throttling. MAXTASKS should be greater than
 * or equal to MAX_MEM_CHUNKS.
 */
#define FSSNAP_TASKQ_THREADS    (2)
#define FSSNAP_MAX_MEM_CHUNKS   (32)
#define FSSNAP_TASKQ_MAXTASKS   (FSSNAP_MAX_MEM_CHUNKS)

/*
 * It is assumed that a chunk is a multiple of a disk sector so that
 * the chunk size can be reduced before using it as a conversion
 * factor.  Therefore the number of chunks on a file system will
 * always be less than the number of blocks it occupies, and these
 * conversions will not overflow. (do not convert to bytes first!)
 */

typedef unsigned long long      chunknumber_t;

/* disk blocks to snapshot chunks */
#define dbtocowchunk(cmap, dblkno) ((dblkno) / \
        ((cmap)->cmap_chunksz >> DEV_BSHIFT))

/* snapshot chunks to disk blocks */
#define cowchunktodb(cmap, cowchunk) ((cowchunk) * \
        ((cmap)->cmap_chunksz >> DEV_BSHIFT))

/*
 * A snapshot_id is the shared structure between the snapshot driver
 * and the file system.
 */
typedef struct snapshot_id {
        struct snapshot_id      *sid_next;      /* next snapshot in list */
        krwlock_t               sid_rwlock;     /* protects enable/disable */
        struct cow_info         *sid_cowinfo;   /* pointer to cow state */
        uint_t                  sid_snapnumber; /* snapshot number */
        uint_t                  sid_flags;      /* general flags */
        struct vnode            *sid_fvp;       /* root vnode to snapshot */
} snapshot_id_t;

/* snapshot_id flags */
#define SID_DISABLED    (0x01)  /* this snapshot has been disabled */
#define SID_DISABLING   (0x02)  /* this snapshot is being disabled */
#define SID_BLOCK_BUSY  (0x04)  /* snapshot block driver is attached */
#define SID_CHAR_BUSY   (0x08)  /* snapshot character driver is attached */
#define SID_CREATING    (0x10)  /* snapshot is being created */
#define SID_DELETE      (0x20)  /* error condition found, delete snapshot */

/* true if snapshot device is open */
#define SID_BUSY(sidp)  (((sidp)->sid_flags & SID_BLOCK_BUSY) || \
        ((sidp)->sid_flags & SID_CHAR_BUSY))

/* true if snapshot can not be used */
#define SID_INACTIVE(sidp)      (((sidp)->sid_flags & SID_DISABLED) || \
        ((sidp)->sid_flags & SID_DISABLING) || \
        ((sidp)->sid_flags & SID_CREATING) || \
        ((sidp)->sid_flags & SID_DELETE) || \
        ((sidp)->sid_cowinfo == NULL))

/* true if snapshot can be reused now */
#define SID_AVAILABLE(sidp)     (!SID_BUSY(sidp) && \
        ((sidp)->sid_flags & SID_DISABLED))

/*
 * The cow_map keeps track of all translations, and two bitmaps to
 * determine whether the chunk is eligible for translation, and if so
 * whether or not it already has a translation.  The candidate bitmap
 * is read-only and does not require a lock, the hastrans bitmap and
 * the translation table are protected by the cmap_rwlock.
 */
typedef struct cow_map {
        krwlock_t       cmap_rwlock;    /* protects this structure */
        ksema_t         cmap_throttle_sem; /* used to throttle writes */
        uint32_t        cmap_waiters;   /* semaphore waiters */
        uint_t          cmap_chunksz;   /* granularity of COW operations */
        chunknumber_t   cmap_chunksperbf; /* chunks in max backing file */
        chunknumber_t   cmap_nchunks;   /* number of chunks in backing file */
        u_offset_t      cmap_maxsize;   /* max bytes allowed (0 is no limit) */
        size_t          cmap_bmsize;    /* size of bitmaps (in bytes) */
        caddr_t         cmap_candidate; /* 1 = block is a candidate for COW */
        caddr_t         cmap_hastrans;  /* 1 = an entry exists in the table */
        struct cow_map_node     *cmap_table;    /* translation table */
} cow_map_t;

/*
 * The cow_map_node keeps track of chunks that are still in memory.
 */

typedef struct cow_map_node {
        struct cow_map_node     *cmn_next;
        struct cow_map_node     *cmn_prev;
        struct snapshot_id      *cmn_sid;       /* backpointer to snapshot */
        chunknumber_t           cmn_chunk;      /* original chunk number */
        caddr_t                 cmn_buf;        /* the data itself */
        int                     release_sem;    /* flag to release */
                                                /* cmap_throttle_sem */
} cow_map_node_t;

/*
 * The cow_info structure holds basic snapshot state information. It is
 * mostly read-only once the snapshot is created so no locking is required.
 * The exception is cow_nextchunk, which is ever-increasing and updated with
 * atomic_add(). This structure is allocated dynamically, and creation and
 * deletion of the snapshot is protected by the snapshot_mutex variable.
 */
typedef struct cow_info {
        int             cow_backcount;  /* number of backing files */
        vnode_t         **cow_backfile_array; /* array of backing files */
        u_offset_t      cow_backfile_sz;        /* max size of a backfile */
        taskq_t         *cow_taskq;     /* task queue for async writes */
        struct kstat    *cow_kstat_mntpt;       /* kstat for mount point */
        struct kstat    *cow_kstat_bfname;      /* kstat for backing file */
        struct kstat    *cow_kstat_num; /* named numeric kstats */
        struct cow_map  cow_map;        /* block translation table */
} cow_info_t;

/* kstat information */
struct cow_kstat_num {
        kstat_named_t   ckn_state;      /* state of the snapshot device */
        kstat_named_t   ckn_bfsize;     /* sum of sizes of backing files */
        kstat_named_t   ckn_maxsize;    /* maximum backing file size */
        kstat_named_t   ckn_createtime; /* snapshot creation time */
        kstat_named_t   ckn_chunksize;  /* chunk size */
};

/* ckn_state values */
#define COWSTATE_CREATING       (0)     /* snapshot being created */
#define COWSTATE_IDLE           (1)     /* snapshot exists, but not open */
#define COWSTATE_ACTIVE         (2)     /* snapshot open */
#define COWSTATE_DISABLED       (3)     /* snapshot deleted (pending close) */

extern  uint_t  bypass_snapshot_throttle_key;

#endif /* _KERNEL */

#ifdef  __cplusplus
}
#endif

#endif /* _SYS_FSSNAP_H */