/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * extent_tree.h * * Copyright (C) 2009 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. */ /* Useful typedef for passing around writing functions for extent tree root. */ typedef errcode_t (*ocfs2_root_write_func)(ocfs2_filesys *fs, uint64_t blkno, char *root_buf); struct ocfs2_extent_tree { struct ocfs2_extent_tree_operations *et_ops; char *et_root_buf; uint64_t et_root_blkno; ocfs2_root_write_func et_root_write; struct ocfs2_extent_list *et_root_el; void *et_object; uint32_t et_max_leaf_clusters; }; enum ocfs2_contig_type { CONTIG_NONE = 0, CONTIG_LEFT, CONTIG_RIGHT, CONTIG_LEFTRIGHT, }; /* * Operations for a specific extent tree type. * * To implement an on-disk btree (extent tree) type in ocfs2, add * an ocfs2_extent_tree_operations structure and the matching * ocfs2_init__extent_tree() function. That's pretty much it * for the allocation portion of the extent tree. */ struct ocfs2_extent_tree_operations { /* * last_eb_blk is the block number of the right most leaf extent * block. Most on-disk structures containing an extent tree store * this value for fast access. The ->eo_set_last_eb_blk() and * ->eo_get_last_eb_blk() operations access this value. They are * both required. */ void (*eo_set_last_eb_blk)(struct ocfs2_extent_tree *et, uint64_t blkno); uint64_t (*eo_get_last_eb_blk)(struct ocfs2_extent_tree *et); /* * The on-disk structure usually keeps track of how many total * clusters are stored in this extent tree. This function updates * that value. new_clusters is the delta, and must be * added to the total. Required. */ void (*eo_update_clusters)(/*struct inode *inode,*/ struct ocfs2_extent_tree *et, uint32_t new_clusters); uint32_t (*eo_get_clusters)(struct ocfs2_extent_tree *et); /* * If ->eo_insert_check() exists, it is called before rec is * inserted into the extent tree. It is optional. */ /* int (*eo_insert_check)(struct inode *inode, struct ocfs2_extent_tree *et, struct ocfs2_extent_rec *rec); int (*eo_sanity_check)(struct inode *inode, struct ocfs2_extent_tree *et); */ int (*eo_sanity_check)(struct ocfs2_extent_tree *et); /* * -------------------------------------------------------------- * The remaining are internal to ocfs2_extent_tree and don't have * accessor functions */ /* * ->eo_fill_root_el() takes et->et_object and sets et->et_root_el. * It is required. */ void (*eo_fill_root_el)(struct ocfs2_extent_tree *et); /* * ->eo_fill_max_leaf_clusters sets et->et_max_leaf_clusters if * it exists. If it does not, et->et_max_leaf_clusters is set * to 0 (unlimited). Optional. */ void (*eo_fill_max_leaf_clusters)(ocfs2_filesys *fs, struct ocfs2_extent_tree *et); /* * ->eo_extent_contig test whether the 2 ocfs2_extent_rec * are contiguous or not. Optional. Don't need to set it if use * ocfs2_extent_rec as the tree leaf. */ enum ocfs2_contig_type (*eo_extent_contig)(ocfs2_filesys *fs, struct ocfs2_extent_tree *et, struct ocfs2_extent_rec *ext, struct ocfs2_extent_rec *insert_rec); }; void ocfs2_init_dinode_extent_tree(struct ocfs2_extent_tree *et, ocfs2_filesys *fs, char *buf, uint64_t blkno); void ocfs2_init_refcount_extent_tree(struct ocfs2_extent_tree *et, ocfs2_filesys *fs, char *buf, uint64_t blkno); void ocfs2_init_xattr_value_extent_tree(struct ocfs2_extent_tree *et, ocfs2_filesys *fs, char *buf, uint64_t blkno, ocfs2_root_write_func write, struct ocfs2_xattr_value_root *xv); void ocfs2_init_dx_root_extent_tree(struct ocfs2_extent_tree *et, ocfs2_filesys *fs, char *buf, uint64_t blkno); errcode_t ocfs2_tree_insert_extent(ocfs2_filesys *fs, struct ocfs2_extent_tree *et, uint32_t cpos, uint64_t c_blkno, uint32_t clusters, uint16_t flag); int ocfs2_change_extent_flag(ocfs2_filesys *fs, struct ocfs2_extent_tree *et, uint32_t cpos, uint32_t len, uint64_t p_blkno, int new_flags, int clear_flags); int ocfs2_remove_extent(ocfs2_filesys *fs, struct ocfs2_extent_tree *et, uint32_t cpos, uint32_t len); /* * Structures which describe a path through a btree, and functions to * manipulate them. * * The idea here is to be as generic as possible with the tree * manipulation code. */ struct ocfs2_path_item { uint64_t blkno; char *buf; struct ocfs2_extent_list *el; }; #define OCFS2_MAX_PATH_DEPTH 5 struct ocfs2_path { int p_tree_depth; struct ocfs2_path_item p_node[OCFS2_MAX_PATH_DEPTH]; }; #define path_root_blkno(_path) ((_path)->p_node[0].blkno) #define path_root_buf(_path) ((_path)->p_node[0].buf) #define path_root_el(_path) ((_path)->p_node[0].el) #define path_leaf_blkno(_path) ((_path)->p_node[(_path)->p_tree_depth].blkno) #define path_leaf_buf(_path) ((_path)->p_node[(_path)->p_tree_depth].buf) #define path_leaf_el(_path) ((_path)->p_node[(_path)->p_tree_depth].el) #define path_num_items(_path) ((_path)->p_tree_depth + 1) struct ocfs2_path *ocfs2_new_path_from_et(struct ocfs2_extent_tree *et); int ocfs2_find_path(ocfs2_filesys *fs, struct ocfs2_path *path, uint32_t cpos); void ocfs2_free_path(struct ocfs2_path *path);