/** * 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; }
/** * 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; }
/** * Add a bio to a logpack header. * Almost the same as walb_logpack_header_add_req(). * Do not validate checksum. * * REQ_DISCARD is supported. * * @lhead log pack header. * lhead->logpack_lsid must be set correctly. * lhead->sector_type must be set correctly. * @logpack_lsid lsid of the log pack. * @bio bio to add. must be write and its size >= 0. * size == 0 is permitted with flush requests only. * @pbs physical block size. * @ring_buffer_size ring buffer size [physical block] * * RETURN: * true in success, or false (you must create new logpack for the bio). */ bool walb_logpack_header_add_bio( struct walb_logpack_header *lhead, const struct bio *bio, unsigned int pbs, u64 ring_buffer_size) { u64 logpack_lsid; u64 bio_lsid; unsigned int bio_lb, bio_pb; u64 padding_pb; unsigned int max_n_rec; int idx; bool is_discard; UNUSED const char no_more_bio_msg[] = "no more bio can not be added.\n"; ASSERT(lhead); ASSERT(lhead->sector_type == SECTOR_TYPE_LOGPACK); ASSERT(bio); ASSERT_PBS(pbs); ASSERT(bio->bi_rw & REQ_WRITE); ASSERT(ring_buffer_size > 0); logpack_lsid = lhead->logpack_lsid; max_n_rec = max_n_log_record_in_sector(pbs); idx = lhead->n_records; ASSERT(lhead->n_records <= max_n_rec); if (lhead->n_records == max_n_rec) { LOG_(no_more_bio_msg); return false; } bio_lsid = logpack_lsid + 1 + lhead->total_io_size; bio_lb = bio_sectors(bio); if (bio_lb == 0) { /* Only flush requests can have zero-size. */ ASSERT(bio->bi_rw & REQ_FLUSH); /* Currently a zero-flush must be alone. */ ASSERT(idx == 0); return true; } ASSERT(0 < bio_lb); bio_pb = capacity_pb(pbs, bio_lb); is_discard = ((bio->bi_rw & REQ_DISCARD) != 0); if (!is_discard) ASSERT(bio_lb <= WALB_MAX_NORMAL_IO_SECTORS); /* Padding check. */ { u64 rem; div64_u64_rem(bio_lsid, ring_buffer_size, &rem); padding_pb = ring_buffer_size - rem; } if (!is_discard && padding_pb < bio_pb) { /* Log of this request will cross the end of ring buffer. So padding is required. */ u64 cap_lb; if (lhead->total_io_size + padding_pb > MAX_TOTAL_IO_SIZE_IN_LOGPACK_HEADER) { LOG_(no_more_bio_msg); return false; } /* Fill the padding record contents. */ set_bit_u32(LOG_RECORD_PADDING, &lhead->record[idx].flags); set_bit_u32(LOG_RECORD_EXIST, &lhead->record[idx].flags); lhead->record[idx].lsid = bio_lsid; ASSERT(bio_lsid - logpack_lsid <= UINT16_MAX); lhead->record[idx].lsid_local = (u16)(bio_lsid - logpack_lsid); lhead->record[idx].offset = 0; cap_lb = capacity_lb(pbs, padding_pb); ASSERT(cap_lb <= UINT16_MAX); lhead->record[idx].io_size = (u16)cap_lb; lhead->n_padding++; lhead->n_records++; lhead->total_io_size += padding_pb; bio_lsid += padding_pb; idx++; ASSERT(bio_lsid == logpack_lsid + 1 + lhead->total_io_size); if (lhead->n_records == max_n_rec) { /* The last record is padding. */ LOG_(no_more_bio_msg); return false; } } if (!is_discard && lhead->total_io_size + bio_pb > MAX_TOTAL_IO_SIZE_IN_LOGPACK_HEADER) { LOG_(no_more_bio_msg); return false; } /* Fill the log record contents. */ set_bit_u32(LOG_RECORD_EXIST, &lhead->record[idx].flags); clear_bit_u32(LOG_RECORD_PADDING, &lhead->record[idx].flags); lhead->record[idx].lsid = bio_lsid; lhead->record[idx].lsid_local = (u16)(bio_lsid - logpack_lsid); lhead->record[idx].offset = (u64)bio->bi_iter.bi_sector; lhead->record[idx].io_size = (u32)bio_lb; lhead->n_records++; if (is_discard) { set_bit_u32(LOG_RECORD_DISCARD, &lhead->record[idx].flags); /* lhead->total_io_size will not be added. */ } else { clear_bit_u32(LOG_RECORD_DISCARD, &lhead->record[idx].flags); lhead->total_io_size += bio_pb; } return true; }