On Thu, Jul 26, 2012 at 01:34:06PM +0200, Kevin Wolf wrote: > Am 26.07.2012 09:08, schrieb Stefan Hajnoczi: > > The qed.py utility can inspect and manipulate QED image files. It can > > be used for testing to see the state of image metadata and also to > > inject corruptions into the image file. It also has a scrubbing feature > > to copy just the metadata out of an image file, allowing users to share > > broken image files without revealing data in bug reports. > > > > This has lived in my local repo for a long time but could be useful > > to others. There are two use cases: > > > > 1. qemu-iotests that need to manipulate (e.g. corrupt) QED image files. > > 2. Users that want to inspect or recover their QED image files. > > > > Signed-off-by: Stefan Hajnoczi <stefa...@linux.vnet.ibm.com> > > --- > > Dong Xu Wang <wdon...@linux.vnet.ibm.com> has contributed generic qemu-img > > info > > support for fragmentation statistics and dirty flag status. I have dropped > > fragmentation statistics from qed.py. Setting the dirty flag is still > > supported in qed.py for testing. > > > > tests/qemu-iotests/qed.py | 234 > > +++++++++++++++++++++++++++++++++++++++++++++ > > 1 file changed, 234 insertions(+) > > create mode 100755 tests/qemu-iotests/qed.py > > > +def random_table_item(table): > > + return random.choice([(index, offset) for index, offset in > > enumerate(table) if offset != 0]) > > + > > +def corrupt_table_duplicate(table): > > + '''Corrupt a table by introducing a duplicate offset''' > > + _, dup_victim = random_table_item(table) > > + > > + for i in xrange(len(table)): > > + dup_target = random.randint(0, len(table) - 1) > > + if table[dup_target] != dup_victim: > > + table[dup_target] = dup_victim > > + return > > + raise Exception('no duplication corruption possible in table') > > At least the message isn't quite correct. If you have a table that is > mostly the same (probably unallocated), and has one allocated entry. In > this situation the chances should be relatively high that the random > number never hits the one different entry. > > Not sure how bad this "relatively high" really is, but I could imagine > that we would see an occasional false positive if a test case used this.
The loop is silly, I will replace it with a better solution. > > +def cmd_need_check(qed, *args): > > + '''need-check [on|off] - Test, set, or clear the QED_F_NEED_CHECK > > header bit''' > > + if not args: > > + print bool(qed.header['features'] & QED_F_NEED_CHECK) > > + return > > + > > + if args[0] == 'on': > > + qed.header['features'] |= QED_F_NEED_CHECK > > + elif args[1] == 'off': > > args[0] Good catch > > + qed.header['features'] &= ~QED_F_NEED_CHECK > > + else: > > + err('unrecognized sub-command') > > + qed.store_header() > > + > > +def cmd_zero_cluster(qed, pos, *args): > > + '''zero-cluster <pos> [<n>] - Zero data clusters''' > > + pos, n = int(pos), 1 > > + if args: > > + if len(args) != 1: > > + err('expected one argument') > > + n = int(args[0]) > > + > > + for i in xrange(n): > > + l1_index = pos / qed.header['cluster_size'] / len(qed.l1_table) > > + if qed.l1_table[l1_index] == 0: > > + err('no l2 table allocated') > > + > > + l2_offset = qed.l1_table[l1_index] > > + l2_table = qed.read_table(l2_offset) > > + > > + l2_index = (pos / qed.header['cluster_size']) % len(qed.l1_table) > > + l2_table[l2_index] = 1 # zero the data cluster > > + qed.write_table(l2_offset, l2_table) > > + pos += qed.header['cluster_size'] > > Isn't it quite slow to write the table after each updated cluster? But > okay, probably works good enough for small test cases. Yes, it is slow but I never noticed an issue. I would like to leave this.