📄 zftape-compress.c
字号:
} TRACE_EXIT (unsigned int)max_out_sz;}/* print some statistics about the efficiency of the compression to * the kernel log */static void zftc_stats(void){ TRACE_FUN(ft_t_flow); if (TRACE_LEVEL < ft_t_info) { TRACE_EXIT; } if (zftc_wr_uncompressed != 0) { if (zftc_wr_compressed > (1<<14)) { TRACE(ft_t_info, "compression statistics (writing):\n" KERN_INFO " compr./uncmpr. : %3d %%", (((zftc_wr_compressed>>10) * 100) / (zftc_wr_uncompressed>>10))); } else { TRACE(ft_t_info, "compression statistics (writing):\n" KERN_INFO " compr./uncmpr. : %3d %%", ((zftc_wr_compressed * 100) / zftc_wr_uncompressed)); } } if (zftc_rd_uncompressed != 0) { if (zftc_rd_compressed > (1<<14)) { TRACE(ft_t_info, "compression statistics (reading):\n" KERN_INFO " compr./uncmpr. : %3d %%", (((zftc_rd_compressed>>10) * 100) / (zftc_rd_uncompressed>>10))); } else { TRACE(ft_t_info, "compression statistics (reading):\n" KERN_INFO " compr./uncmpr. : %3d %%", ((zftc_rd_compressed * 100) / zftc_rd_uncompressed)); } } /* only print it once: */ zftc_wr_uncompressed = zftc_wr_compressed = zftc_rd_uncompressed = zftc_rd_compressed = 0; TRACE_EXIT;}/* start new compressed block */static int start_new_cseg(cmpr_info *cluster, char *dst_buf, const zft_position *pos, const unsigned int blk_sz, const char *src_buf, const int this_segs_sz, const int qic113){ int size_left; int cp_cnt; int buf_pos; TRACE_FUN(ft_t_flow); size_left = this_segs_sz - sizeof(__u16) - cluster->cmpr_sz; TRACE(ft_t_data_flow,"\n" KERN_INFO "segment size : %d\n" KERN_INFO "compressed_sz: %d\n" KERN_INFO "size_left : %d", this_segs_sz, cluster->cmpr_sz, size_left); if (size_left > 18) { /* start a new cluseter */ cp_cnt = cluster->cmpr_sz; cluster->cmpr_sz = 0; buf_pos = cp_cnt + sizeof(__u16); PUT2(dst_buf, 0, buf_pos); if (qic113) { __s64 foffs = pos->volume_pos; if (cp_cnt) foffs += (__s64)blk_sz; TRACE(ft_t_data_flow, "new style QIC-113 header"); PUT8(dst_buf, buf_pos, foffs); buf_pos += sizeof(__s64); } else { __u32 foffs = (__u32)pos->volume_pos; if (cp_cnt) foffs += (__u32)blk_sz; TRACE(ft_t_data_flow, "old style QIC-80MC header"); PUT4(dst_buf, buf_pos, foffs); buf_pos += sizeof(__u32); } } else if (size_left >= 0) { cp_cnt = cluster->cmpr_sz; cluster->cmpr_sz = 0; buf_pos = cp_cnt + sizeof(__u16); PUT2(dst_buf, 0, buf_pos); /* zero unused part of segment. */ memset(dst_buf + buf_pos, '\0', size_left); buf_pos = this_segs_sz; } else { /* need entire segment and more space */ PUT2(dst_buf, 0, 0); cp_cnt = this_segs_sz - sizeof(__u16); cluster->cmpr_sz -= cp_cnt; buf_pos = this_segs_sz; } memcpy(dst_buf + sizeof(__u16), src_buf + cluster->cmpr_pos, cp_cnt); cluster->cmpr_pos += cp_cnt; TRACE_EXIT buf_pos;}/* return-value: the number of bytes removed from the user-buffer * `src_buf' or error code * * int *write_cnt : how much actually has been moved to the * dst_buf. Need not be initialized when * function returns with an error code * (negativ return value) * __u8 *dst_buf : kernel space buffer where the has to be * copied to. The contents of this buffers * goes to a specific segment. * const int seg_sz : the size of the segment dst_buf will be * copied to. * const zft_position *pos : struct containing the coordinates in * the current volume (byte position, * segment id of current segment etc) * const zft_volinfo *volume: information about the current volume, * size etc. * const __u8 *src_buf : user space buffer that contains the * data the user wants to be written to * tape. * const int req_len : the amount of data the user wants to be * written to tape. */static int zftc_write(int *write_cnt, __u8 *dst_buf, const int seg_sz, const __u8 __user *src_buf, const int req_len, const zft_position *pos, const zft_volinfo *volume){ int req_len_left = req_len; int result; int len_left; int buf_pos_write = pos->seg_byte_pos; TRACE_FUN(ft_t_flow); /* Note: we do not unlock the module because * there are some values cached in that `cseg' variable. We * don't don't want to use this information when being * unloaded by kerneld even when the tape is full or when we * cannot allocate enough memory. */ if (pos->tape_pos > (volume->size-volume->blk_sz-ZFT_CMPR_OVERHEAD)) { TRACE_EXIT -ENOSPC; } if (zft_allocate_cmpr_mem(volume->blk_sz) < 0) { /* should we unlock the module? But it shouldn't * be locked anyway ... */ TRACE_EXIT -ENOMEM; } if (buf_pos_write == 0) { /* fill a new segment */ *write_cnt = buf_pos_write = start_new_cseg(&cseg, dst_buf, pos, volume->blk_sz, zftc_buf, seg_sz, volume->qic113); if (cseg.cmpr_sz == 0 && cseg.cmpr_pos != 0) { req_len_left -= result = volume->blk_sz; cseg.cmpr_pos = 0; } else { result = 0; } } else { *write_cnt = result = 0; } len_left = seg_sz - buf_pos_write; while ((req_len_left > 0) && (len_left > 18)) { /* now we have some size left for a new compressed * block. We know, that the compression buffer is * empty (else there wouldn't be any space left). */ if (copy_from_user(zftc_scratch_buf, src_buf + result, volume->blk_sz) != 0) { TRACE_EXIT -EFAULT; } req_len_left -= volume->blk_sz; cseg.cmpr_sz = zft_compress(zftc_scratch_buf, volume->blk_sz, zftc_buf); if (cseg.cmpr_sz < 0) { cseg.uncmpr = 0x8000; cseg.cmpr_sz = -cseg.cmpr_sz; } else { cseg.uncmpr = 0; } /* increment "result" iff we copied the entire * compressed block to the zft_deblock_buf */ len_left -= sizeof(__u16); if (len_left >= cseg.cmpr_sz) { len_left -= cseg.count = cseg.cmpr_sz; cseg.cmpr_pos = cseg.cmpr_sz = 0; result += volume->blk_sz; } else { cseg.cmpr_sz -= cseg.cmpr_pos = cseg.count = len_left; len_left = 0; } PUT2(dst_buf, buf_pos_write, cseg.uncmpr | cseg.count); buf_pos_write += sizeof(__u16); memcpy(dst_buf + buf_pos_write, zftc_buf, cseg.count); buf_pos_write += cseg.count; *write_cnt += cseg.count + sizeof(__u16); FT_SIGNAL_EXIT(_DONT_BLOCK); } /* erase the remainder of the segment if less than 18 bytes * left (18 bytes is due to the QIC-80 standard) */ if (len_left <= 18) { memset(dst_buf + buf_pos_write, '\0', len_left); (*write_cnt) += len_left; } TRACE(ft_t_data_flow, "returning %d", result); TRACE_EXIT result;} /* out: * * int *read_cnt: the number of bytes we removed from the zft_deblock_buf * (result) * int *to_do : the remaining size of the read-request. * * in: * * char *buff : buff is the address of the upper part of the user * buffer, that hasn't been filled with data yet. * int buf_pos_read : copy of from _ftape_read() * int buf_len_read : copy of buf_len_rd from _ftape_read() * char *zft_deblock_buf: zft_deblock_buf * unsigned short blk_sz: the block size valid for this volume, may differ * from zft_blk_sz. * int finish: if != 0 means that this is the last segment belonging * to this volume * returns the amount of data actually copied to the user-buffer * * to_do MUST NOT SHRINK except to indicate an EOF. In this case *to_do has to * be set to 0 */static int zftc_read (int *read_cnt, __u8 __user *dst_buf, const int to_do, const __u8 *src_buf, const int seg_sz, const zft_position *pos, const zft_volinfo *volume){ int uncompressed_sz; int result = 0; int remaining = to_do; TRACE_FUN(ft_t_flow); TRACE_CATCH(zft_allocate_cmpr_mem(volume->blk_sz),); if (pos->seg_byte_pos == 0) { /* new segment just read */ TRACE_CATCH(get_cseg(&cseg, src_buf, seg_sz, volume), *read_cnt = 0); memcpy(zftc_buf + cseg.cmpr_pos, src_buf + sizeof(__u16), cseg.count); cseg.cmpr_pos += cseg.count; *read_cnt = cseg.offset; DUMP_CMPR_INFO(ft_t_noise /* ft_t_any */, "", &cseg); } else { *read_cnt = 0; } /* loop and uncompress until user buffer full or * deblock-buffer empty */ TRACE(ft_t_data_flow, "compressed_sz: %d, compos : %d, *read_cnt: %d", cseg.cmpr_sz, cseg.cmpr_pos, *read_cnt); while ((cseg.spans == 0) && (remaining > 0)) { if (cseg.cmpr_pos != 0) { /* cmpr buf is not empty */ uncompressed_sz = zft_uncompress(zftc_buf, cseg.uncmpr == 0x8000 ? -cseg.cmpr_pos : cseg.cmpr_pos, zftc_scratch_buf, volume->blk_sz); if (uncompressed_sz != volume->blk_sz) { *read_cnt = 0; TRACE_ABORT(-EIO, ft_t_warn, "Uncompressed blk (%d) != blk size (%d)", uncompressed_sz, volume->blk_sz); } if (copy_to_user(dst_buf + result, zftc_scratch_buf, uncompressed_sz) != 0 ) { TRACE_EXIT -EFAULT; } remaining -= uncompressed_sz; result += uncompressed_sz; cseg.cmpr_pos = 0; } if (remaining > 0) { get_next_cluster(&cseg, src_buf, seg_sz, volume->end_seg == pos->seg_pos); if (cseg.count != 0) { memcpy(zftc_buf, src_buf + cseg.offset, cseg.count); cseg.cmpr_pos = cseg.count; cseg.offset += cseg.count; *read_cnt += cseg.count + sizeof(__u16); } else { remaining = 0; } } TRACE(ft_t_data_flow, "\n" KERN_INFO "compressed_sz: %d\n" KERN_INFO "compos : %d\n" KERN_INFO "*read_cnt : %d", cseg.cmpr_sz, cseg.cmpr_pos, *read_cnt); } if (seg_sz - cseg.offset <= 18) { *read_cnt += seg_sz - cseg.offset; TRACE(ft_t_data_flow, "expanding read cnt to: %d", *read_cnt); } TRACE(ft_t_data_flow, "\n" KERN_INFO "segment size : %d\n" KERN_INFO "read count : %d\n" KERN_INFO "buf_pos_read : %d\n" KERN_INFO "remaining : %d", seg_sz, *read_cnt, pos->seg_byte_pos, seg_sz - *read_cnt - pos->seg_byte_pos); TRACE(ft_t_data_flow, "returning: %d", result); TRACE_EXIT result;} /* seeks to the new data-position. Reads sometimes a segment. * * start_seg and end_seg give the boundaries of the current volume * blk_sz is the blk_sz of the current volume as stored in the * volume label * * We don't allow blocksizes less than 1024 bytes, therefore we don't need * a 64 bit argument for new_block_pos. */static int seek_in_segment(const unsigned int to_do, cmpr_info *c_info, const char *src_buf, const int seg_sz, const int seg_pos, const zft_volinfo *volume);static int slow_seek_forward_until_error(const unsigned int distance, cmpr_info *c_info, zft_position *pos, const zft_volinfo *volume, __u8 *buf);static int search_valid_segment(unsigned int segment, const unsigned int end_seg, const unsigned int max_foffs, zft_position *pos, cmpr_info *c_info, const zft_volinfo *volume, __u8 *buf);static int slow_seek_forward(unsigned int dest, cmpr_info *c_info, zft_position *pos, const zft_volinfo *volume, __u8 *buf);static int compute_seg_pos(unsigned int dest, zft_position *pos, const zft_volinfo *volume);#define ZFT_SLOW_SEEK_THRESHOLD 10 /* segments */#define ZFT_FAST_SEEK_MAX_TRIALS 10 /* times */#define ZFT_FAST_SEEK_BACKUP 10 /* segments */static int zftc_seek(unsigned int new_block_pos, zft_position *pos, const zft_volinfo *volume, __u8 *buf){ unsigned int dest; int limit; int distance; int result = 0; int seg_dist; int new_seg; int old_seg = 0; int fast_seek_trials = 0; TRACE_FUN(ft_t_flow); if (new_block_pos == 0) { pos->seg_pos = volume->start_seg; pos->seg_byte_pos = 0; pos->volume_pos = 0; zftc_reset(); TRACE_EXIT 0; } dest = new_block_pos * (volume->blk_sz >> 10); distance = dest - (pos->volume_pos >> 10); while (distance != 0) { seg_dist = compute_seg_pos(dest, pos, volume); TRACE(ft_t_noise, "\n" KERN_INFO "seg_dist: %d\n" KERN_INFO "distance: %d\n" KERN_INFO "dest : %d\n" KERN_INFO "vpos : %d\n" KERN_INFO "seg_pos : %d\n" KERN_INFO "trials : %d", seg_dist, distance, dest, (unsigned int)(pos->volume_pos>>10), pos->seg_pos, fast_seek_trials); if (distance > 0) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -