diff options
-rw-r--r-- | mydisks.py | 1 | ||||
-rw-r--r-- | myraid.py | 83 | ||||
-rwxr-xr-x | raidguessfs.py | 63 |
3 files changed, 81 insertions, 66 deletions
@@ -26,6 +26,7 @@ class MyDisks(): def __init__(self, *args, **kwargs): self.disks = [] self.disk_paths = [] + self.sector_size = 512 self.disk_count = 0 self.disks_size = [0] self.max_disks = 16 @@ -19,24 +19,24 @@ # along with RaidGuessFS. If not, see <http://www.gnu.org/licenses/> import logging -from myraidmaths import MyRaidMaths +import myraidmaths class MyRaid(): """Auxiliary class, managing RAID layer""" RAID_TYPES = [ '0', '1', '5', '5+0' ] RAID5_LAYOUTS = [ 'la', 'ra', 'ls', 'rs' ] - def __init__(self, *args, **kwargs): - self.d = None + def __init__(self, mydisks): + self.d = mydisks self.raid_start = 0 self.raid_end = 0 - self.raid_sector_size = 512 # TODO : should be self.d.sector_size self.raid_chunk_size = 65536 self.raid_disk_order = [] self.raid_disk_count = 0 + self.raid_type = '5' self.raid_layout = 'ls' self.raid_disks = [] - self.nested_subraid = 2 + self.raid_subraid_count = 2 def get_raid_start(self): return self.raid_start @@ -53,9 +53,15 @@ class MyRaid(): def get_raid_disk_order_str(self): return ' '.join(map(str,self.raid_disk_order)) + def get_raid_type(self): + return self.raid_type + def get_raid_layout(self): return self.raid_layout + def get_raid_subraid_count(self): + return self.raid_subraid_count + def set_disks(self, new_mydisks): # FIXME : self.d don't need to be updaed (pass on __init__) self.d = new_mydisks @@ -89,75 +95,86 @@ class MyRaid(): self.raid_disk_order = new_raid_disk_order self.raid_disks = [ self.d.disks[i] for i in self.raid_disk_order ] + def set_raid_type(self, new_raid_type): + if new_raid_type in MyRaid.RAID_TYPES: + self.raid_type = new_raid_type + else: + raise ValueError('raid_type has to be one of %s'%' '.join(MyRaid.RAID_TYPES)) + + def set_raid_subraid_count(self, new_raid_subraid_count): + """Update the number of subcomponents in nested RAID levels""" + self.raid_subraid_count = new_raid_subraid_count + def set_raid_layout(self, new_raid_layout): + """Update the kind of data/parity block layout for RAID5 family""" if new_raid_layout in MyRaid.RAID5_LAYOUTS: self.raid_layout = new_raid_layout else: - raise ValueError('raid_layout has to be one of %s'%' '.join(RAID_LAYOUTS)) + raise ValueError('raid_layout has to be one of %s'%' '.join(MyRaid.RAID_LAYOUTS)) - def sizeof_raid_result(self, raid_type): + def sizeof_raid_result(self): size = max(0, self.raid_end - self.raid_start) return { '0' : size * self.raid_disk_count, '1' : size if self.raid_disk_count == 2 else 0, '5' : size * (self.raid_disk_count - 1) if self.raid_disk_count >= 3 else 0, '5+0': size * (self.raid_disk_count - 2) if self.raid_disk_count >= 6 and self.raid_disk_count % 2 == 0 else 0, - }[raid_type] + }[self.raid_type] - def sizeof_disk_xor(self, raid_type): + def sizeof_disk_xor(self): return max(0, self.raid_end - self.raid_start) - def sizeof_disk_parity(self, raid_type): - size = max(0, self.raid_end - self.raid_start) / self.raid_sector_size * 16 + def sizeof_disk_parity(self): + size = max(0, self.raid_end - self.raid_start) / self.d.sector_size * 16 return { '0' : 64, '1' : size if self.raid_disk_count == 2 else 64, '5' : size if self.raid_disk_count >= 3 else 64, '5+0': size if self.raid_disk_count >= 6 and self.raid_disk_count % 2 == 0 else 64, - }[raid_type] + }[self.raid_type] - def read_disk_xor(self,raid_type,offset,size): + def read_disk_xor(self,offset,size): """Returns raw bitwise XOR against a bunch of disks slice""" - return MyRaidMaths.xor_blocks(self.raid_disks,offset,size)[1] + return myraidmaths.MyRaidMaths.xor_blocks(self.raid_disks,offset,size)[1] - def read_disk_parity(self,raid_type,offset,size): + def read_disk_parity(self,offset,size): """Returns textual information about parity status of each sector""" - logging.warn("Enter read_disk_parity(%s,%d,%d)"%(raid_type,offset,size)) + logging.warn("Enter read_disk_parity(%d,%d)"%(offset,size)) msg = { '0' : 'There no notion of parity in RAID 0 mode\n', '1' : None if self.raid_disk_count == 2 else 'Wrong disk count (should be 2)\n', '5' : None if self.raid_disk_count >= 3 else 'Wrong disk count (should be >=3)\n', '5+0': None if self.raid_disk_count >= 6 and self.raid_disk_count % 2 == 0 else 'Wrong disk count (should be >=6 and even)\n', - }[raid_type] + }[self.raid_type] if msg: return msg[offset:offset+size] - start = self.raid_start + offset * self.raid_sector_size / 16 - end = start + size * self.raid_sector_size / 16 + start = self.raid_start + offset * self.d.sector_size / 16 + end = start + size * self.d.sector_size / 16 #TODO : improove for nested levels - if raid_type in ['1','5', '5+0']: + if self.raid_type in ['1','5', '5+0']: result = ''.join( - [ '0x%011x %c\n'%( addr, MyRaidMaths.xor_blocks(self.raid_disks, addr, self.raid_sector_size)[0]) - for addr in xrange(start, end, self.raid_sector_size) + [ '0x%011x %c\n'%( addr, myraidmaths.MyRaidMaths.xor_blocks(self.raid_disks, addr, self.d.sector_size)[0]) + for addr in xrange(start, end, self.d.sector_size) ]) else: result = None - logging.warn("Exit. read_disk_parity(%s,%d,%d)"%(raid_type,offset,size)) + logging.warn("Exit. read_disk_parity(%d,%d)"%(offset,size)) return result - def read_raid_result(self,raid_type,offset,size): + def read_raid_result(self,offset,size): """Returns actual RAID data""" - res = MyRaidMaths.apply_raid_layout(offset, size, raid_type, self.raid_layout, self.raid_chunk_size, self.raid_disk_count, self.raid_start, self.nested_subraid); + res = myraidmaths.MyRaidMaths.apply_raid_layout(offset, size, self.raid_type, self.raid_layout, self.raid_chunk_size, self.raid_disk_count, self.raid_start, self.raid_subraid_count); (segment_no, segment_off, stripe_no, subraid_no, par_disk, data_disk, off_disk, aligned_read_size) = res logging.debug("raid.read_result(%s): offset=%d,segment_no=%d,segment_off=%d,stripe_no=%d,subraid_no=%d,par_disk=%d(disk%02d),data_disk=%d(disk%02d),off_disk=%d,aligned_read_size=%d,segment_off+aligned_read_size=%d" - % (raid_type,offset,segment_no,segment_off,stripe_no,subraid_no,par_disk,self.raid_disk_order[par_disk],data_disk,self.raid_disk_order[data_disk],off_disk,aligned_read_size,segment_off+aligned_read_size) ) + % (self.raid_type,offset,segment_no,segment_off,stripe_no,subraid_no,par_disk,self.raid_disk_order[par_disk],data_disk,self.raid_disk_order[data_disk],off_disk,aligned_read_size,segment_off+aligned_read_size) ) data_fd = self.raid_disks[data_disk] @@ -176,29 +193,29 @@ class MyRaid(): other_fds.remove(data_fd) data_arr = [] - for s in xrange(off_disk, off_disk+aligned_read_size, self.raid_sector_size): - if self.d.is_readable(self.raid_disk_order[data_disk],s,self.raid_sector_size): + for s in xrange(off_disk, off_disk+aligned_read_size, self.d.sector_size): + if self.d.is_readable(self.raid_disk_order[data_disk],s,self.d.sector_size): # Current sector is readable from data disk, read it logging.debug('-> 0x%011x : readable'%s) data_fd.seek(off_disk) - data_arr.append(data_fd.read(self.raid_sector_size)) + data_arr.append(data_fd.read(self.d.sector_size)) else: # Current sector is dead on data disk, recover it if possible recoverable = reduce(lambda a,b: a and b, [ - self.d.is_readable(other_disk,off_disk,self.raid_sector_size) for other_disk in other_disks + self.d.is_readable(other_disk,off_disk,self.d.sector_size) for other_disk in other_disks ]) if recoverable: logging.info('-> 0x%011x : recoverable'%s) - data_arr.append( MyRaidMaths.xor_blocks(other_fds, s,self.raid_sector_size)[1] ) + data_arr.append( myraidmaths.MyRaidMaths.xor_blocks(other_fds, s,self.d.sector_size)[1] ) else: logging.warn('-> 0x%011x : unrecoverable'%s) - data_arr.append( '\0' * self.raid_sector_size) + data_arr.append( '\0' * self.d.sector_size) data = ''.join(data_arr) # Prevent short reads, seems mandatory for losetup'ing raid_result but kills performance #TODO : make it activable per config if aligned_read_size < size: - return ''.join( (data, self.read_raid_result(raid_type,offset+aligned_read_size,size-aligned_read_size) ) ) + return ''.join( (data, self.read_raid_result(offset + aligned_read_size, size - aligned_read_size) ) ) return data diff --git a/raidguessfs.py b/raidguessfs.py index bb26b3f..bd256bf 100755 --- a/raidguessfs.py +++ b/raidguessfs.py @@ -50,7 +50,7 @@ class RaidGuessFS(fuse.Fuse): # Early initialisations (notably modules and the static directory tree part) self.d = mydisks.MyDisks() - self.raid = myraid.MyRaid() + self.raid = myraid.MyRaid(self.d) self.bmp = mybinview.MyBinView() self.st = mystat.MyStat() self.tasks = mytasks.MyTasks(self.d) @@ -63,7 +63,7 @@ class RaidGuessFS(fuse.Fuse): self.settings = [ 'disk_count', 'raid_start', 'raid_end', 'raid_chunk_size', - 'raid_disk_order', 'raid_layout', + 'raid_type', 'raid_disk_order', 'raid_layout', 'raid_subraid_count', 'bmp_height', 'bmp_width', 'bmp_start_offset', 'task_start', 'task_kill', 'task_find_files_pathlist' ] @@ -71,15 +71,15 @@ class RaidGuessFS(fuse.Fuse): self.settings_getters = [ self.d.get_disk_count, self.raid.get_raid_start, self.raid.get_raid_end, self.raid.get_raid_chunk_size, - self.raid.get_raid_disk_order_str, self.raid.get_raid_layout, + self.raid.get_raid_type, self.raid.get_raid_disk_order_str, self.raid.get_raid_layout, self.raid.get_raid_subraid_count, self.bmp.get_bmp_height, self.bmp.get_bmp_width, self.bmp.get_bmp_start_offset, self.get_task_start, self.get_task_kill, self.tasks.get_find_files_pathlist_str, ] self.settings_updaters = [ self.update_disk_count, - self.update_raid_start, self.update_raid_end, self.update_raid_chunk_size, self.update_raid_disk_order, - self.raid.set_raid_layout, + self.update_raid_start, self.update_raid_end, self.update_raid_chunk_size, + self.update_raid_type, self.update_raid_disk_order, self.raid.set_raid_layout, self.update_raid_subraid_count, self.update_bmp_height, self.update_bmp_width, self.update_bmp_start_offset, self.tasks.task_start, self.tasks.task_kill, self.tasks.append_find_files_pathlist ] @@ -88,17 +88,12 @@ class RaidGuessFS(fuse.Fuse): self.dentries = { '/' : [ fuse.Direntry(name) for name in ['config','disk','raid','tasks','visual'] ], '/config': [ fuse.Direntry(name) for name in self.settings ], - '/raid' : [ fuse.Direntry(name) for name in myraid.MyRaid.RAID_TYPES ], + '/raid' : [ fuse.Direntry(name) for name in ['disk_parity','disk_xor','raid_result'] ], '/tasks' : [ fuse.Direntry(name) for name in self.tasks.TASK_NAMES ], '/disk' : [ ], # Filled in _refresh_disk_dentries() '/visual': [ ], # Filled in _refresh_disk_dentries() } - for raid_type in myraid.MyRaid.RAID_TYPES: - self.dentries.update( { - '/raid/%s'%raid_type: [ fuse.Direntry(name) for name in ['disk_parity','disk_xor','raid_result'] ], - } - ) logging.debug("Exit. RaidGuessFS.__init__()") def _refresh_disk_dentries(self): @@ -124,12 +119,9 @@ class RaidGuessFS(fuse.Fuse): def _refresh_raid_fattr(self): """Update the raid computed attributes after a config change""" logging.debug("Enter _refresh_raid_fattr()") - - for raid_type in myraid.MyRaid.RAID_TYPES: - self.fattr['/raid/%s/disk_parity'%raid_type].st_size = self.raid.sizeof_disk_parity(raid_type) - self.fattr['/raid/%s/disk_xor' %raid_type].st_size = self.raid.sizeof_disk_xor (raid_type) - self.fattr['/raid/%s/raid_result'%raid_type].st_size = self.raid.sizeof_raid_result(raid_type) - + self.fattr['/raid/disk_parity'].st_size = self.raid.sizeof_disk_parity() + self.fattr['/raid/disk_xor' ].st_size = self.raid.sizeof_disk_xor() + self.fattr['/raid/raid_result'].st_size = self.raid.sizeof_raid_result() logging.debug("Exit. _refresh_raid_fattr()") def _split_path(self,path): @@ -155,7 +147,6 @@ class RaidGuessFS(fuse.Fuse): self.d.set_disk_count(i) self.d.open_disks() self._refresh_disk_dentries() - self.raid.set_disks(self.d) self.raid.set_raid_end(min(self.d.disks_size)-1) self.update_raid_disk_order(range(i)) @@ -187,10 +178,22 @@ class RaidGuessFS(fuse.Fuse): self.raid.set_raid_end(i) self._refresh_raid_fattr() + def update_raid_subraid_count(self, arg): + i = self._aton(arg) + self.raid.set_subraid_count(i) + self._refresh_raid_fattr() + def update_raid_chunk_size(self, arg): i = self._aton(arg,False) self.raid.set_raid_chunk_size(i) + def update_raid_type(self, arg): + if arg in myraid.MyRaid.RAID_TYPES: + self.raid.set_raid_type(arg) + self._refresh_raid_fattr() + else: + raise ValueError('update_raid_type() : raid type could be in %s'%myraid.MyRaid.RAID_TYPES) + def update_raid_disk_order(self, arg): logging.debug("Enter update_raid_disk_order(%s)"%arg) if type(arg) is str: @@ -233,13 +236,9 @@ class RaidGuessFS(fuse.Fuse): '/tasks/%s'%s: self.st.make_fake_file(4096) for s in self.tasks.TASK_NAMES }) - for raid_type in myraid.MyRaid.RAID_TYPES: - self.fattr.update( { - '/raid/%s/disk_parity'%raid_type: self.st.make_fake_file(0), - '/raid/%s/disk_xor'%raid_type: self.st.make_fake_file(0), - '/raid/%s/raid_result'%raid_type: self.st.make_fake_file(0), - }) - + self.fattr.update( { + '/raid/%s'%s: self.st.make_fake_file(0) for s in ['disk_parity', 'disk_xor', 'raid_result'] + }) self.d.set_disks_path([getattr(self.parser.values,'disk%02d'%d) for d in range(self.d.max_disks)]) self.update_disk_count(len(self.d.disk_paths)) @@ -311,14 +310,12 @@ class RaidGuessFS(fuse.Fuse): return self.bmp.read(self.d.disks[i],offset,size) if path_chuncks[0] == 'raid': - raid_type=path_chuncks[2] - if raid_type in myraid.MyRaid.RAID_TYPES: - if path_chuncks[4] == 'disk_parity': - return self.raid.read_disk_parity(raid_type,offset,size) - if path_chuncks[4] == 'disk_xor': - return self.raid.read_disk_xor(raid_type,offset,size) - if path_chuncks[4] == 'raid_result': - return self.raid.read_raid_result(raid_type,offset,size) + if path_chuncks[1] == 'disk_parity': + return self.raid.read_disk_parity(offset,size) + if path_chuncks[1] == 'disk_xor': + return self.raid.read_disk_xor(offset,size) + if path_chuncks[1] == 'raid_result': + return self.raid.read_raid_result(offset,size) if path_chuncks[0] == 'tasks': if path_chuncks[1] == 'find_bootsect': |