Btrfs-progs, btrfsck: add block group check function
Subsystems (2)
RFC PATCH v2 1/1 Btrfs-progs, btrfsck: add block group check function
From: Chen Yang <[email protected]>
This patch adds the function to check correspondence between block group, chunk and device extent.
---v1->v2: optimaze the checking process:
* Remove the checking traversal of block group RB tree.
* Mark block group item which matched with chunk item.
* Output the unmarked block group item error infomaton. when releasing RB tree.
* Merge some relevant flows into one.
--- Makefile | 2 +- btrfsck.c | 517 +++++++++++++++++++++++++++++++++++++++++++++++++++- dev-extent-cache.c | 188 +++++++++++++++++++ dev-extent-cache.h | 60 ++++++ 4 files changed, 760 insertions(+), 7 deletions(-) create mode 100644 dev-extent-cache.c create mode 100644 dev-extent-cache.h
Makefile +1 -1
@@ -4,7 +4,7 @@ CFLAGS = -g -O0 objects = ctree.o disk-io.o radix-tree.o extent-tree.o print-tree.o \ root-tree.o dir-item.o file-item.o inode-item.o \ inode-map.o crc32c.o rbtree.o extent-cache.o extent_io.o \ - volumes.o utils.o btrfs-list.o btrfslabel.o repair.o + volumes.o utils.o btrfs-list.o btrfslabel.o repair.o dev-extent-cache.o cmds_objects = cmds-subvolume.o cmds-filesystem.o cmds-device.o cmds-scrub.o \ cmds-inspect.o cmds-balance.o
btrfsck.c +511 -6
592 lines not on this page · raw message
dev-extent-cache.c new file +188 -0
188 lines not on this page · raw message
dev-extent-cache.h new file +60 -0
60 lines not on this page · raw message
Signature · 1 line
1.7.7
Any comments ?
Quoted 903 lines · Chen Yang
From: Chen Yang <[email protected]>
This patch adds the function to check correspondence between block group, chunk and device extent.
Signed-off-by Cheng Yang <[email protected]>---
v1->v2: optimaze the checking process:
* Remove the checking traversal of block group RB tree.
* Mark block group item which matched with chunk item.
* Output the unmarked block group item error infomaton. when releasing RB tree.
* Merge some relevant flows into one.--- Makefile | 2 +- btrfsck.c | 517 +++++++++++++++++++++++++++++++++++++++++++++++++++- dev-extent-cache.c | 188 +++++++++++++++++++ dev-extent-cache.h | 60 ++++++ 4 files changed, 760 insertions(+), 7 deletions(-) create mode 100644 dev-extent-cache.c create mode 100644 dev-extent-cache.hMakefile +1
-1@@ -4,7 +4,7 @@ CFLAGS = -g -O0 objects = ctree.o disk-io.o radix-tree.o extent-tree.o print-tree.o \ root-tree.o dir-item.o file-item.o inode-item.o \ inode-map.o crc32c.o rbtree.o extent-cache.o extent_io.o \ - volumes.o utils.o btrfs-list.o btrfslabel.o repair.o + volumes.o utils.o btrfs-list.o btrfslabel.o repair.o dev-extent-cache.o cmds_objects = cmds-subvolume.o cmds-filesystem.o cmds-device.o cmds-scrub.o \ cmds-inspect.o cmds-balance.obtrfsck.c +511
-6@@ -34,6 +34,66 @@#include "list.h" #include "version.h" #include "utils.h" +#include "dev-extent-cache.h" + +#define REC_UNCHECKED 0 +#define REC_CHECKED 1 + +struct block_group_record { +struct cache_extent cache; +int state; + +u64 objectid; +u8 type; +u64 offset; + +u64 flags; +}; + +struct dev_record { +struct cache_extent cache; +int state; + +u64 objectid; +u8 type; +u64 offset; + +u64 devid; +u64 total_byte; +u64 byte_used; +}; + +struct stripe { +u64 devid; +u64 offset; +}; + +struct chunk_record { +struct cache_extent cache; +int state; + +u64 objectid; +u8 type; +u64 offset; + +u64 length; +u64 type_flags; +u16 num_stripes; +struct stripe stripes[0 ]; +}; + +struct dev_extent_record { +struct cache_dev_extent cache; +int state; + +u64 objectid; +u8 type; +u64 offset; + +u64 chunk_objecteid; +u64 chunk_offset; +u64 length; +};static u64 bytes_used =0 ;static u64 total_csum_bytes =0 ;@@ -1852,7 +1912,7 @@ static int all_backpointers_checked(struct extent_record *rec, int print_errs) (unsigned long long )rec->start, back->full_backref ?"parent" :"root" , - back->full_backref ? + back->full_backref ? (unsigned long long )dback->parent: (unsigned long long )dback->root, (unsigned long long)dback->owner,@@ -2440,6 +2500,153 @@ static int process_extent_ref_v0(struct cache_tree *extent_cache, }#endif +static int process_chunk_item (struct cache_tree *chunk_cache, +struct btrfs_key *key,struct extent_buffer *eb,int slot) +{ +struct btrfs_chunk *ptr; +struct chunk_record *rec; +int num_stripes, i; +int ret =0 ; + + ptr =btrfs_item_ptr (eb, + slot, struct btrfs_chunk); + + num_stripes =btrfs_chunk_num_stripes (eb, ptr); + + rec =malloc (sizeof (*rec) + + num_stripes *sizeof (*rec->stripes)); +if (!rec) { +fprintf (stderr,"memory allocation failed\n" ); +return -ENOMEM ; + } + + rec->cache.start = key->offset; + rec->cache.size =1 ; + rec->state =REC_UNCHECKED ; + + rec->objectid = key->objectid; + rec->type = key->type; + rec->offset = key->offset; + + rec->length =btrfs_chunk_length (eb, ptr); + rec->type =btrfs_chunk_type (eb, ptr); + rec->num_stripes = num_stripes; + +for (i =0 ; i < rec->num_stripes; ++i) { + rec->stripes[i].devid = +btrfs_stripe_devid_nr (eb, ptr, i); + rec->stripes[i].offset = +btrfs_stripe_offset_nr (eb, ptr, i); + } + + ret =insert_existing_cache_extent ( + chunk_cache, &rec->cache); + +return ret; +} + +static int process_dev_item (struct cache_tree *dev_cache, +struct btrfs_key *key,struct extent_buffer *eb,int slot) +{ +struct btrfs_dev_item *ptr; +struct dev_record *rec; +int ret =0 ; + + ptr =btrfs_item_ptr (eb, + slot, struct btrfs_dev_item); + + rec =malloc (sizeof (*rec)); +if (!rec) { +fprintf (stderr,"memory allocation failed\n" ); +return -ENOMEM ; + } + + rec->cache.start = key->offset; + rec->cache.size =1 ; + rec->state =REC_UNCHECKED ; + + rec->objectid = key->objectid; + rec->type = key->type; + rec->offset = key->offset; + + rec->devid =btrfs_device_id (eb, ptr); + rec->total_byte =btrfs_device_total_bytes (eb, ptr); + rec->byte_used =btrfs_device_bytes_used (eb, ptr); + + ret =insert_existing_cache_extent ( + dev_cache, &rec->cache); + +return ret; +} + +static int process_block_group_item (struct cache_tree *block_group_cache, +struct btrfs_key *key,struct extent_buffer *eb,int slot) +{ +struct btrfs_block_group_item *ptr; +struct block_group_record *rec; +int ret =0 ; + + ptr =btrfs_item_ptr (eb, slot, + struct btrfs_block_group_item); + + rec =malloc (sizeof (*rec)); +if (!rec) { +fprintf (stderr,"memory allocation failed\n" ); +return -ENOMEM ; + } + + rec->cache.start = key->objectid; + rec->cache.size =1 ; + rec->state =REC_UNCHECKED ; + + rec->objectid = key->objectid; + rec->type = key->type; + rec->offset = key->offset; + rec->flags =btrfs_disk_block_group_flags (eb, ptr); + + ret =insert_existing_cache_extent ( + block_group_cache, &rec->cache); + +return ret; +} + +static int process_dev_extent_item (struct dev_extent_tree *dev_extent_cache, +struct btrfs_key *key,struct extent_buffer *eb,int slot) +{ +int ret =0 ; + +struct btrfs_dev_extent *ptr; +struct dev_extent_record *rec; + + ptr =btrfs_item_ptr (eb, + slot, struct btrfs_dev_extent); + + rec =malloc (sizeof (*rec)); +if (!rec) { +fprintf (stderr,"memory allocation failed\n" ); +return -ENOMEM ; + } + + rec->cache.devno = key->objectid; + rec->cache.offset = key->offset; + rec->state =REC_UNCHECKED ; + + rec->objectid = key->objectid; + rec->type = key->type; + rec->offset = key->offset; + + rec->chunk_objecteid = +btrfs_dev_extent_chunk_objectid (eb, ptr); + rec->chunk_offset = +btrfs_dev_extent_chunk_offset (eb, ptr); + rec->length =btrfs_dev_extent_length (eb, ptr); + + ret =insert_existing_cache_dev_extent ( + dev_extent_cache, &rec->cache); + +return ret; +} +static int process_extent_item (struct cache_tree *extent_cache,struct extent_buffer *eb,int slot) {@@ -2531,7 +2738,11 @@ static int run_next_block(struct btrfs_root *root,struct cache_tree *seen, struct cache_tree *reada, struct cache_tree *nodes, - struct cache_tree *extent_cache) + struct cache_tree *extent_cache, + struct cache_tree *chunk_cache, + struct cache_tree *dev_cache, + struct cache_tree *block_group_cache, + struct dev_extent_tree *dev_extent_cache) { struct extent_buffer *buf;u64 bytenr;@@ -2622,8 +2833,24 @@ static int run_next_block(struct btrfs_root *root,btrfs_item_size_nr (buf, i);continue ; } +if (key.type ==BTRFS_CHUNK_ITEM_KEY ) { +process_chunk_item (chunk_cache, &key, buf, i); +continue ; + } +if (key.type ==BTRFS_DEV_ITEM_KEY ) { +process_dev_item (dev_cache, &key, buf, i); +continue ; + }if (key.type ==BTRFS_BLOCK_GROUP_ITEM_KEY ) { +process_block_group_item (block_group_cache, + &key, buf, i); +continue ; + } +if (key.type ==BTRFS_DEV_EXTENT_KEY ) { +process_dev_extent_item (dev_extent_cache, + &key, buf, i);continue ; + }if (key.type ==BTRFS_EXTENT_REF_V0_KEY ) {#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 @@ -2663,7 +2890,7 @@ static int run_next_block(struct btrfs_root *root, ref =btrfs_item_ptr (buf, i, struct btrfs_shared_data_ref);add_data_backref (extent_cache, - key.objectid, key.offset,0 ,0 ,0 , + key.objectid, key.offset,0 ,0 ,0 ,btrfs_shared_data_ref_count (buf, ref),0 , root->sectorsize);continue ;@@ -3366,9 +3593,260 @@ repair_abort:return err; } +static void free_chunk_cache (struct cache_tree *chunk_cache) +{ +struct cache_extent *cache; +while (1 ) { +struct chunk_record *rec; + + cache =find_first_cache_extent (chunk_cache,0 ); +if (!cache) +break ; + rec = container_of(cache, struct chunk_record, cache); +if (rec->state ==REC_UNCHECKED ) { +fprintf (stderr, +"Chunk[%llu, %u, %llu] " +"is not referred by any others\n" , + rec->objectid, + rec->type, + rec->offset); + } + +remove_cache_extent (chunk_cache, &rec->cache); +free (rec); + } +} + +static void free_dev_cache (struct cache_tree *dev_cache) +{ +struct cache_extent *cache; +while (1 ) { +struct dev_record *rec; + + cache =find_first_cache_extent (dev_cache,0 ); +if (!cache) +break ; + rec = container_of(cache, struct dev_record, cache); +if (rec->state ==REC_UNCHECKED ) { +fprintf (stderr, +"Dev[%llu, %u, %llu] " +"is not referred by any others\n" , + rec->objectid, + rec->type, + rec->offset); + } + +remove_cache_extent (dev_cache, &rec->cache); +free (rec); + } +} + +static void free_block_group_cache (struct cache_tree *block_group_cache) +{ +struct cache_extent *cache; +while (1 ) { +struct block_group_record *rec; + + cache =find_first_cache_extent (block_group_cache,0 ); +if (!cache) +break ; + rec = container_of(cache, struct block_group_record, cache); +if (rec->state ==REC_UNCHECKED ) { +fprintf (stderr, +"Block group[%llu, %u, %llu] " +"is not referred by any others\n" , + rec->objectid, + rec->type, + rec->offset); + } + +remove_cache_extent (block_group_cache, &rec->cache); +free (rec); + } +} + +static void free_dev_extent_cache (struct dev_extent_tree *dev_extent_cache) +{ +struct cache_dev_extent *cache; +while (1 ) { +struct dev_extent_record *rec; + + cache =find_first_cache_dev_extent (dev_extent_cache,0 ); +if (!cache) +break ; + rec = container_of(cache, struct dev_extent_record, cache); +if (rec->state ==REC_UNCHECKED ) { +fprintf (stderr, +"Dev extent[%llu, %u, %llu] " +"is not referred by any others\n" , + rec->objectid, + rec->type, + rec->offset); + } + +remove_cache_dev_extent (dev_extent_cache, &rec->cache); +free (rec); + } +} + +/* check btrfs_chunk -> btrfs_dev_extent / btrfs_block_group_item */ +static int check_chunk_refs (struct cache_tree *chunk_cache, +struct cache_tree *block_group_cache, +struct dev_extent_tree *dev_extent_cache) +{ +struct cache_extent *chunk_item; +struct chunk_record *chunk_rec; +int err =0 ; + + chunk_item =find_first_cache_extent (chunk_cache,0 ); +while (chunk_item) { +struct cache_extent *block_group_item; +struct block_group_record *block_group_rec; + +struct cache_dev_extent *dev_extent_item; +struct dev_extent_record *dev_extent_rec; +int i; + + chunk_rec =container_of ( + chunk_item, struct chunk_record, cache); + + block_group_item =find_cache_extent (block_group_cache, + chunk_rec->offset,1 ); +if (block_group_item) { + block_group_rec =container_of (block_group_item, + struct block_group_record, cache); + +if (chunk_rec->length != block_group_rec->offset) + err =-2 ; +if (chunk_rec->offset != block_group_rec->objectid) + err =-2 ; +if (chunk_rec->type != block_group_rec->flags) + err =-2 ; + +if (err !=0 ) { +BUG_ON (1 ); +fprintf (stderr, +"Chunk[%llu, %u, %llu]: " +"length(%llu), offset(%llu), type(%llu) " +"mismatch with block group[%llu, %u, %llu]: " +"offset(%llu), objectid(%llu), flags(%llu)\n" , + chunk_rec->objectid, + chunk_rec->type, + chunk_rec->offset, + chunk_rec->length, + chunk_rec->offset, + chunk_rec->type_flags, + block_group_rec->objectid, + block_group_rec->type, + block_group_rec->offset, + block_group_rec->offset, + block_group_rec->objectid, + block_group_rec->flags); + } + + block_group_rec->state =REC_CHECKED ; + chunk_rec->state =REC_CHECKED ; + }else { +fprintf (stderr, +"Chunk[%llu, %u, %llu]: " +"length(%llu), offset(%llu), type(%llu) " +"is not found in block group\n" , + chunk_rec->objectid, + chunk_rec->type, + chunk_rec->offset, + chunk_rec->length, + chunk_rec->offset, + chunk_rec->type_flags); + err =-1 ; + } + +for (i =0 ; i < chunk_rec->num_stripes; ++i) { + dev_extent_item =find_cache_dev_extent ( + dev_extent_cache, + chunk_rec->stripes[i].devid, + chunk_rec->stripes[i].offset); +if (dev_extent_item) { + dev_extent_rec =container_of (dev_extent_item, + struct dev_extent_record, cache); + dev_extent_rec->state =REC_CHECKED ; + chunk_rec->state =REC_CHECKED ; + }else { +fprintf (stderr, +"Chunk[%llu, %u, %llu] stripe[%llu, %llu]" +"is not found in dev extent\n" , + chunk_rec->objectid, + chunk_rec->type, + chunk_rec->offset, + chunk_rec->stripes[i].devid, + chunk_rec->stripes[i].offset); + err =-1 ; + } + } + + chunk_item =next_cache_extent (chunk_item); + } +return err; +} + +/* check btrfs_dev_item -> btrfs_dev_extent */ +static int check_dev_refs (struct cache_tree *dev_cache, +struct dev_extent_tree *dev_extent_cache) +{ +struct cache_extent *dev_item; +struct dev_record *dev_rec; +int err =0 ; + + dev_item =find_first_cache_extent (dev_cache,0 ); +while (dev_item) { +struct cache_dev_extent *dev_extent_item; +struct dev_extent_record *dev_extent_rec; +u64 total_byte =0 ; + + dev_rec = container_of(dev_item, struct dev_record, cache); + + dev_extent_item =find_first_cache_dev_extent ( + dev_extent_cache,0 ); +while (dev_extent_item) { + dev_extent_rec =container_of (dev_extent_item, + struct dev_extent_record, cache); + +if (dev_extent_rec->objectid == dev_rec->devid) + total_byte += dev_extent_rec->length; + + dev_extent_item =next_cache_dev_extent ( + dev_extent_item); + } + +if (total_byte != dev_rec->byte_used) { + err =-2 ; + +BUG_ON (1 ); +fprintf (stderr, +"Dev extent's total-byte(%llu)" +"is not equal to byte-used(%llu) in" +"dev[%llu, %u, %llu]\n" , + total_byte, + dev_rec->byte_used, + dev_rec->objectid, + dev_rec->type, + dev_rec->offset); + } + + dev_rec->state =REC_CHECKED ; + + dev_item =next_cache_extent (dev_item); + } +return err; +} +static int check_extents (struct btrfs_trans_handle *trans,struct btrfs_root *root,int repair) { +struct cache_tree dev_cache; +struct cache_tree chunk_cache; +struct cache_tree block_group_cache; +struct dev_extent_tree dev_extent_cache; +struct cache_tree extent_cache;struct cache_tree seen;struct cache_tree pending;@@ -3378,7 +3856,7 @@ static int check_extents(struct btrfs_trans_handle *trans,struct btrfs_path path;struct btrfs_key key;struct btrfs_key found_key; -int ret; +int ret, err =0 ;u64 last =0 ;struct block_info *bits;int bits_nr;@@ -3386,6 +3864,11 @@ static int check_extents(struct btrfs_trans_handle *trans,int slot;struct btrfs_root_item ri; +cache_tree_init (&dev_cache); +cache_tree_init (&chunk_cache); +cache_tree_init (&block_group_cache); +dev_extent_tree_init (&dev_extent_cache); +cache_tree_init (&extent_cache);cache_tree_init (&seen);cache_tree_init (&pending);@@ -3452,11 +3935,28 @@ static int check_extents(struct btrfs_trans_handle *trans,btrfs_release_path (root, &path);while (1 ) { ret =run_next_block (root, bits, bits_nr, &last, &pending, - &seen, &reada, &nodes, &extent_cache); + &seen, &reada, &nodes, &extent_cache, + &chunk_cache, &dev_cache, + &block_group_cache, &dev_extent_cache);if (ret !=0 )break ; } ret =check_extent_refs (trans, root, &extent_cache, repair); +if (ret) { + err =1 ; +fprintf (stderr,"Errors found in extent checking\n" ); + } + ret =check_chunk_refs (&chunk_cache, + &block_group_cache, &dev_extent_cache); +if (ret) { + err =1 ; +fprintf (stderr,"Errors found in chunk refs checking\n" ); + } + ret =check_dev_refs (&dev_cache, &dev_extent_cache); +if (ret) { + err =1 ; +fprintf (stderr,"Errors found in dev refs checking\n" ); + }if (repair) {free_corrupt_blocks (root->fs_info);@@ -3465,7 +3965,12 @@ static int check_extents(struct btrfs_trans_handle *trans, root->fs_info->corrupt_blocks =NULL ; } -return ret; +free_chunk_cache (&chunk_cache); +free_dev_cache (&dev_cache); +free_block_group_cache (&block_group_cache); +free_dev_extent_cache (&dev_extent_cache); + +return err; }static void print_usage (void )dev-extent-cache.c new file +188
-0@@ -0,0 +1,188 @@ +/* +* Copyright (C) 2012 Fujitsu. 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 v2 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. +* +* You should have received a copy of the GNU General Public +* License along with this program; if not, write to the +* Free Software Foundation, Inc., 59 Temple Place - Suite 330, +* Boston, MA 021110-1307, USA. +*/ +#include <stdio.h> +#include <stdlib.h> +#include "kerncompat.h" +#include "dev-extent-cache.h" + +void dev_extent_tree_init (struct dev_extent_tree *tree) +{ + tree->root.rb_node =NULL ; +} + +static struct rb_node *tree_insert (struct rb_root *root,u64 devno, +u64 offset,struct rb_node *node) +{ +struct rb_node **p = &root->rb_node; +struct rb_node *parent =NULL ; +struct cache_dev_extent *entry; + +while (*p) { + parent = *p; + entry = rb_entry(parent, struct cache_dev_extent, rb_node); + +if (devno == entry->devno) { +if (offset < entry->offset) + p = &(*p)->rb_left; +else if (offset > entry->offset) + p = &(*p)->rb_right; +else +return parent; + }else { +if (devno < entry->devno) + p = &(*p)->rb_left; +else if (devno > entry->devno) + p = &(*p)->rb_right; +else +return parent; + } + } + + entry = rb_entry(parent, struct cache_dev_extent, rb_node); +rb_link_node (node, parent, p); +rb_insert_color (node, root); +return NULL ; +} + +static struct rb_node *__tree_search (struct rb_root *root,u64 devno, +u64 offset,struct rb_node **prev_ret) +{ +struct rb_node *n = root->rb_node; +struct rb_node *prev =NULL ; +struct cache_dev_extent *entry; +struct cache_dev_extent *prev_entry =NULL ; + +while (n) { + entry = rb_entry(n, struct cache_dev_extent, rb_node); + prev = n; + prev_entry = entry; + +if (devno == entry->devno) { +if (offset < entry->offset) + n = n->rb_left; +else if (offset > entry->offset) + n = n->rb_right; +else +return n; + }else { +if (devno < entry->devno) + n = n->rb_left; +else if (devno > entry->devno) + n = n->rb_right; +else +return n; + } + } +if (!prev_ret) +return NULL ; + +while (prev && devno >= prev_entry->devno + prev_entry->offset) { + prev =rb_next (prev); + prev_entry = rb_entry(prev, struct cache_dev_extent, rb_node); + } + *prev_ret = prev; +return NULL ; +} + +struct cache_dev_extent *alloc_cache_dev_extent (u64 devno,u64 offset) +{ +struct cache_dev_extent *pe =malloc (sizeof (*pe)); + +if (!pe) +return pe; + pe->devno = devno; + pe->offset = offset; +return pe; +} + +int insert_existing_cache_dev_extent (struct dev_extent_tree *tree, +struct cache_dev_extent *pe) +{ +struct rb_node *found; + + found =tree_insert (&tree->root, pe->devno, pe->offset, &pe->rb_node); +if (found) +return -EEXIST ; + +return 0 ; +} + +int insert_cache_dev_extent (struct dev_extent_tree *tree,u64 devno,u64 offset) +{ +struct cache_dev_extent *pe =alloc_cache_dev_extent (devno, offset); +int ret; + ret =insert_existing_cache_dev_extent (tree, pe); +if (ret) +free (pe); +return ret; +} + +struct cache_dev_extent *find_cache_dev_extent (struct dev_extent_tree *tree, +u64 devno,u64 offset) +{ +struct rb_node *prev; +struct rb_node *ret; +struct cache_dev_extent *entry; + ret =__tree_search (&tree->root, devno, offset, &prev); +if (!ret) +return NULL ; + + entry = rb_entry(ret, struct cache_dev_extent, rb_node); +return entry; +} + +struct cache_dev_extent *find_first_cache_dev_extent ( +struct dev_extent_tree *tree,u64 devno) +{ +struct rb_node *prev; +struct rb_node *ret; +struct cache_dev_extent *entry; + + ret =__tree_search (&tree->root, devno,1 , &prev); +if (!ret) + ret = prev; +if (!ret) +return NULL ; + entry = rb_entry(ret, struct cache_dev_extent, rb_node); +return entry; +} + +struct cache_dev_extent *prev_cache_dev_extent (struct cache_dev_extent *pe) +{ +struct rb_node *node =rb_prev (&pe->rb_node); + +if (!node) +return NULL ; + return rb_entry(node, struct cache_dev_extent, rb_node); +} + +struct cache_dev_extent *next_cache_dev_extent (struct cache_dev_extent *pe) +{ +struct rb_node *node =rb_next (&pe->rb_node); + +if (!node) +return NULL ; + return rb_entry(node, struct cache_dev_extent, rb_node); +} + +void remove_cache_dev_extent (struct dev_extent_tree *tree, +struct cache_dev_extent *pe) +{ +rb_erase (&pe->rb_node, &tree->root); +} +dev-extent-cache.h new file +60
-0@@ -0,0 +1,60 @@ +/* +* Copyright (C) 2012 Fujitsu. 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 v2 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. +* +* You should have received a copy of the GNU General Public +* License along with this program; if not, write to the +* Free Software Foundation, Inc., 59 Temple Place - Suite 330, +* Boston, MA 021110-1307, USA. +*/ + +#ifndef __PENDING_DEV_EXTENT__ +#define __PENDING_DEV_EXTENT__ +#include "kerncompat.h" +#include "rbtree.h" + +struct dev_extent_tree { +struct rb_root root; +}; + +struct cache_dev_extent { +struct rb_node rb_node; +u64 devno; +u64 offset; +}; + +void dev_extent_tree_init (struct dev_extent_tree *tree); +void remove_cache_dev_extent (struct dev_extent_tree *tree, +struct cache_dev_extent *pe); +struct cache_dev_extent *find_first_cache_dev_extent ( +struct dev_extent_tree *tree,u64 devno); +struct cache_dev_extent *prev_cache_dev_extent (struct cache_dev_extent *pe); +struct cache_dev_extent *next_cache_dev_extent (struct cache_dev_extent *pe); +struct cache_dev_extent *find_cache_dev_extent (struct dev_extent_tree *tree, +u64 devno,u64 offset); +int insert_cache_dev_extent (struct dev_extent_tree *tree, +u64 devno,u64 offset); +int insert_existing_cache_dev_extent (struct dev_extent_tree *tree, +struct cache_dev_extent *pe); + +static inline int dev_extent_tree_empty (struct dev_extent_tree *tree) +{ +return RB_EMPTY_ROOT (&tree->root); +} + +static inline void free_cache_dev_extent (struct cache_dev_extent *pe) +{ +free (pe); +} + +struct cache_dev_extent *alloc_pending_dev_extent (u64 devno,u64 offset); + +#endif