/** * Shrink logpack header. * * @logh logpack header to shrink. * @invalid_idx new logpack header's n_records must be invalid_idx. * @pbs physical block size [byte]. * @salt checksum salt. */ void shrink_logpack_header( struct walb_logpack_header *logh, unsigned int invalid_idx, unsigned int pbs, u32 salt) { unsigned int i; /* Invalidate records. */ ASSERT(invalid_idx < logh->n_records); for (i = invalid_idx; i < logh->n_records; i++) { log_record_init(&logh->record[i]); } /* Set n_records, n_padding, and total_io_size. */ logh->n_records = invalid_idx; logh->n_padding = 0; logh->total_io_size = 0; for (i = 0; i < invalid_idx; i++) { const struct walb_log_record *rec = &logh->record[i]; if (!test_bit_u32(LOG_RECORD_DISCARD, &rec->flags)) { logh->total_io_size += capacity_pb(pbs, rec->io_size); } if (test_bit_u32(LOG_RECORD_PADDING, &rec->flags)) { logh->n_padding++; } } /* Calculate checksum. */ logh->checksum = 0; logh->checksum = checksum((const u8 *)logh, pbs, salt); ASSERT(is_valid_logpack_header_with_checksum(logh, pbs, salt)); }
/** * Redo logpack. * * @fd file descriptor of data device (opened). * @logpack logpack header to be redo. * @buf logpack data. * (data size: logh->total_io_size * physical_bs) * * RETURN: * true in success, or false. */ bool redo_logpack( int fd, const struct walb_logpack_header* logh, const struct sector_data_array *sect_ary) { int i, n_req; ASSERT(logh); ASSERT_SECTOR_DATA_ARRAY(sect_ary); n_req = logh->n_records; for (i = 0; i < n_req; i++) { unsigned int idx_lb, n_lb; u64 off_lb; const struct walb_log_record *rec = &logh->record[i]; if (test_bit_u32(LOG_RECORD_PADDING, &rec->flags)) { continue; } off_lb = rec->offset; idx_lb = addr_lb(sect_ary->sector_size, rec->lsid_local - 1); n_lb = rec->io_size; if (test_bit_u32(LOG_RECORD_DISCARD, &rec->flags)) { /* If the data device supports discard request, you must issue discard requests. */ /* now editing */ continue; } if (!sector_array_pwrite_lb(fd, off_lb, sect_ary, idx_lb, n_lb)) { LOGe("write sectors failed.\n"); return false; } } return true; }
/** * Read a logpack data from a stream. * * @fd file descriptor (opened, seeked) * @logh corresponding logpack header. * @salt checksum salt. * @sect_ary sector data array to be store data. * * RETURN: * true in success, or false. */ bool read_logpack_data( int fd, const struct walb_logpack_header* logh, u32 salt, struct sector_data_array *sect_ary) { unsigned int pbs; u32 total_pb; int i; int n_req; ASSERT(fd >= 0); ASSERT(logh); n_req = logh->n_records; ASSERT_SECTOR_DATA_ARRAY(sect_ary); pbs = sect_ary->sector_size; ASSERT_PBS(pbs); if (logh->total_io_size > sect_ary->size) { LOGe("sect_ary size is not enough.\n"); return false; } total_pb = 0; for (i = 0; i < n_req; i++) { unsigned int idx_pb, log_lb, log_pb; u32 csum; const struct walb_log_record *rec = &logh->record[i]; if (test_bit_u32(LOG_RECORD_DISCARD, &rec->flags)) { continue; } idx_pb = rec->lsid_local - 1; log_lb = rec->io_size; log_pb = capacity_pb(pbs, log_lb); /* Read data of the log record. */ if (!sector_array_read(fd, sect_ary, idx_pb, log_pb)) { LOGe("read log data failed.\n"); return false; } if (test_bit_u32(LOG_RECORD_PADDING, &rec->flags)) { total_pb += log_pb; continue; } /* Confirm checksum. */ csum = sector_array_checksum( sect_ary, idx_pb * pbs, log_lb * LOGICAL_BLOCK_SIZE, salt); if (csum != rec->checksum) { LOGe("log record[%d] checksum is invalid. %08x %08x\n", i, csum, rec->checksum); return false; } total_pb += log_pb; } ASSERT(total_pb == logh->total_io_size); return true; }
/** * Debug print of logpack header. * */ void walb_logpack_header_print( const char *level, const struct walb_logpack_header *lhead) { int i; printk("%s*****logpack header*****\n" "checksum: %08x\n" "n_records: %u\n" "n_padding: %u\n" "total_io_size: %u\n" "logpack_lsid: %"PRIu64"\n", level, lhead->checksum, lhead->n_records, lhead->n_padding, lhead->total_io_size, lhead->logpack_lsid); for (i = 0; i < lhead->n_records; i++) { printk("%srecord %d\n" " checksum: %08x\n" " lsid: %llu\n" " lsid_local: %u\n" " is_exist: %u\n" " is_padding: %u\n" " is_discard: %u\n" " offset: %"PRIu64"\n" " io_size: %u\n", level, i, lhead->record[i].checksum, lhead->record[i].lsid, lhead->record[i].lsid_local, test_bit_u32(LOG_RECORD_EXIST, &lhead->record[i].flags), test_bit_u32(LOG_RECORD_PADDING, &lhead->record[i].flags), test_bit_u32(LOG_RECORD_DISCARD, &lhead->record[i].flags), lhead->record[i].offset, lhead->record[i].io_size); printk("%slogpack lsid: %llu\n", level, lhead->record[i].lsid - lhead->record[i].lsid_local); } }
/** * Print logpack header. * * @loghk log pack header. */ void print_logpack_header(const struct walb_logpack_header* logh) { ASSERT(logh); int i; printf("*****logpack header*****\n" "checksum: %08x\n" "n_records: %u\n" "n_padding: %u\n" "total_io_size: %u\n" "logpack_lsid: %"PRIu64"\n", logh->checksum, logh->n_records, logh->n_padding, logh->total_io_size, logh->logpack_lsid); for (i = 0; i < logh->n_records; i++) { printf("record %d\n" " checksum: %08x\n" " lsid: %"PRIu64"\n" " lsid_local: %u\n" " is_exist: %u\n" " is_padding: %u\n" " is_discard: %u\n" " offset: %"PRIu64"\n" " io_size: %u\n", i, logh->record[i].checksum, logh->record[i].lsid, logh->record[i].lsid_local, test_bit_u32(LOG_RECORD_EXIST, &logh->record[i].flags), test_bit_u32(LOG_RECORD_PADDING, &logh->record[i].flags), test_bit_u32(LOG_RECORD_DISCARD, &logh->record[i].flags), logh->record[i].offset, logh->record[i].io_size); printf("logpack lsid: %"PRIu64"\n", logh->record[i].lsid - logh->record[i].lsid_local); } }
/** * Get total size of padding data in a logpack header. * * RETURN: * total padding size [physical block]. */ unsigned int get_padding_size_in_logpack_header( const struct walb_logpack_header *logh, unsigned int pbs) { unsigned int total_padding_size = 0; const struct walb_log_record *rec; int i; for_each_logpack_record(i, rec, logh) { if (test_bit_u32(LOG_RECORD_PADDING, &rec->flags)) { total_padding_size += capacity_pb(pbs, rec->io_size); } } return total_padding_size; }
/** * Read logpack data. * Padding area will be also read. * * @fd file descriptor of log device. * @super super sector. * @logh logpack header. * @salt checksum salt. * @sect_ary sector array. * * RETURN: * index of invalid record found at first. * logh->n_records if the whole logpack is valid. */ unsigned int read_logpack_data_from_wldev( int fd, const struct walb_super_sector* super, const struct walb_logpack_header* logh, u32 salt, struct sector_data_array *sect_ary) { const int lbs = super->logical_bs; const int pbs = super->physical_bs; int i; int total_pb; ASSERT(lbs == LOGICAL_BLOCK_SIZE); ASSERT_PBS(pbs); if (logh->total_io_size > sect_ary->size) { LOGe("buffer size is not enough.\n"); return false; } total_pb = 0; for (i = 0; i < logh->n_records; i++) { u64 log_off; u32 log_lb, log_pb; if (test_bit_u32(LOG_RECORD_DISCARD, &logh->record[i].flags)) { continue; } log_lb = logh->record[i].io_size; log_pb = capacity_pb(pbs, log_lb); log_off = get_offset_of_lsid_2 (super, logh->record[i].lsid); LOGd_("lsid: %"PRIu64" log_off: %"PRIu64"\n", logh->record[i].lsid, log_off); /* Read data for the log record. */ if (!sector_array_pread( fd, log_off, sect_ary, total_pb, log_pb)) { LOGe("read sectors failed.\n"); return i; } if (test_bit_u32(LOG_RECORD_PADDING, &logh->record[i].flags)) { total_pb += log_pb; continue; } /* Confirm checksum */ u32 csum = sector_array_checksum( sect_ary, total_pb * pbs, log_lb * lbs, salt); if (csum != logh->record[i].checksum) { LOGe("log header checksum is invalid. %08x %08x\n", csum, logh->record[i].checksum); return i; } total_pb += log_pb; } ASSERT(i == logh->n_records); return logh->n_records; }