zftape-read.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:11k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  *      Copyright (C) 1996, 1997 Claus-Justus Heine
  3.  This program is free software; you can redistribute it and/or modify
  4.  it under the terms of the GNU General Public License as published by
  5.  the Free Software Foundation; either version 2, or (at your option)
  6.  any later version.
  7.  This program is distributed in the hope that it will be useful,
  8.  but WITHOUT ANY WARRANTY; without even the implied warranty of
  9.  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  10.  GNU General Public License for more details.
  11.  You should have received a copy of the GNU General Public License
  12.  along with this program; see the file COPYING.  If not, write to
  13.  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  14.  *
  15.  * $Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-read.c,v $
  16.  * $Revision: 1.2 $
  17.  * $Date: 1997/10/05 19:19:06 $
  18.  *
  19.  *      This file contains the high level reading code
  20.  *      for the QIC-117 floppy-tape driver for Linux.
  21.  */
  22. #include <linux/errno.h>
  23. #include <linux/mm.h>
  24. #include <linux/zftape.h>
  25. #if LINUX_VERSION_CODE >= KERNEL_VER(2,1,6)
  26. #include <asm/uaccess.h>
  27. #else
  28. #include <asm/segment.h>
  29. #endif
  30. #include "../zftape/zftape-init.h"
  31. #include "../zftape/zftape-eof.h"
  32. #include "../zftape/zftape-ctl.h"
  33. #include "../zftape/zftape-write.h"
  34. #include "../zftape/zftape-read.h"
  35. #include "../zftape/zftape-rw.h"
  36. #include "../zftape/zftape-vtbl.h"
  37. /*      Global vars.
  38.  */
  39. int zft_just_before_eof;
  40. /*      Local vars.
  41.  */
  42. static int buf_len_rd;
  43. void zft_zap_read_buffers(void)
  44. {
  45. buf_len_rd = 0;
  46. }
  47. int zft_read_header_segments(void)      
  48. {
  49. TRACE_FUN(ft_t_flow);
  50. zft_header_read = 0;
  51. TRACE_CATCH(zft_vmalloc_once(&zft_hseg_buf, FT_SEGMENT_SIZE),);
  52. TRACE_CATCH(ftape_read_header_segment(zft_hseg_buf),);
  53. TRACE(ft_t_info, "Segments written since first format: %d",
  54.       (int)GET4(zft_hseg_buf, FT_SEG_CNT));
  55. zft_qic113 = (ft_format_code != fmt_normal &&
  56.       ft_format_code != fmt_1100ft &&
  57.       ft_format_code != fmt_425ft);
  58. TRACE(ft_t_info, "ft_first_data_segment: %d, ft_last_data_segment: %d", 
  59.       ft_first_data_segment, ft_last_data_segment);
  60. zft_capacity = zft_get_capacity();
  61. zft_old_ftape = zft_ftape_validate_label(&zft_hseg_buf[FT_LABEL]);
  62. if (zft_old_ftape) {
  63. TRACE(ft_t_info, 
  64. "Found old ftaped tape, emulating eof marks, entering read-only mode");
  65. zft_ftape_extract_file_marks(zft_hseg_buf);
  66. TRACE_CATCH(zft_fake_volume_headers(zft_eof_map, 
  67.     zft_nr_eof_marks),);
  68. } else {
  69. /* the specs say that the volume table must be
  70.  * initialized with zeroes during formatting, so it
  71.  * MUST be readable, i.e. contain vaid ECC
  72.  * information.  
  73.  */
  74. TRACE_CATCH(ftape_read_segment(ft_first_data_segment, 
  75.        zft_deblock_buf, 
  76.        FT_RD_SINGLE),);
  77. TRACE_CATCH(zft_extract_volume_headers(zft_deblock_buf),);
  78. }
  79. zft_header_read = 1;
  80. zft_set_flags(zft_unit);
  81. zft_reset_position(&zft_pos);
  82. TRACE_EXIT 0;
  83. }
  84. int zft_fetch_segment_fraction(const unsigned int segment, void *buffer,
  85.        const ft_read_mode_t read_mode,
  86.        const unsigned int start,
  87.        const unsigned int size)
  88. {
  89. int seg_sz;
  90. TRACE_FUN(ft_t_flow);
  91. if (segment == zft_deblock_segment) {
  92. TRACE(ft_t_data_flow,
  93.       "re-using segment %d already in deblock buffer",
  94.       segment);
  95. seg_sz = zft_get_seg_sz(segment);
  96. if (start > seg_sz) {
  97. TRACE_ABORT(-EINVAL, ft_t_bug,
  98.     "trying to read beyond end of segment:n"
  99.     KERN_INFO "seg_sz : %dn"
  100.     KERN_INFO "start  : %dn"
  101.     KERN_INFO "segment: %d",
  102.     seg_sz, start, segment);
  103. }
  104. if ((start + size) > seg_sz) {
  105. TRACE_EXIT seg_sz - start;
  106. }
  107. TRACE_EXIT size;
  108. }
  109. seg_sz = ftape_read_segment_fraction(segment, buffer, read_mode,
  110.      start, size);
  111. TRACE(ft_t_data_flow, "segment %d, result %d", segment, seg_sz);
  112. if ((int)seg_sz >= 0 && start == 0 && size == FT_SEGMENT_SIZE) {
  113. /*  this implicitly assumes that we are always called with
  114.  *  buffer == zft_deblock_buf 
  115.  */
  116. zft_deblock_segment = segment;
  117. } else {
  118. zft_deblock_segment = -1;
  119. }
  120. TRACE_EXIT seg_sz;
  121. }
  122. /*
  123.  * out:
  124.  *
  125.  * int *read_cnt: the number of bytes we removed from the
  126.  *                zft_deblock_buf (result)
  127.  *
  128.  * int *to_do   : the remaining size of the read-request. Is changed.
  129.  *
  130.  * in:
  131.  *
  132.  * char *buff      : buff is the address of the upper part of the user
  133.  *                   buffer, that hasn't been filled with data yet.
  134.  * int buf_pos_read: copy of buf_pos_rd
  135.  * int buf_len_read: copy of buf_len_rd
  136.  * char *zft_deblock_buf: ftape_zft_deblock_buf
  137.  *
  138.  * returns the amount of data actually copied to the user-buffer
  139.  *
  140.  * to_do MUST NOT SHRINK except to indicate an EOT. In this case to_do
  141.  * has to be set to 0. We cannot return -ENOSPC, because we return the
  142.  * amount of data actually * copied to the user-buffer
  143.  */
  144. static int zft_simple_read (int *read_cnt, 
  145.     __u8  *dst_buf, 
  146.     const int to_do, 
  147.     const __u8 *src_buf, 
  148.     const int seg_sz, 
  149.     const zft_position *pos,
  150.     const zft_volinfo *volume)
  151. {
  152. TRACE_FUN(ft_t_flow);
  153. if (seg_sz - pos->seg_byte_pos < to_do) {
  154. *read_cnt = seg_sz - pos->seg_byte_pos;
  155. } else {
  156. *read_cnt = to_do;
  157. }
  158. #if LINUX_VERSION_CODE > KERNEL_VER(2,1,3)
  159. if (copy_to_user(dst_buf, 
  160.  src_buf + pos->seg_byte_pos, *read_cnt) != 0) {
  161. TRACE_EXIT -EFAULT;
  162. }
  163. #else
  164. TRACE_CATCH(verify_area(VERIFY_WRITE, dst_buf, *read_cnt),);
  165. memcpy_tofs(dst_buf, src_buf +  pos->seg_byte_pos, *read_cnt);
  166. #endif
  167. TRACE(ft_t_noise, "nr bytes just read: %d", *read_cnt);
  168. TRACE_EXIT *read_cnt;
  169. }
  170. /* req_len: gets clipped due to EOT of EOF.
  171.  * req_clipped: is a flag indicating whether req_len was clipped or not
  172.  * volume: contains information on current volume (blk_sz etc.)
  173.  */
  174. static int check_read_access(int *req_len, 
  175.      const zft_volinfo **volume,
  176.      int *req_clipped, 
  177.      const zft_position *pos)
  178. {
  179. static __s64 remaining;
  180. static int eod;
  181. TRACE_FUN(ft_t_flow);
  182. if (zft_io_state != zft_reading) {
  183. if (zft_offline) { /* offline includes no_tape */
  184. TRACE_ABORT(-ENXIO, ft_t_warn,
  185.     "tape is offline or no cartridge");
  186. }
  187. if (!ft_formatted) {
  188. TRACE_ABORT(-EACCES,
  189.     ft_t_warn, "tape is not formatted");
  190. }
  191. /*  now enter defined state, read header segment if not
  192.  *  already done and flush write buffers
  193.  */
  194. TRACE_CATCH(zft_def_idle_state(),);
  195. zft_io_state = zft_reading;
  196. if (zft_tape_at_eod(pos)) {
  197. eod = 1;
  198. TRACE_EXIT 1;
  199. }
  200. eod = 0;
  201. *volume = zft_find_volume(pos->seg_pos);
  202. /* get the space left until EOF */
  203. remaining = zft_check_for_eof(*volume, pos);
  204. buf_len_rd = 0;
  205. TRACE(ft_t_noise, "remaining: " LL_X ", vol_no: %d",
  206.       LL(remaining), (*volume)->count);
  207. } else if (zft_tape_at_eod(pos)) {
  208. if (++eod > 2) {
  209. TRACE_EXIT -EIO; /* st.c also returns -EIO */
  210. } else {
  211. TRACE_EXIT 1;
  212. }
  213. }
  214. if ((*req_len % (*volume)->blk_sz) != 0) {
  215. /*  this message is informational only. The user gets the
  216.  *  proper return value
  217.  */
  218. TRACE_ABORT(-EINVAL, ft_t_info,
  219.     "req_len %d not a multiple of block size %d",
  220.     *req_len, (*volume)->blk_sz);
  221. }
  222. /* As GNU tar doesn't accept partial read counts when the
  223.  * multiple volume flag is set, we make sure to return the
  224.  * requested amount of data. Except, of course, at the end of
  225.  * the tape or file mark.  
  226.  */
  227. remaining -= *req_len;
  228. if (remaining <= 0) {
  229. TRACE(ft_t_noise, 
  230.       "clipped request from %d to %d.", 
  231.       *req_len, (int)(*req_len + remaining));
  232. *req_len += remaining;
  233. *req_clipped = 1;
  234. } else {
  235. *req_clipped = 0;
  236. }
  237. TRACE_EXIT 0;
  238. }
  239. /* this_segs_size: the current segment's size.
  240.  * buff: the USER-SPACE buffer provided by the calling function.
  241.  * req_len: how much data should be read at most.
  242.  * volume: contains information on current volume (blk_sz etc.)
  243.  */  
  244. static int empty_deblock_buf(__u8 *usr_buf, const int req_len,
  245.      const __u8 *src_buf, const int seg_sz,
  246.      zft_position *pos,
  247.      const zft_volinfo *volume)
  248. {
  249. int cnt;
  250. int result = 0;
  251. TRACE_FUN(ft_t_flow);
  252. TRACE(ft_t_data_flow, "this_segs_size: %d", seg_sz);
  253. if (zft_use_compression && volume->use_compression) {
  254. TRACE_CATCH(zft_cmpr_lock(1 /* try to load */),);
  255. TRACE_CATCH(result= (*zft_cmpr_ops->read)(&cnt,
  256.   usr_buf, req_len,
  257.   src_buf, seg_sz,
  258.   pos, volume),);
  259. } else {                                  
  260. TRACE_CATCH(result= zft_simple_read (&cnt,
  261.      usr_buf, req_len,
  262.      src_buf, seg_sz,
  263.      pos, volume),);
  264. }
  265. pos->volume_pos   += result;
  266.         pos->tape_pos     += cnt;
  267. pos->seg_byte_pos += cnt;
  268. buf_len_rd        -= cnt; /* remaining bytes in buffer */
  269. TRACE(ft_t_data_flow, "buf_len_rd: %d, cnt: %d", buf_len_rd, cnt);
  270. if(pos->seg_byte_pos >= seg_sz) {
  271. pos->seg_pos++;
  272. pos->seg_byte_pos = 0;
  273. }
  274. TRACE(ft_t_data_flow, "bytes moved out of deblock-buffer: %d", cnt);
  275. TRACE_EXIT result;
  276. }
  277. /* note: we store the segment id of the segment that is inside the
  278.  * deblock buffer. This spares a lot of ftape_read_segment()s when we
  279.  * use small block-sizes. The block-size may be 1kb (SECTOR_SIZE). In
  280.  * this case a MTFSR 28 maybe still inside the same segment.
  281.  */
  282. int _zft_read(char* buff, int req_len)
  283. {
  284. int req_clipped;
  285. int result     = 0;
  286. int bytes_read = 0;
  287. static unsigned int seg_sz = 0;
  288. static const zft_volinfo *volume = NULL;
  289. TRACE_FUN(ft_t_flow);
  290. zft_resid = req_len;
  291. result = check_read_access(&req_len, &volume,
  292.    &req_clipped, &zft_pos);
  293. switch(result) {
  294. case 0: 
  295. break; /* nothing special */
  296. case 1: 
  297. TRACE(ft_t_noise, "EOD reached");
  298. TRACE_EXIT 0;   /* EOD */
  299. default:
  300. TRACE_ABORT(result, ft_t_noise,
  301.     "check_read_access() failed with result %d",
  302.     result);
  303. TRACE_EXIT result;
  304. }
  305. while (req_len > 0) { 
  306. /*  Allow escape from this loop on signal !
  307.  */
  308. FT_SIGNAL_EXIT(_DONT_BLOCK);
  309. /* buf_len_rd == 0 means that we need to read a new
  310.  * segment.
  311.  */
  312. if (buf_len_rd == 0) {
  313. while((result = zft_fetch_segment(zft_pos.seg_pos,
  314.   zft_deblock_buf,
  315.   FT_RD_AHEAD)) == 0) {
  316. zft_pos.seg_pos ++;
  317. zft_pos.seg_byte_pos = 0;
  318. }
  319. if (result < 0) {
  320. zft_resid -= bytes_read;
  321. TRACE_ABORT(result, ft_t_noise,
  322.     "zft_fetch_segment(): %d",
  323.     result);
  324. }
  325. seg_sz = result;
  326. buf_len_rd = seg_sz - zft_pos.seg_byte_pos;
  327. }
  328. TRACE_CATCH(result = empty_deblock_buf(buff, 
  329.        req_len,
  330.        zft_deblock_buf, 
  331.        seg_sz, 
  332.        &zft_pos,
  333.        volume),
  334.     zft_resid -= bytes_read);
  335. TRACE(ft_t_data_flow, "bytes just read: %d", result);
  336. bytes_read += result; /* what we got so far       */
  337. buff       += result; /* index in user-buffer     */
  338. req_len    -= result; /* what's left from req_len */
  339. } /* while (req_len  > 0) */
  340. if (req_clipped) {
  341. TRACE(ft_t_data_flow,
  342.       "maybe partial count because of eof mark");
  343. if (zft_just_before_eof && bytes_read == 0) {
  344. /* req_len was > 0, but user didn't get
  345.  * anything the user has read in the eof-mark 
  346.  */
  347. zft_move_past_eof(&zft_pos);
  348. ftape_abort_operation();
  349. } else {
  350. /* don't skip to the next file before the user
  351.  * tried to read a second time past EOF Just
  352.  * mark that we are at EOF and maybe decrement
  353.  * zft_seg_pos to stay in the same volume;
  354.  */
  355. zft_just_before_eof = 1;
  356. zft_position_before_eof(&zft_pos, volume);
  357. TRACE(ft_t_noise, "just before eof");
  358. }
  359. }
  360. zft_resid -= result; /* for MTSTATUS       */
  361. TRACE_EXIT bytes_read;
  362. }