From 5943acb92ce0159e9f482748e4fa4aadddae6851 Mon Sep 17 00:00:00 2001 From: Ludovic Pouzenc Date: Fri, 12 Jun 2015 08:34:26 +0200 Subject: Initial import. RAID 5 xor parity checking is working, data reading on left-assymetric RAID 5 is working. Nothing done on other RAID types. --- myraid.py | 154 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 myraid.py (limited to 'myraid.py') diff --git a/myraid.py b/myraid.py new file mode 100644 index 0000000..60e8b28 --- /dev/null +++ b/myraid.py @@ -0,0 +1,154 @@ +#!/usr/bin/env python + +# RaidGuessFS, a FUSE pseudo-filesystem to guess RAID parameters of a damaged device +# Copyright (C) 2015 Ludovic Pouzenc +# +# This file is part of RaidGuessFS. +# +# RaidGuessFS is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# RaidGuessFS 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 RaidGuessFS. If not, see + +import logging, numpy + +class MyRaid(): + """Auxiliary class, managing RAID layer""" + + def __init__(self, *args, **kwargs): + self.raid_start = 0 + self.raid_end = 0 + self.raid_size = 0 + self.raid_sector_size = 512 + self.raid_chunk_size = 65536 + self.raid_disk_order = range(15) + self.raid_types = [ '0', '1', '5', '5+0' ] + + def _update_raid_size(self): + if self.raid_end > self.raid_start: + self.raid_size = self.raid_end - self.raid_start + else: + self.raid_size = 0 + + def get_raid_start(self): + return self.raid_start + + def get_raid_chunk_size(self): + return self.raid_chunk_size + + def get_raid_disk_order(self): + return self.raid_disk_order + + def get_raid_disk_order_str(self): + return ' '.join(map(str,self.raid_disk_order)) + + def set_raid_start(self, new_raid_start): + """Update the start offset of raid data on underlying disks""" + self.raid_start = new_raid_start + self._update_raid_size() + + def set_raid_end(self, new_raid_end): + """Update the end offset of raid data on underlying disks""" + self.raid_end = new_raid_end + self._update_raid_size() + + def set_raid_chunk_size(self, new_raid_chunk_size): + """Update the size of chucks of data (or slice size)""" + self.raid_chunk_size = new_raid_chunk_size + + def set_raid_disk_order(self, new_raid_disk_order): + """Update the raid logical disk order""" + self.raid_disk_order = new_raid_disk_order + + + def read_data(self,raid_type,disks,offset,size): + """TODO""" + disk_count = len(self.raid_disk_order) + + # This code is RAID 5 only + + slice_no = offset / self.raid_chunk_size + slice_off = offset % self.raid_chunk_size + segment=slice_no/(disk_count-1) + par_disk=(disk_count-1) - (segment % disk_count) # TODO : equivalent a : segment-1 % disk_count ? + data_disk=( par_disk + 1 + (slice_no % (disk_count-1)) ) % disk_count + off_disk = self.raid_start + segment * self.raid_chunk_size + slice_off + + size2 = min(size, (slice_no+1) * self.raid_chunk_size - offset) + + logging.info("raid.read_data(%s): offset=%d,slice_no=%d,slice_off=%d,segment=%d,par_disk=%d,data_disk=%d,off_disk=%d,size2=%d,slice_off+size2=%d" + % (raid_type,offset,slice_no,slice_off,segment,par_disk,data_disk,off_disk,size2,slice_off+size2) ) + + data_fd = disks[self.raid_disk_order[data_disk]] + data_fd.seek(off_disk) + data = data_fd.read(size2) + + # This kills performance but don't make short reads before EOF + #if size2 < size: + # data += self.read_data(self,raid_type,disks,offset+size2,size-size2) + + return data + + def xor_blocks(self,fd_list, offset, size): + """TODO""" + logging.info("Enter xor_blocks(fd_list,%d,%d)"%(offset, size)) + + assert(size % 8 == 0), "Size must be multiple of 8" + dt = numpy.dtype('