File: /usr/src/linux/drivers/char/ftape/compressor/zftape-compress.c
1 /*
2 * Copyright (C) 1994-1997 Claus-Justus Heine
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License as
6 published by the Free Software Foundation; either version 2, or (at
7 your option) any later version.
8
9 This program is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; see the file COPYING. If not, write to
16 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139,
17 USA.
18
19 *
20 * This file implements a "generic" interface between the *
21 * zftape-driver and a compression-algorithm. The *
22 * compression-algorithm currently used is a LZ77. I use the *
23 * implementation lzrw3 by Ross N. Williams (Renaissance *
24 * Software). The compression program itself is in the file
25 * lzrw3.c * and lzrw3.h. To adopt another compression algorithm
26 * the functions * zft_compress() and zft_uncompress() must be
27 * changed * appropriately. See below.
28 */
29
30 char zftc_src[] ="$Source: /homes/cvs/ftape-stacked/ftape/compressor/zftape-compress.c,v $";
31 char zftc_rev[] = "$Revision: 1.1.6.1 $";
32 char zftc_dat[] = "$Date: 1997/11/16 15:15:56 $";
33
34 #include <linux/errno.h>
35 #include <linux/mm.h>
36 #include <linux/module.h>
37
38 #include <linux/zftape.h>
39
40 #if LINUX_VERSION_CODE >= KERNEL_VER(2,1,6)
41 #include <asm/uaccess.h>
42 #else
43 #include <asm/segment.h>
44 #endif
45
46 #include "../zftape/zftape-init.h"
47 #include "../zftape/zftape-eof.h"
48 #include "../zftape/zftape-ctl.h"
49 #include "../zftape/zftape-write.h"
50 #include "../zftape/zftape-read.h"
51 #include "../zftape/zftape-rw.h"
52 #include "../compressor/zftape-compress.h"
53 #include "../zftape/zftape-vtbl.h"
54 #include "../compressor/lzrw3.h"
55
56 /*
57 * global variables
58 */
59
60 /* I handle the allocation of this buffer as a special case, because
61 * it's size varies depending on the tape length inserted.
62 */
63
64 /* local variables
65 */
66 static int keep_module_locked = 1;
67
68 static void *zftc_wrk_mem = NULL;
69 static __u8 *zftc_buf = NULL;
70 static void *zftc_scratch_buf = NULL;
71
72 /* compression statistics
73 */
74 static unsigned int zftc_wr_uncompressed = 0;
75 static unsigned int zftc_wr_compressed = 0;
76 static unsigned int zftc_rd_uncompressed = 0;
77 static unsigned int zftc_rd_compressed = 0;
78
79 /* forward */
80 static int zftc_write(int *write_cnt,
81 __u8 *dst_buf, const int seg_sz,
82 const __u8 *src_buf, const int req_len,
83 const zft_position *pos, const zft_volinfo *volume);
84 static int zftc_read(int *read_cnt,
85 __u8 *dst_buf, const int to_do,
86 const __u8 *src_buf, const int seg_sz,
87 const zft_position *pos, const zft_volinfo *volume);
88 static int zftc_seek(unsigned int new_block_pos,
89 zft_position *pos, const zft_volinfo *volume,
90 __u8 *buffer);
91 static void zftc_lock (void);
92 static void zftc_reset (void);
93 static void zftc_cleanup(void);
94 static void zftc_stats (void);
95
96 /* compressed segment. This conforms to QIC-80-MC, Revision K.
97 *
98 * Rev. K applies to tapes with `fixed length format' which is
99 * indicated by format code 2,3 and 5. See below for format code 4 and 6
100 *
101 * 2 bytes: offset of compression segment structure
102 * 29k > offset >= 29k-18: data from previous segment ens in this
103 * segment and no compressed block starts
104 * in this segment
105 * offset == 0: data from previous segment occupies entire
106 * segment and continues in next segment
107 * n bytes: remainder from previous segment
108 *
109 * Rev. K:
110 * 4 bytes: 4 bytes: files set byte offset
111 * Post Rev. K and QIC-3020/3020:
112 * 8 bytes: 8 bytes: files set byte offset
113 * 2 bytes: byte count N (amount of data following)
114 * bit 15 is set if data is compressed, bit 15 is not
115 * set if data is uncompressed
116 * N bytes: data (as much as specified in the byte count)
117 * 2 bytes: byte count N_1 of next cluster
118 * N_1 bytes: data of next cluset
119 * 2 bytes: byte count N_2 of next cluster
120 * N_2 bytes: ...
121 *
122 * Note that the `N' byte count accounts only for the bytes that in the
123 * current segment if the cluster spans to the next segment.
124 */
125
126 typedef struct
127 {
128 int cmpr_pos; /* actual position in compression buffer */
129 int cmpr_sz; /* what is left in the compression buffer
130 * when copying the compressed data to the
131 * deblock buffer
132 */
133 unsigned int first_block; /* location of header information in
134 * this segment
135 */
136 unsigned int count; /* amount of data of current block
137 * contained in current segment
138 */
139 unsigned int offset; /* offset in current segment */
140 unsigned int spans:1; /* might continue in next segment */
141 unsigned int uncmpr; /* 0x8000 if this block contains
142 * uncompressed data
143 */
144 __s64 foffs; /* file set byte offset, same as in
145 * compression map segment
146 */
147 } cmpr_info;
148
149 static cmpr_info cseg; /* static data. Must be kept uptodate and shared by
150 * read, write and seek functions
151 */
152
153 #define DUMP_CMPR_INFO(level, msg, info) \
154 TRACE(level, msg "\n" \
155 KERN_INFO "cmpr_pos : %d\n" \
156 KERN_INFO "cmpr_sz : %d\n" \
157 KERN_INFO "first_block: %d\n" \
158 KERN_INFO "count : %d\n" \
159 KERN_INFO "offset : %d\n" \
160 KERN_INFO "spans : %d\n" \
161 KERN_INFO "uncmpr : 0x%04x\n" \
162 KERN_INFO "foffs : " LL_X, \
163 (info)->cmpr_pos, (info)->cmpr_sz, (info)->first_block, \
164 (info)->count, (info)->offset, (info)->spans == 1, \
165 (info)->uncmpr, LL((info)->foffs))
166
167 /* dispatch compression segment info, return error code
168 *
169 * afterwards, cseg->offset points to start of data of the NEXT
170 * compressed block, and cseg->count contains the amount of data
171 * left in the actual compressed block. cseg->spans is set to 1 if
172 * the block is continued in the following segment. Otherwise it is
173 * set to 0.
174 */
175 static int get_cseg (cmpr_info *cinfo, const __u8 *buff,
176 const unsigned int seg_sz,
177 const zft_volinfo *volume)
178 {
179 TRACE_FUN(ft_t_flow);
180
181 cinfo->first_block = GET2(buff, 0);
182 if (cinfo->first_block == 0) { /* data spans to next segment */
183 cinfo->count = seg_sz - sizeof(__u16);
184 cinfo->offset = seg_sz;
185 cinfo->spans = 1;
186 } else { /* cluster definetely ends in this segment */
187 if (cinfo->first_block > seg_sz) {
188 /* data corrupted */
189 TRACE_ABORT(-EIO, ft_t_err, "corrupted data:\n"
190 KERN_INFO "segment size: %d\n"
191 KERN_INFO "first block : %d",
192 seg_sz, cinfo->first_block);
193 }
194 cinfo->count = cinfo->first_block - sizeof(__u16);
195 cinfo->offset = cinfo->first_block;
196 cinfo->spans = 0;
197 }
198 /* now get the offset the first block should have in the
199 * uncompressed data stream.
200 *
201 * For this magic `18' refer to CRF-3 standard or QIC-80MC,
202 * Rev. K.
203 */
204 if ((seg_sz - cinfo->offset) > 18) {
205 if (volume->qic113) { /* > revision K */
206 TRACE(ft_t_data_flow, "New QIC-113 compliance");
207 cinfo->foffs = GET8(buff, cinfo->offset);
208 cinfo->offset += sizeof(__s64);
209 } else {
210 TRACE(/* ft_t_data_flow */ ft_t_noise, "pre QIC-113 version");
211 cinfo->foffs = (__s64)GET4(buff, cinfo->offset);
212 cinfo->offset += sizeof(__u32);
213 }
214 }
215 if (cinfo->foffs > volume->size) {
216 TRACE_ABORT(-EIO, ft_t_err, "Inconsistency:\n"
217 KERN_INFO "offset in current volume: %d\n"
218 KERN_INFO "size of current volume : %d",
219 (int)(cinfo->foffs>>10), (int)(volume->size>>10));
220 }
221 if (cinfo->cmpr_pos + cinfo->count > volume->blk_sz) {
222 TRACE_ABORT(-EIO, ft_t_err, "Inconsistency:\n"
223 KERN_INFO "block size : %d\n"
224 KERN_INFO "data record: %d",
225 volume->blk_sz, cinfo->cmpr_pos + cinfo->count);
226 }
227 DUMP_CMPR_INFO(ft_t_noise /* ft_t_any */, "", cinfo);
228 TRACE_EXIT 0;
229 }
230
231 /* This one is called, when a new cluster starts in same segment.
232 *
233 * Note: if this is the first cluster in the current segment, we must
234 * not check whether there are more than 18 bytes available because
235 * this have already been done in get_cseg() and there may be less
236 * than 18 bytes available due to header information.
237 *
238 */
239 static void get_next_cluster(cmpr_info *cluster, const __u8 *buff,
240 const int seg_sz, const int finish)
241 {
242 TRACE_FUN(ft_t_flow);
243
244 if (seg_sz - cluster->offset > 18 || cluster->foffs != 0) {
245 cluster->count = GET2(buff, cluster->offset);
246 cluster->uncmpr = cluster->count & 0x8000;
247 cluster->count -= cluster->uncmpr;
248 cluster->offset += sizeof(__u16);
249 cluster->foffs = 0;
250 if ((cluster->offset + cluster->count) < seg_sz) {
251 cluster->spans = 0;
252 } else if (cluster->offset + cluster->count == seg_sz) {
253 cluster->spans = !finish;
254 } else {
255 /* either an error or a volume written by an
256 * old version. If this is a data error, then we'll
257 * catch it later.
258 */
259 TRACE(ft_t_data_flow, "Either error or old volume");
260 cluster->spans = 1;
261 cluster->count = seg_sz - cluster->offset;
262 }
263 } else {
264 cluster->count = 0;
265 cluster->spans = 0;
266 cluster->foffs = 0;
267 }
268 DUMP_CMPR_INFO(ft_t_noise /* ft_t_any */ , "", cluster);
269 TRACE_EXIT;
270 }
271
272 static void zftc_lock(void)
273 {
274 #if LINUX_VERSION_CODE < KERNEL_VER(2,1,18)
275 if (!MOD_IN_USE) {
276 MOD_INC_USE_COUNT;
277 }
278 #else
279 MOD_INC_USE_COUNT; /* sets MOD_VISITED and MOD_USED_ONCE,
280 * locking is done with can_unload()
281 */
282 #endif
283 keep_module_locked = 1;
284 }
285
286 /* this function is needed for zftape_reset_position in zftape-io.c
287 */
288 static void zftc_reset(void)
289 {
290 TRACE_FUN(ft_t_flow);
291
292 memset((void *)&cseg, '\0', sizeof(cseg));
293 zftc_stats();
294 #if LINUX_VERSION_CODE < KERNEL_VER(2,1,18)
295 if (MOD_IN_USE) {
296 MOD_DEC_USE_COUNT;
297 }
298 #endif
299 keep_module_locked = 0;
300 TRACE_EXIT;
301 }
302
303 static int cmpr_mem_initialized = 0;
304 static unsigned int alloc_blksz = 0;
305
306 static int zft_allocate_cmpr_mem(unsigned int blksz)
307 {
308 TRACE_FUN(ft_t_flow);
309
310 if (cmpr_mem_initialized && blksz == alloc_blksz) {
311 TRACE_EXIT 0;
312 }
313 TRACE_CATCH(zft_vmalloc_once(&zftc_wrk_mem, CMPR_WRK_MEM_SIZE),
314 zftc_cleanup());
315 TRACE_CATCH(zft_vmalloc_always(&zftc_buf, blksz + CMPR_OVERRUN),
316 zftc_cleanup());
317 alloc_blksz = blksz;
318 TRACE_CATCH(zft_vmalloc_always(&zftc_scratch_buf, blksz+CMPR_OVERRUN),
319 zftc_cleanup());
320 cmpr_mem_initialized = 1;
321 TRACE_EXIT 0;
322 }
323
324 static void zftc_cleanup(void)
325 {
326 TRACE_FUN(ft_t_flow);
327
328 zft_vfree(&zftc_wrk_mem, CMPR_WRK_MEM_SIZE);
329 zft_vfree(&zftc_buf, alloc_blksz + CMPR_OVERRUN);
330 zft_vfree(&zftc_scratch_buf, alloc_blksz + CMPR_OVERRUN);
331 cmpr_mem_initialized = alloc_blksz = 0;
332 TRACE_EXIT;
333 }
334
335 /*****************************************************************************
336 * *
337 * The following two functions "ftape_compress()" and *
338 * "ftape_uncompress()" are the interface to the actual compression *
339 * algorithm (i.e. they are calling the "compress()" function from *
340 * the lzrw3 package for now). These routines could quite easily be *
341 * changed to adopt another compression algorithm instead of lzrw3, *
342 * which currently is used. *
343 * *
344 *****************************************************************************/
345
346 /* called by zft_compress_write() to perform the compression. Must
347 * return the size of the compressed data.
348 *
349 * NOTE: The size of the compressed data should not exceed the size of
350 * the uncompressed data. Most compression algorithms have means
351 * to store data unchanged if the "compressed" data amount would
352 * exceed the original one. Mostly this is done by storing some
353 * flag-bytes in front of the compressed data to indicate if it
354 * is compressed or not. Thus the worst compression result
355 * length is the original length plus those flag-bytes.
356 *
357 * We don't want that, as the QIC-80 standard provides a means
358 * of marking uncompressed blocks by simply setting bit 15 of
359 * the compressed block's length. Thus a compessed block can
360 * have at most a length of 2^15-1 bytes. The QIC-80 standard
361 * restricts the block-length even further, allowing only 29k -
362 * 6 bytes.
363 *
364 * Currently, the maximum blocksize used by zftape is 28k.
365 *
366 * In short: don't exceed the length of the input-package, set
367 * bit 15 of the compressed size to 1 if you have copied data
368 * instead of compressing it.
369 */
370 static int zft_compress(__u8 *in_buffer, unsigned int in_sz, __u8 *out_buffer)
371 {
372 __s32 compressed_sz;
373 TRACE_FUN(ft_t_flow);
374
375
376 lzrw3_compress(COMPRESS_ACTION_COMPRESS, zftc_wrk_mem,
377 in_buffer, in_sz, out_buffer, &compressed_sz);
378 if (TRACE_LEVEL >= ft_t_info) {
379 /* the compiler will optimize this away when
380 * compiled with NO_TRACE_AT_ALL option
381 */
382 TRACE(ft_t_data_flow, "\n"
383 KERN_INFO "before compression: %d bytes\n"
384 KERN_INFO "after compresison : %d bytes",
385 in_sz,
386 (int)(compressed_sz < 0
387 ? -compressed_sz : compressed_sz));
388 /* for statistical purposes
389 */
390 zftc_wr_compressed += (compressed_sz < 0
391 ? -compressed_sz : compressed_sz);
392 zftc_wr_uncompressed += in_sz;
393 }
394 TRACE_EXIT (int)compressed_sz;
395 }
396
397 /* called by zft_compress_read() to decompress the data. Must
398 * return the size of the decompressed data for sanity checks
399 * (compared with zft_blk_sz)
400 *
401 * NOTE: Read the note for zft_compress() above! If bit 15 of the
402 * parameter in_sz is set, then the data in in_buffer isn't
403 * compressed, which must be handled by the un-compression
404 * algorithm. (I changed lzrw3 to handle this.)
405 *
406 * The parameter max_out_sz is needed to prevent buffer overruns when
407 * uncompressing corrupt data.
408 */
409 static unsigned int zft_uncompress(__u8 *in_buffer,
410 int in_sz,
411 __u8 *out_buffer,
412 unsigned int max_out_sz)
413 {
414 TRACE_FUN(ft_t_flow);
415
416 lzrw3_compress(COMPRESS_ACTION_DECOMPRESS, zftc_wrk_mem,
417 in_buffer, (__s32)in_sz,
418 out_buffer, (__u32 *)&max_out_sz);
419
420 if (TRACE_LEVEL >= ft_t_info) {
421 TRACE(ft_t_data_flow, "\n"
422 KERN_INFO "before decompression: %d bytes\n"
423 KERN_INFO "after decompression : %d bytes",
424 in_sz < 0 ? -in_sz : in_sz,(int)max_out_sz);
425 /* for statistical purposes
426 */
427 zftc_rd_compressed += in_sz < 0 ? -in_sz : in_sz;
428 zftc_rd_uncompressed += max_out_sz;
429 }
430 TRACE_EXIT (unsigned int)max_out_sz;
431 }
432
433 /* print some statistics about the efficiency of the compression to
434 * the kernel log
435 */
436 static void zftc_stats(void)
437 {
438 TRACE_FUN(ft_t_flow);
439
440 if (TRACE_LEVEL < ft_t_info) {
441 TRACE_EXIT;
442 }
443 if (zftc_wr_uncompressed != 0) {
444 if (zftc_wr_compressed > (1<<14)) {
445 TRACE(ft_t_info, "compression statistics (writing):\n"
446 KERN_INFO " compr./uncmpr. : %3d %%",
447 (((zftc_wr_compressed>>10) * 100)
448 / (zftc_wr_uncompressed>>10)));
449 } else {
450 TRACE(ft_t_info, "compression statistics (writing):\n"
451 KERN_INFO " compr./uncmpr. : %3d %%",
452 ((zftc_wr_compressed * 100)
453 / zftc_wr_uncompressed));
454 }
455 }
456 if (zftc_rd_uncompressed != 0) {
457 if (zftc_rd_compressed > (1<<14)) {
458 TRACE(ft_t_info, "compression statistics (reading):\n"
459 KERN_INFO " compr./uncmpr. : %3d %%",
460 (((zftc_rd_compressed>>10) * 100)
461 / (zftc_rd_uncompressed>>10)));
462 } else {
463 TRACE(ft_t_info, "compression statistics (reading):\n"
464 KERN_INFO " compr./uncmpr. : %3d %%",
465 ((zftc_rd_compressed * 100)
466 / zftc_rd_uncompressed));
467 }
468 }
469 /* only print it once: */
470 zftc_wr_uncompressed =
471 zftc_wr_compressed =
472 zftc_rd_uncompressed =
473 zftc_rd_compressed = 0;
474 TRACE_EXIT;
475 }
476
477 /* start new compressed block
478 */
479 static int start_new_cseg(cmpr_info *cluster,
480 char *dst_buf,
481 const zft_position *pos,
482 const unsigned int blk_sz,
483 const char *src_buf,
484 const int this_segs_sz,
485 const int qic113)
486 {
487 int size_left;
488 int cp_cnt;
489 int buf_pos;
490 TRACE_FUN(ft_t_flow);
491
492 size_left = this_segs_sz - sizeof(__u16) - cluster->cmpr_sz;
493 TRACE(ft_t_data_flow,"\n"
494 KERN_INFO "segment size : %d\n"
495 KERN_INFO "compressed_sz: %d\n"
496 KERN_INFO "size_left : %d",
497 this_segs_sz, cluster->cmpr_sz, size_left);
498 if (size_left > 18) { /* start a new cluseter */
499 cp_cnt = cluster->cmpr_sz;
500 cluster->cmpr_sz = 0;
501 buf_pos = cp_cnt + sizeof(__u16);
502 PUT2(dst_buf, 0, buf_pos);
503
504 if (qic113) {
505 __s64 foffs = pos->volume_pos;
506 if (cp_cnt) foffs += (__s64)blk_sz;
507
508 TRACE(ft_t_data_flow, "new style QIC-113 header");
509 PUT8(dst_buf, buf_pos, foffs);
510 buf_pos += sizeof(__s64);
511 } else {
512 __u32 foffs = (__u32)pos->volume_pos;
513 if (cp_cnt) foffs += (__u32)blk_sz;
514
515 TRACE(ft_t_data_flow, "old style QIC-80MC header");
516 PUT4(dst_buf, buf_pos, foffs);
517 buf_pos += sizeof(__u32);
518 }
519 } else if (size_left >= 0) {
520 cp_cnt = cluster->cmpr_sz;
521 cluster->cmpr_sz = 0;
522 buf_pos = cp_cnt + sizeof(__u16);
523 PUT2(dst_buf, 0, buf_pos);
524 /* zero unused part of segment. */
525 memset(dst_buf + buf_pos, '\0', size_left);
526 buf_pos = this_segs_sz;
527 } else { /* need entire segment and more space */
528 PUT2(dst_buf, 0, 0);
529 cp_cnt = this_segs_sz - sizeof(__u16);
530 cluster->cmpr_sz -= cp_cnt;
531 buf_pos = this_segs_sz;
532 }
533 memcpy(dst_buf + sizeof(__u16), src_buf + cluster->cmpr_pos, cp_cnt);
534 cluster->cmpr_pos += cp_cnt;
535 TRACE_EXIT buf_pos;
536 }
537
538 /* return-value: the number of bytes removed from the user-buffer
539 * `src_buf' or error code
540 *
541 * int *write_cnt : how much actually has been moved to the
542 * dst_buf. Need not be initialized when
543 * function returns with an error code
544 * (negativ return value)
545 * __u8 *dst_buf : kernel space buffer where the has to be
546 * copied to. The contents of this buffers
547 * goes to a specific segment.
548 * const int seg_sz : the size of the segment dst_buf will be
549 * copied to.
550 * const zft_position *pos : struct containing the coordinates in
551 * the current volume (byte position,
552 * segment id of current segment etc)
553 * const zft_volinfo *volume: information about the current volume,
554 * size etc.
555 * const __u8 *src_buf : user space buffer that contains the
556 * data the user wants to be written to
557 * tape.
558 * const int req_len : the amount of data the user wants to be
559 * written to tape.
560 */
561 static int zftc_write(int *write_cnt,
562 __u8 *dst_buf, const int seg_sz,
563 const __u8 *src_buf, const int req_len,
564 const zft_position *pos, const zft_volinfo *volume)
565 {
566 int req_len_left = req_len;
567 int result;
568 int len_left;
569 int buf_pos_write = pos->seg_byte_pos;
570 TRACE_FUN(ft_t_flow);
571
572 keep_module_locked = 1;
573 #if LINUX_VERSION_CODE >= KERNEL_VER(2,1,18)
574 MOD_INC_USE_COUNT; /* sets MOD_VISITED and MOD_USED_ONCE,
575 * locking is done with can_unload()
576 */
577 #else
578 if (!MOD_IN_USE) {
579 MOD_INC_USE_COUNT;
580 }
581 #endif
582 /* Note: we do not unlock the module because
583 * there are some values cached in that `cseg' variable. We
584 * don't don't want to use this information when being
585 * unloaded by kerneld even when the tape is full or when we
586 * cannot allocate enough memory.
587 */
588 if (pos->tape_pos > (volume->size-volume->blk_sz-ZFT_CMPR_OVERHEAD)) {
589 TRACE_EXIT -ENOSPC;
590 }
591 if (zft_allocate_cmpr_mem(volume->blk_sz) < 0) {
592 /* should we unlock the module? But it shouldn't
593 * be locked anyway ...
594 */
595 TRACE_EXIT -ENOMEM;
596 }
597 if (buf_pos_write == 0) { /* fill a new segment */
598 *write_cnt = buf_pos_write = start_new_cseg(&cseg,
599 dst_buf,
600 pos,
601 volume->blk_sz,
602 zftc_buf,
603 seg_sz,
604 volume->qic113);
605 if (cseg.cmpr_sz == 0 && cseg.cmpr_pos != 0) {
606 req_len_left -= result = volume->blk_sz;
607 cseg.cmpr_pos = 0;
608 } else {
609 result = 0;
610 }
611 } else {
612 *write_cnt = result = 0;
613 }
614
615 len_left = seg_sz - buf_pos_write;
616 while ((req_len_left > 0) && (len_left > 18)) {
617 /* now we have some size left for a new compressed
618 * block. We know, that the compression buffer is
619 * empty (else there wouldn't be any space left).
620 */
621 #if LINUX_VERSION_CODE > KERNEL_VER(2,1,3)
622 if (copy_from_user(zftc_scratch_buf, src_buf + result,
623 volume->blk_sz) != 0) {
624 TRACE_EXIT -EFAULT;
625 }
626 #else
627 TRACE_CATCH(verify_area(VERIFY_READ, src_buf + result,
628 volume->blk_sz),);
629 memcpy_fromfs(zftc_scratch_buf, src_buf + result,
630 volume->blk_sz);
631 #endif
632 req_len_left -= volume->blk_sz;
633 cseg.cmpr_sz = zft_compress(zftc_scratch_buf, volume->blk_sz,
634 zftc_buf);
635 if (cseg.cmpr_sz < 0) {
636 cseg.uncmpr = 0x8000;
637 cseg.cmpr_sz = -cseg.cmpr_sz;
638 } else {
639 cseg.uncmpr = 0;
640 }
641 /* increment "result" iff we copied the entire
642 * compressed block to the zft_deblock_buf
643 */
644 len_left -= sizeof(__u16);
645 if (len_left >= cseg.cmpr_sz) {
646 len_left -= cseg.count = cseg.cmpr_sz;
647 cseg.cmpr_pos = cseg.cmpr_sz = 0;
648 result += volume->blk_sz;
649 } else {
650 cseg.cmpr_sz -=
651 cseg.cmpr_pos =
652 cseg.count = len_left;
653 len_left = 0;
654 }
655 PUT2(dst_buf, buf_pos_write, cseg.uncmpr | cseg.count);
656 buf_pos_write += sizeof(__u16);
657 memcpy(dst_buf + buf_pos_write, zftc_buf, cseg.count);
658 buf_pos_write += cseg.count;
659 *write_cnt += cseg.count + sizeof(__u16);
660 FT_SIGNAL_EXIT(_DONT_BLOCK);
661 }
662 /* erase the remainder of the segment if less than 18 bytes
663 * left (18 bytes is due to the QIC-80 standard)
664 */
665 if (len_left <= 18) {
666 memset(dst_buf + buf_pos_write, '\0', len_left);
667 (*write_cnt) += len_left;
668 }
669 TRACE(ft_t_data_flow, "returning %d", result);
670 TRACE_EXIT result;
671 }
672
673 /* out:
674 *
675 * int *read_cnt: the number of bytes we removed from the zft_deblock_buf
676 * (result)
677 * int *to_do : the remaining size of the read-request.
678 *
679 * in:
680 *
681 * char *buff : buff is the address of the upper part of the user
682 * buffer, that hasn't been filled with data yet.
683
684 * int buf_pos_read : copy of from _ftape_read()
685 * int buf_len_read : copy of buf_len_rd from _ftape_read()
686 * char *zft_deblock_buf: zft_deblock_buf
687 * unsigned short blk_sz: the block size valid for this volume, may differ
688 * from zft_blk_sz.
689 * int finish: if != 0 means that this is the last segment belonging
690 * to this volume
691 * returns the amount of data actually copied to the user-buffer
692 *
693 * to_do MUST NOT SHRINK except to indicate an EOF. In this case *to_do has to
694 * be set to 0
695 */
696 static int zftc_read (int *read_cnt,
697 __u8 *dst_buf, const int to_do,
698 const __u8 *src_buf, const int seg_sz,
699 const zft_position *pos, const zft_volinfo *volume)
700 {
701 int uncompressed_sz;
702 int result = 0;
703 int remaining = to_do;
704 TRACE_FUN(ft_t_flow);
705
706 keep_module_locked = 1;
707 #if LINUX_VERSION_CODE >= KERNEL_VER(2,1,18)
708 MOD_INC_USE_COUNT; /* sets MOD_VISITED and MOD_USED_ONCE,
709 * locking is done with can_unload()
710 */
711 #else
712 if (!MOD_IN_USE) {
713 MOD_INC_USE_COUNT;
714 }
715 #endif
716 TRACE_CATCH(zft_allocate_cmpr_mem(volume->blk_sz),);
717 if (pos->seg_byte_pos == 0) {
718 /* new segment just read
719 */
720 TRACE_CATCH(get_cseg(&cseg, src_buf, seg_sz, volume),
721 *read_cnt = 0);
722 memcpy(zftc_buf + cseg.cmpr_pos, src_buf + sizeof(__u16),
723 cseg.count);
724 cseg.cmpr_pos += cseg.count;
725 *read_cnt = cseg.offset;
726 DUMP_CMPR_INFO(ft_t_noise /* ft_t_any */, "", &cseg);
727 } else {
728 *read_cnt = 0;
729 }
730 /* loop and uncompress until user buffer full or
731 * deblock-buffer empty
732 */
733 TRACE(ft_t_data_flow, "compressed_sz: %d, compos : %d, *read_cnt: %d",
734 cseg.cmpr_sz, cseg.cmpr_pos, *read_cnt);
735 while ((cseg.spans == 0) && (remaining > 0)) {
736 if (cseg.cmpr_pos != 0) { /* cmpr buf is not empty */
737 uncompressed_sz =
738 zft_uncompress(zftc_buf,
739 cseg.uncmpr == 0x8000 ?
740 -cseg.cmpr_pos : cseg.cmpr_pos,
741 zftc_scratch_buf,
742 volume->blk_sz);
743 if (uncompressed_sz != volume->blk_sz) {
744 *read_cnt = 0;
745 TRACE_ABORT(-EIO, ft_t_warn,
746 "Uncompressed blk (%d) != blk size (%d)",
747 uncompressed_sz, volume->blk_sz);
748 }
749 #if LINUX_VERSION_CODE > KERNEL_VER(2,1,3)
750 if (copy_to_user(dst_buf + result,
751 zftc_scratch_buf,
752 uncompressed_sz) != 0 ) {
753 TRACE_EXIT -EFAULT;
754 }
755 #else
756 memcpy_tofs(dst_buf + result, zftc_scratch_buf,
757 uncompressed_sz);
758 #endif
759 remaining -= uncompressed_sz;
760 result += uncompressed_sz;
761 cseg.cmpr_pos = 0;
762 }
763 if (remaining > 0) {
764 get_next_cluster(&cseg, src_buf, seg_sz,
765 volume->end_seg == pos->seg_pos);
766 if (cseg.count != 0) {
767 memcpy(zftc_buf, src_buf + cseg.offset,
768 cseg.count);
769 cseg.cmpr_pos = cseg.count;
770 cseg.offset += cseg.count;
771 *read_cnt += cseg.count + sizeof(__u16);
772 } else {
773 remaining = 0;
774 }
775 }
776 TRACE(ft_t_data_flow, "\n"
777 KERN_INFO "compressed_sz: %d\n"
778 KERN_INFO "compos : %d\n"
779 KERN_INFO "*read_cnt : %d",
780 cseg.cmpr_sz, cseg.cmpr_pos, *read_cnt);
781 }
782 if (seg_sz - cseg.offset <= 18) {
783 *read_cnt += seg_sz - cseg.offset;
784 TRACE(ft_t_data_flow, "expanding read cnt to: %d", *read_cnt);
785 }
786 TRACE(ft_t_data_flow, "\n"
787 KERN_INFO "segment size : %d\n"
788 KERN_INFO "read count : %d\n"
789 KERN_INFO "buf_pos_read : %d\n"
790 KERN_INFO "remaining : %d",
791 seg_sz, *read_cnt, pos->seg_byte_pos,
792 seg_sz - *read_cnt - pos->seg_byte_pos);
793 TRACE(ft_t_data_flow, "returning: %d", result);
794 TRACE_EXIT result;
795 }
796
797 /* seeks to the new data-position. Reads sometimes a segment.
798 *
799 * start_seg and end_seg give the boundaries of the current volume
800 * blk_sz is the blk_sz of the current volume as stored in the
801 * volume label
802 *
803 * We don't allow blocksizes less than 1024 bytes, therefore we don't need
804 * a 64 bit argument for new_block_pos.
805 */
806
807 static int seek_in_segment(const unsigned int to_do, cmpr_info *c_info,
808 const char *src_buf, const int seg_sz,
809 const int seg_pos, const zft_volinfo *volume);
810 static int slow_seek_forward_until_error(const unsigned int distance,
811 cmpr_info *c_info, zft_position *pos,
812 const zft_volinfo *volume, __u8 *buf);
813 static int search_valid_segment(unsigned int segment,
814 const unsigned int end_seg,
815 const unsigned int max_foffs,
816 zft_position *pos, cmpr_info *c_info,
817 const zft_volinfo *volume, __u8 *buf);
818 static int slow_seek_forward(unsigned int dest, cmpr_info *c_info,
819 zft_position *pos, const zft_volinfo *volume,
820 __u8 *buf);
821 static int compute_seg_pos(unsigned int dest, zft_position *pos,
822 const zft_volinfo *volume);
823
824 #define ZFT_SLOW_SEEK_THRESHOLD 10 /* segments */
825 #define ZFT_FAST_SEEK_MAX_TRIALS 10 /* times */
826 #define ZFT_FAST_SEEK_BACKUP 10 /* segments */
827
828 static int zftc_seek(unsigned int new_block_pos,
829 zft_position *pos, const zft_volinfo *volume, __u8 *buf)
830 {
831 unsigned int dest;
832 int limit;
833 int distance;
834 int result = 0;
835 int seg_dist;
836 int new_seg;
837 int old_seg = 0;
838 int fast_seek_trials = 0;
839 TRACE_FUN(ft_t_flow);
840
841 keep_module_locked = 1;
842 #if LINUX_VERSION_CODE >= KERNEL_VER(2,1,18)
843 MOD_INC_USE_COUNT; /* sets MOD_VISITED and MOD_USED_ONCE,
844 * locking is done with can_unload()
845 */
846 #else
847 if (!MOD_IN_USE) {
848 MOD_INC_USE_COUNT;
849 }
850 #endif
851 if (new_block_pos == 0) {
852 pos->seg_pos = volume->start_seg;
853 pos->seg_byte_pos = 0;
854 pos->volume_pos = 0;
855 zftc_reset();
856 TRACE_EXIT 0;
857 }
858 dest = new_block_pos * (volume->blk_sz >> 10);
859 distance = dest - (pos->volume_pos >> 10);
860 while (distance != 0) {
861 seg_dist = compute_seg_pos(dest, pos, volume);
862 TRACE(ft_t_noise, "\n"
863 KERN_INFO "seg_dist: %d\n"
864 KERN_INFO "distance: %d\n"
865 KERN_INFO "dest : %d\n"
866 KERN_INFO "vpos : %d\n"
867 KERN_INFO "seg_pos : %d\n"
868 KERN_INFO "trials : %d",
869 seg_dist, distance, dest,
870 (unsigned int)(pos->volume_pos>>10), pos->seg_pos,
871 fast_seek_trials);
872 if (distance > 0) {
873 if (seg_dist < 0) {
874 TRACE(ft_t_bug, "BUG: distance %d > 0, "
875 "segment difference %d < 0",
876 distance, seg_dist);
877 result = -EIO;
878 break;
879 }
880 new_seg = pos->seg_pos + seg_dist;
881 if (new_seg > volume->end_seg) {
882 new_seg = volume->end_seg;
883 }
884 if (old_seg == new_seg || /* loop */
885 seg_dist <= ZFT_SLOW_SEEK_THRESHOLD ||
886 fast_seek_trials >= ZFT_FAST_SEEK_MAX_TRIALS) {
887 TRACE(ft_t_noise, "starting slow seek:\n"
888 KERN_INFO "fast seek failed too often: %s\n"
889 KERN_INFO "near target position : %s\n"
890 KERN_INFO "looping between two segs : %s",
891 (fast_seek_trials >=
892 ZFT_FAST_SEEK_MAX_TRIALS)
893 ? "yes" : "no",
894 (seg_dist <= ZFT_SLOW_SEEK_THRESHOLD)
895 ? "yes" : "no",
896 (old_seg == new_seg)
897 ? "yes" : "no");
898 result = slow_seek_forward(dest, &cseg,
899 pos, volume, buf);
900 break;
901 }
902 old_seg = new_seg;
903 limit = volume->end_seg;
904 fast_seek_trials ++;
905 for (;;) {
906 result = search_valid_segment(new_seg, limit,
907 volume->size,
908 pos, &cseg,
909 volume, buf);
910 if (result == 0 || result == -EINTR) {
911 break;
912 }
913 if (new_seg == volume->start_seg) {
914 result = -EIO; /* set errror
915 * condition
916 */
917 break;
918 }
919 limit = new_seg;
920 new_seg -= ZFT_FAST_SEEK_BACKUP;
921 if (new_seg < volume->start_seg) {
922 new_seg = volume->start_seg;
923 }
924 }
925 if (result < 0) {
926 TRACE(ft_t_warn,
927 "Couldn't find a readable segment");
928 break;
929 }
930 } else /* if (distance < 0) */ {
931 if (seg_dist > 0) {
932 TRACE(ft_t_bug, "BUG: distance %d < 0, "
933 "segment difference %d >0",
934 distance, seg_dist);
935 result = -EIO;
936 break;
937 }
938 new_seg = pos->seg_pos + seg_dist;
939 if (fast_seek_trials > 0 && seg_dist == 0) {
940 /* this avoids sticking to the same
941 * segment all the time. On the other hand:
942 * if we got here for the first time, and the
943 * deblock_buffer still contains a valid
944 * segment, then there is no need to skip to
945 * the previous segment if the desired position
946 * is inside this segment.
947 */
948 new_seg --;
949 }
950 if (new_seg < volume->start_seg) {
951 new_seg = volume->start_seg;
952 }
953 limit = pos->seg_pos;
954 fast_seek_trials ++;
955 for (;;) {
956 result = search_valid_segment(new_seg, limit,
957 pos->volume_pos,
958 pos, &cseg,
959 volume, buf);
960 if (result == 0 || result == -EINTR) {
961 break;
962 }
963 if (new_seg == volume->start_seg) {
964 result = -EIO; /* set errror
965 * condition
966 */
967 break;
968 }
969 limit = new_seg;
970 new_seg -= ZFT_FAST_SEEK_BACKUP;
971 if (new_seg < volume->start_seg) {
972 new_seg = volume->start_seg;
973 }
974 }
975 if (result < 0) {
976 TRACE(ft_t_warn,
977 "Couldn't find a readable segment");
978 break;
979 }
980 }
981 distance = dest - (pos->volume_pos >> 10);
982 }
983 TRACE_EXIT result;
984 }
985
986
987 /* advance inside the given segment at most to_do bytes.
988 * of kilobytes moved
989 */
990
991 static int seek_in_segment(const unsigned int to_do,
992 cmpr_info *c_info,
993 const char *src_buf,
994 const int seg_sz,
995 const int seg_pos,
996 const zft_volinfo *volume)
997 {
998 int result = 0;
999 int blk_sz = volume->blk_sz >> 10;
1000 int remaining = to_do;
1001 TRACE_FUN(ft_t_flow);
1002
1003 if (c_info->offset == 0) {
1004 /* new segment just read
1005 */
1006 TRACE_CATCH(get_cseg(c_info, src_buf, seg_sz, volume),);
1007 c_info->cmpr_pos += c_info->count;
1008 DUMP_CMPR_INFO(ft_t_noise, "", c_info);
1009 }
1010 /* loop and uncompress until user buffer full or
1011 * deblock-buffer empty
1012 */
1013 TRACE(ft_t_noise, "compressed_sz: %d, compos : %d",
1014 c_info->cmpr_sz, c_info->cmpr_pos);
1015 while (c_info->spans == 0 && remaining > 0) {
1016 if (c_info->cmpr_pos != 0) { /* cmpr buf is not empty */
1017 result += blk_sz;
1018 remaining -= blk_sz;
1019 c_info->cmpr_pos = 0;
1020 }
1021 if (remaining > 0) {
1022 get_next_cluster(c_info, src_buf, seg_sz,
1023 volume->end_seg == seg_pos);
1024 if (c_info->count != 0) {
1025 c_info->cmpr_pos = c_info->count;
1026 c_info->offset += c_info->count;
1027 } else {
1028 break;
1029 }
1030 }
1031 /* Allow escape from this loop on signal!
1032 */
1033 FT_SIGNAL_EXIT(_DONT_BLOCK);
1034 DUMP_CMPR_INFO(ft_t_noise, "", c_info);
1035 TRACE(ft_t_noise, "to_do: %d", remaining);
1036 }
1037 if (seg_sz - c_info->offset <= 18) {
1038 c_info->offset = seg_sz;
1039 }
1040 TRACE(ft_t_noise, "\n"
1041 KERN_INFO "segment size : %d\n"
1042 KERN_INFO "buf_pos_read : %d\n"
1043 KERN_INFO "remaining : %d",
1044 seg_sz, c_info->offset,
1045 seg_sz - c_info->offset);
1046 TRACE_EXIT result;
1047 }
1048
1049 static int slow_seek_forward_until_error(const unsigned int distance,
1050 cmpr_info *c_info,
1051 zft_position *pos,
1052 const zft_volinfo *volume,
1053 __u8 *buf)
1054 {
1055 unsigned int remaining = distance;
1056 int seg_sz;
1057 int seg_pos;
1058 int result;
1059 TRACE_FUN(ft_t_flow);
1060
1061 seg_pos = pos->seg_pos;
1062 do {
1063 TRACE_CATCH(seg_sz = zft_fetch_segment(seg_pos, buf,
1064 FT_RD_AHEAD),);
1065 /* now we have the contents of the actual segment in
1066 * the deblock buffer
1067 */
1068 TRACE_CATCH(result = seek_in_segment(remaining, c_info, buf,
1069 seg_sz, seg_pos,volume),);
1070 remaining -= result;
1071 pos->volume_pos += result<<10;
1072 pos->seg_pos = seg_pos;
1073 pos->seg_byte_pos = c_info->offset;
1074 seg_pos ++;
1075 if (seg_pos <= volume->end_seg && c_info->offset == seg_sz) {
1076 pos->seg_pos ++;
1077 pos->seg_byte_pos = 0;
1078 c_info->offset = 0;
1079 }
1080 /* Allow escape from this loop on signal!
1081 */
1082 FT_SIGNAL_EXIT(_DONT_BLOCK);
1083 TRACE(ft_t_noise, "\n"
1084 KERN_INFO "remaining: %d\n"
1085 KERN_INFO "seg_pos: %d\n"
1086 KERN_INFO "end_seg: %d\n"
1087 KERN_INFO "result: %d",
1088 remaining, seg_pos, volume->end_seg, result);
1089 } while (remaining > 0 && seg_pos <= volume->end_seg);
1090 TRACE_EXIT 0;
1091 }
1092
1093 /* return segment id of next segment containing valid data, -EIO otherwise
1094 */
1095 static int search_valid_segment(unsigned int segment,
1096 const unsigned int end_seg,
1097 const unsigned int max_foffs,
1098 zft_position *pos,
1099 cmpr_info *c_info,
1100 const zft_volinfo *volume,
1101 __u8 *buf)
1102 {
1103 cmpr_info tmp_info;
1104 int seg_sz;
1105 TRACE_FUN(ft_t_flow);
1106
1107 memset(&tmp_info, 0, sizeof(cmpr_info));
1108 while (segment <= end_seg) {
1109 FT_SIGNAL_EXIT(_DONT_BLOCK);
1110 TRACE(ft_t_noise,
1111 "Searching readable segment between %d and %d",
1112 segment, end_seg);
1113 seg_sz = zft_fetch_segment(segment, buf, FT_RD_AHEAD);
1114 if ((seg_sz > 0) &&
1115 (get_cseg (&tmp_info, buf, seg_sz, volume) >= 0) &&
1116 (tmp_info.foffs != 0 || segment == volume->start_seg)) {
1117 if ((tmp_info.foffs>>10) > max_foffs) {
1118 TRACE_ABORT(-EIO, ft_t_noise, "\n"
1119 KERN_INFO "cseg.foff: %d\n"
1120 KERN_INFO "dest : %d",
1121 (int)(tmp_info.foffs >> 10),
1122 max_foffs);
1123 }
1124 DUMP_CMPR_INFO(ft_t_noise, "", &tmp_info);
1125 *c_info = tmp_info;
1126 pos->seg_pos = segment;
1127 pos->volume_pos = c_info->foffs;
1128 pos->seg_byte_pos = c_info->offset;
1129 TRACE(ft_t_noise, "found segment at %d", segment);
1130 TRACE_EXIT 0;
1131 }
1132 segment++;
1133 }
1134 TRACE_EXIT -EIO;
1135 }
1136
1137 static int slow_seek_forward(unsigned int dest,
1138 cmpr_info *c_info,
1139 zft_position *pos,
1140 const zft_volinfo *volume,
1141 __u8 *buf)
1142 {
1143 unsigned int distance;
1144 int result = 0;
1145 TRACE_FUN(ft_t_flow);
1146
1147 distance = dest - (pos->volume_pos >> 10);
1148 while ((distance > 0) &&
1149 (result = slow_seek_forward_until_error(distance,
1150 c_info,
1151 pos,
1152 volume,
1153 buf)) < 0) {
1154 if (result == -EINTR) {
1155 break;
1156 }
1157 TRACE(ft_t_noise, "seg_pos: %d", pos->seg_pos);
1158 /* the failing segment is either pos->seg_pos or
1159 * pos->seg_pos + 1. There is no need to further try
1160 * that segment, because ftape_read_segment() already
1161 * has tried very much to read it. So we start with
1162 * following segment, which is pos->seg_pos + 1
1163 */
1164 if(search_valid_segment(pos->seg_pos+1, volume->end_seg, dest,
1165 pos, c_info,
1166 volume, buf) < 0) {
1167 TRACE(ft_t_noise, "search_valid_segment() failed");
1168 result = -EIO;
1169 break;
1170 }
1171 distance = dest - (pos->volume_pos >> 10);
1172 result = 0;
1173 TRACE(ft_t_noise, "segment: %d", pos->seg_pos);
1174 /* found valid segment, retry the seek */
1175 }
1176 TRACE_EXIT result;
1177 }
1178
1179 static int compute_seg_pos(const unsigned int dest,
1180 zft_position *pos,
1181 const zft_volinfo *volume)
1182 {
1183 int segment;
1184 int distance = dest - (pos->volume_pos >> 10);
1185 unsigned int raw_size;
1186 unsigned int virt_size;
1187 unsigned int factor;
1188 TRACE_FUN(ft_t_flow);
1189
1190 if (distance >= 0) {
1191 raw_size = volume->end_seg - pos->seg_pos + 1;
1192 virt_size = ((unsigned int)(volume->size>>10)
1193 - (unsigned int)(pos->volume_pos>>10)
1194 + FT_SECTORS_PER_SEGMENT - FT_ECC_SECTORS - 1);
1195 virt_size /= FT_SECTORS_PER_SEGMENT - FT_ECC_SECTORS;
1196 if (virt_size == 0 || raw_size == 0) {
1197 TRACE_EXIT 0;
1198 }
1199 if (raw_size >= (1<<25)) {
1200 factor = raw_size/(virt_size>>7);
1201 } else {
1202 factor = (raw_size<<7)/virt_size;
1203 }
1204 segment = distance/(FT_SECTORS_PER_SEGMENT-FT_ECC_SECTORS);
1205 segment = (segment * factor)>>7;
1206 } else {
1207 raw_size = pos->seg_pos - volume->start_seg + 1;
1208 virt_size = ((unsigned int)(pos->volume_pos>>10)
1209 + FT_SECTORS_PER_SEGMENT - FT_ECC_SECTORS - 1);
1210 virt_size /= FT_SECTORS_PER_SEGMENT - FT_ECC_SECTORS;
1211 if (virt_size == 0 || raw_size == 0) {
1212 TRACE_EXIT 0;
1213 }
1214 if (raw_size >= (1<<25)) {
1215 factor = raw_size/(virt_size>>7);
1216 } else {
1217 factor = (raw_size<<7)/virt_size;
1218 }
1219 segment = distance/(FT_SECTORS_PER_SEGMENT-FT_ECC_SECTORS);
1220 }
1221 TRACE(ft_t_noise, "factor: %d/%d", factor, 1<<7);
1222 TRACE_EXIT segment;
1223 }
1224
1225 static struct zft_cmpr_ops cmpr_ops = {
1226 zftc_write,
1227 zftc_read,
1228 zftc_seek,
1229 zftc_lock,
1230 zftc_reset,
1231 zftc_cleanup
1232 };
1233
1234 int zft_compressor_init(void)
1235 {
1236 TRACE_FUN(ft_t_flow);
1237
1238 #ifdef MODULE
1239 printk(KERN_INFO "zftape compressor v1.00a 970514 for " FTAPE_VERSION "\n");
1240 if (TRACE_LEVEL >= ft_t_info) {
1241 printk(
1242 KERN_INFO "(c) 1997 Claus-Justus Heine (claus@momo.math.rwth-aachen.de)\n"
1243 KERN_INFO "Compressor for zftape (lzrw3 algorithm)\n"
1244 KERN_INFO "Compiled for kernel version %s"
1245 #ifdef MODVERSIONS
1246 " with versioned symbols"
1247 #endif
1248 "\n", UTS_RELEASE);
1249 }
1250 #else /* !MODULE */
1251 /* print a short no-nonsense boot message */
1252 printk("zftape compressor v1.00a 970514 for Linux " UTS_RELEASE "\n");
1253 printk("For use with " FTAPE_VERSION "\n");
1254 #endif /* MODULE */
1255 TRACE(ft_t_info, "zft_compressor_init @ 0x%p", zft_compressor_init);
1256 TRACE(ft_t_info, "installing compressor for zftape ...");
1257 TRACE_CATCH(zft_cmpr_register(&cmpr_ops),);
1258 TRACE_EXIT 0;
1259 }
1260
1261 #ifdef MODULE
1262
1263 MODULE_AUTHOR(
1264 "(c) 1996, 1997 Claus-Justus Heine (claus@momo.math.rwth-aachen.de");
1265 MODULE_DESCRIPTION(
1266 "Compression routines for zftape. Uses the lzrw3 algorithm by Ross Williams");
1267 MODULE_LICENSE("GPL");
1268
1269 #if LINUX_VERSION_CODE >= KERNEL_VER(2,1,18)
1270 static int can_unload(void)
1271 {
1272 return keep_module_locked ? -EBUSY : 0;
1273 }
1274 #endif
1275
1276 /* Called by modules package when installing the driver
1277 */
1278 int init_module(void)
1279 {
1280 int result;
1281
1282 #if LINUX_VERSION_CODE < KERNEL_VER(2,1,18)
1283 register_symtab(0); /* remove global ftape symbols */
1284 #else
1285 if (!mod_member_present(&__this_module, can_unload))
1286 return -EBUSY;
1287 __this_module.can_unload = can_unload;
1288 EXPORT_NO_SYMBOLS;
1289 #endif
1290 result = zft_compressor_init();
1291 keep_module_locked = 0;
1292 return result;
1293 }
1294
1295 /* Called by modules package when removing the driver
1296 */
1297 void cleanup_module(void)
1298 {
1299 TRACE_FUN(ft_t_flow);
1300
1301 if (zft_cmpr_unregister() != &cmpr_ops) {
1302 TRACE(ft_t_info, "failed");
1303 } else {
1304 TRACE(ft_t_info, "successful");
1305 }
1306 zftc_cleanup();
1307 printk(KERN_INFO "zft-compressor successfully unloaded.\n");
1308 TRACE_EXIT;
1309 }
1310 #endif /* MODULE */
1311