. Handle orphan "unprepped" clusters; . Don't repair the value of cluster shift in ctail item in all circumstances. If cluster shift is wrong, then remove the whole cluster. Signed-off-by: Edward Shishkin --- plugin/object/ccreg40/ccreg40.c | 12 +- plugin/object/ccreg40/ccreg40.h | 9 + plugin/object/ccreg40/ccreg40_repair.c | 196 +++++++++++++++++---------------- 3 files changed, 121 insertions(+), 96 deletions(-) --- reiser4progs-1.0.7.orig/plugin/object/ccreg40/ccreg40.h +++ reiser4progs-1.0.7/plugin/object/ccreg40/ccreg40.h @@ -11,6 +11,12 @@ #include "reiser4/plugin.h" #include "plugin/object/obj40/obj40.h" +#define MIN_VALID_CLUSTER_SHIFT (0xc) +#define MAX_VALID_CLUSTER_SHIFT (0x10) +#define UNPREPPED_CLUSTER_SHIFT (0xff) + +#define ccreg40_cloff(off, size) ((off) & ((size) - 1)) + #define ccreg40_clstart(off, size) ((off) & ~((size) - 1)) #define ccreg40_clnext(off, size) (ccreg40_clstart(off, size) + (size)) @@ -22,7 +28,8 @@ extern errno_t ccreg40_check_struct(reis place_func_t func, void *data, uint8_t mode); -extern uint32_t ccreg40_get_cluster_size(reiser4_place_t *place); +extern errno_t ccreg40_get_cluster_shift(reiser4_place_t *place, + uint8_t *shift); extern errno_t ccreg40_set_cluster_size(reiser4_place_t *place, uint32_t cluster); --- reiser4progs-1.0.7.orig/plugin/object/ccreg40/ccreg40_repair.c +++ reiser4progs-1.0.7/plugin/object/ccreg40/ccreg40_repair.c @@ -25,80 +25,81 @@ typedef struct ccreg40_hint { uint64_t seek; /* expected offset for lookup */ uint64_t found; /* what has been really found */ uint64_t maxreal; /* maximal (key) offset in the found item */ - - /* Bytes all clusters takes on disk. */ - uint32_t bytes; uint64_t sdsize; + /* The following two fields are to delete wrecks of a disk cluster */ + uint64_t cut_from; /* offset to cut from */ + uint32_t cut_size; /* how many bytes to cut */ + uint32_t clsize; + /* Total number of units in a disk cluster */ + uint32_t bytes; uint32_t adler; uint8_t mode; - - /* If a hole is detected. */ + /* Indicates if cluster has a hole in key space */ uint8_t hole; - /* The cluster size & the buffer for the data. */ uint8_t data[64 * 1024]; - uint64_t clstart; - uint32_t clsize; } ccreg40_hint_t; static errno_t ccreg40_check_item(reiser4_object_t *cc, void *data) { ccreg40_hint_t *hint = (ccreg40_hint_t *)data; - uint32_t clsize; - errno_t res = 0; - + uint8_t shift; + errno_t result; + hint->found = objcall(&cc->body.key, get_offset); hint->maxreal = obj40_place_maxreal(&cc->body); aal_assert("vpf-1871", hint->maxreal >= hint->found); aal_assert("vpf-1872", hint->seek <= hint->found); - /* Check the item plugin. */ + /* check item plugin */ if (cc->body.plug != reiser4_psctail(cc)) { - fsck_mess("The file [%s] (%s), node [%llu], item " - "[%u]: item of the illegal plugin (%s) " - "with the key of this object found.%s", - print_inode(obj40_core, &cc->info.object), - reiser4_psobj(cc)->p.label, place_blknr(&cc->body), - cc->body.pos.item, cc->body.plug->p.label, - hint->mode == RM_BUILD ? " Removed." : ""); - - return hint->mode == RM_BUILD ? -ESTRUCT : RE_FATAL; + fsck_mess("Found item of illegal plugin (%s) " + "with the key of this object ", + cc->body.plug->p.label); + goto fatal; } - - /* Check the shift. */ - clsize = ccreg40_get_cluster_size(&cc->body); - - if (hint->clsize != clsize) { - fsck_mess("The file [%s] (%s), node [%llu], item [%u]: item " - "of the wrong cluster size (%d) found, Should be " - "(%d).%s", print_inode(obj40_core, &cc->info.object), - reiser4_psobj(cc)->p.label, place_blknr(&cc->body), - cc->body.pos.item, clsize, hint->clsize, - hint->mode != RM_CHECK ? " Fixed." : ""); - - /* Just fix the shift if wrong. */ - if (hint->mode == RM_CHECK) { - res |= RE_FIXABLE; - } else { - ccreg40_set_cluster_size(&cc->body, hint->clsize); - } + /* check cluster shift. */ + result = ccreg40_get_cluster_shift(&cc->body, &shift); + if (result < 0) + return result; + if (shift == UNPREPPED_CLUSTER_SHIFT) { + fsck_mess("Found unprepped disk cluster "); + goto fatal; + } + if (shift < MIN_VALID_CLUSTER_SHIFT || + shift > MAX_VALID_CLUSTER_SHIFT || + shift != aal_log2(hint->clsize)) { + fsck_mess("Found item with wrong cluster shift %d, " + "should be %d", shift, aal_log2(hint->clsize)); + goto fatal; + } + if (hint->seek && + !ccreg40_clsame(hint->prev_found, hint->found, hint->clsize) && + ccreg40_cloff(hint->found, hint->clsize) != 0){ + fsck_mess("Found item of lenght (%llu) which has wrong " + "offset %llu, should be a multiple of logical " + "cluster size ", + hint->maxreal - hint->found + 1, hint->found); + goto fatal; } - if (!ccreg40_clsame(hint->found, hint->maxreal, hint->clsize)) { - /* The item covers the cluster border. Delete it. */ - fsck_mess("The file [%s] (%s), node [%llu], item [%u]: " - "item of the lenght (%llu) found, it cannot " - "contain data of 2 clusters.%s", - print_inode(obj40_core, &cc->info.object), - reiser4_psobj(cc)->p.label, - place_blknr(&cc->body), cc->body.pos.item, - hint->maxreal - hint->found + 1, - hint->mode == RM_BUILD ? " Removed." : ""); - - return hint->mode == RM_BUILD ? -ESTRUCT : RE_FATAL; + fsck_mess("Found item of length %llu and offset %llu, " + "which contains logical cluster boundary ", + hint->maxreal - hint->found + 1, hint->found); + goto fatal; } - - return res; + return 0; + fatal: + fsck_mess("(file [%s] (%s), node [%llu], item [%u]). %s", + print_inode(obj40_core, &cc->info.object), + reiser4_psobj(cc)->p.label, + place_blknr(&cc->body), + cc->body.pos.item, + hint->mode == RM_BUILD ? " Removed." : ""); + hint->cut_from = hint->found; + hint->cut_size = hint->maxreal - hint->found + 1; + + return hint->mode == RM_BUILD ? -ESTRUCT : RE_FATAL; } static int64_t ccreg40_read_item(reiser4_place_t *place, ccreg40_hint_t *hint) { @@ -133,23 +134,21 @@ static errno_t ccreg40_check_crc(ccreg40 return adler == disk ? 0 : RE_FATAL; } +/* + * Read a found item to the stream. + * Check a checksum, if the previous iteration completed a disk cluster. + */ static errno_t ccreg40_check_cluster(reiser4_object_t *cc, ccreg40_hint_t *hint, uint8_t mode) { - errno_t result; + errno_t result = 0; errno_t res; - int start; - uint32_t lcl_size; - - result = 0; - /* true, if the found item is the - first one in the disk cluster */ - start = (ccreg40_clstart(hint->found, hint->clsize) == hint->found); + uint32_t lcl_bytes; if ((cc->body.plug == NULL) || - (hint->seek && start) || - !ccreg40_clsame(hint->prev_found, hint->found, hint->clsize)) { + (hint->seek != 0 && + !ccreg40_clsame(hint->prev_found, hint->found, hint->clsize))) { /* Cluster is over */ if (hint->prev_found > hint->sdsize) { @@ -158,31 +157,32 @@ static errno_t ccreg40_check_cluster(rei result = RE_FATAL; /* set offset of the cluster to be deleted. */ - hint->clstart = ccreg40_clstart(hint->prev_found, - hint->clsize); + hint->cut_from = ccreg40_clstart(hint->prev_found, + hint->clsize); fsck_mess("The file [%s] (%s): the cluster at [%llu] " "offset %u bytes long is orphan.%s", print_inode(obj40_core, &cc->info.object), - reiser4_psobj(cc)->p.label, hint->clstart, + reiser4_psobj(cc)->p.label, hint->cut_from, hint->clsize, hint->mode != RM_CHECK ? " Removed." : ""); } /** - * If there still is a hole in the logical cluster, - * then check a checksum (no hole means no checksum) + * If there still is a hole in the keyspace, then + * check a checksum (no such hole means that no + * checksum was appended) */ - else if (hint->hole && ccreg40_check_crc(hint)) { + else if (hint->bytes && hint->hole && ccreg40_check_crc(hint)) { /* wrong checksum */ hint->bytes = 0; result = RE_FATAL; /* set offset of the cluster to be deleted. */ - hint->clstart = ccreg40_clstart(hint->prev_found, - hint->clsize); + hint->cut_from = ccreg40_clstart(hint->prev_found, + hint->clsize); fsck_mess("The file [%s] (%s): the cluster at [%llu] " "offset %u bytes long is corrupted.%s", print_inode(obj40_core, &cc->info.object), - reiser4_psobj(cc)->p.label, hint->clstart, + reiser4_psobj(cc)->p.label, hint->cut_from, hint->clsize, hint->mode != RM_CHECK ? " Removed." : ""); } @@ -192,16 +192,13 @@ static errno_t ccreg40_check_cluster(rei hint->adler = 0; if (!cc->body.plug) + /* finish with this object */ return result; /* Update the cluster data. */ aal_memset(hint->data, 0, hint->clsize); } - /* An item found. */ - aal_assert("edward-1", - ccreg40_clstart(hint->found, hint->clsize) == - ccreg40_clstart(hint->maxreal, hint->clsize)); if ((res = ccreg40_read_item(&cc->body, hint))) return res; @@ -209,16 +206,19 @@ static errno_t ccreg40_check_cluster(rei hint->prev_found = hint->found; hint->bytes += objcall(&cc->body, object->bytes); /** - * Calculate a size of logical cluster - * and figure out, if there is a hole - * for the found items in the logical cluster. + * Calculate actual number of file's bytes in the + * logical cluster and figure out, if corresponding + * disk cluster has a hole in key space. + * + * We need this to figure out if disk cluster contains + * appended checksum. */ - lcl_size = 0; + lcl_bytes = 0; if (ccreg40_clsame(hint->found, hint->sdsize - 1, hint->clsize)) - lcl_size = hint->sdsize % hint->clsize; - if (lcl_size == 0) - lcl_size = hint->clsize; - hint->hole = (hint->bytes != lcl_size); + lcl_bytes = hint->sdsize % hint->clsize; + if (lcl_bytes == 0) + lcl_bytes = hint->clsize; + hint->hole = (hint->bytes != lcl_bytes); return result; } @@ -256,8 +256,23 @@ errno_t ccreg40_check_struct(reiser4_obj /* Get next item. */ lookup = obj40_check_item(cc, ccreg40_check_item, NULL, &hint); - if (repair_error_fatal(lookup)) - return lookup; + if (repair_error_fatal(lookup)) { + if ((lookup & RE_FATAL) && mode == RM_BUILD) { + /* + * Delete item found in this iteration + */ + res &= ~RE_FATAL; + res |= obj40_cut(cc, &trans, hint.cut_from, + hint.cut_size, NULL, NULL); + if (res < 0) + return res; + hint.seek = hint.maxreal + 1; + obj40_seek(cc, hint.seek); + continue; + } + else + return lookup; + } else if (lookup == ABSENT) cc->body.plug = NULL; @@ -267,16 +282,17 @@ errno_t ccreg40_check_struct(reiser4_obj "registered yet.", print_key(obj40_core, &info->object)); } - + /* check cluster found in previous iteration */ if ((res |= ccreg40_check_cluster(cc, &hint, mode)) < 0) return res; if (res & RE_FATAL) { - /* Delete the whole cluster. */ - + /* + * Delete cluster found in previous iteration + */ if (mode == RM_BUILD) { res &= ~RE_FATAL; - res |= obj40_cut(cc, &trans, hint.clstart, + res |= obj40_cut(cc, &trans, hint.cut_from, hint.clsize, NULL, NULL); if (res < 0) return res; --- reiser4progs-1.0.7.orig/plugin/object/ccreg40/ccreg40.c +++ reiser4progs-1.0.7/plugin/object/ccreg40/ccreg40.c @@ -8,7 +8,7 @@ #include "ccreg40.h" #include "plugin/object/obj40/obj40_repair.h" -uint32_t ccreg40_get_cluster_size(reiser4_place_t *place) { +errno_t ccreg40_get_cluster_shift(reiser4_place_t *place, uint8_t *shift) { trans_hint_t hint; ctail_hint_t chint; @@ -17,10 +17,12 @@ uint32_t ccreg40_get_cluster_size(reiser hint.specific = &chint; hint.count = 1; - if (objcall(place, object->fetch_units, &hint) != 1) - return MAX_UINT32; - - return 1 << chint.shift; + if (objcall(place, object->fetch_units, &hint) != 1) { + aal_error("Can not extract cluster shift."); + return -EINVAL; + } + *shift = chint.shift; + return 0; } errno_t ccreg40_set_cluster_size(reiser4_place_t *place, uint32_t cluster) {