zftape-write.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:14k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  *      Copyright (C) 1996, 1997 Claus 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-write.c,v $
  16.  * $Revision: 1.3 $
  17.  * $Date: 1997/11/06 00:50:29 $
  18.  *
  19.  *      This file contains the writing 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. /*      Local vars.
  40.  */
  41. static int last_write_failed;
  42. static int need_flush;
  43. void zft_prevent_flush(void)
  44. {
  45. need_flush = 0;
  46. }
  47. static int zft_write_header_segments(__u8* buffer)
  48. {
  49. int header_1_ok = 0;
  50. int header_2_ok = 0;
  51. unsigned int time_stamp;
  52. TRACE_FUN(ft_t_noise);
  53. TRACE_CATCH(ftape_abort_operation(),);
  54. ftape_seek_to_bot();    /* prevents extra rewind */
  55. if (GET4(buffer, 0) != FT_HSEG_MAGIC) {
  56. TRACE_ABORT(-EIO, ft_t_err,
  57.     "wrong header signature found, aborting");
  58. /*   Be optimistic: */
  59. PUT4(buffer, FT_SEG_CNT,
  60.      zft_written_segments + GET4(buffer, FT_SEG_CNT) + 2);
  61. if ((time_stamp = zft_get_time()) != 0) {
  62. PUT4(buffer, FT_WR_DATE, time_stamp);
  63. if (zft_label_changed) {
  64. PUT4(buffer, FT_LABEL_DATE, time_stamp);
  65. }
  66. }
  67. TRACE(ft_t_noise,
  68.       "writing first header segment %d", ft_header_segment_1);
  69. header_1_ok = zft_verify_write_segments(ft_header_segment_1, 
  70. buffer, FT_SEGMENT_SIZE,
  71. zft_deblock_buf) >= 0;
  72. TRACE(ft_t_noise,
  73.       "writing second header segment %d", ft_header_segment_2);
  74. header_2_ok = zft_verify_write_segments(ft_header_segment_2, 
  75. buffer, FT_SEGMENT_SIZE,
  76. zft_deblock_buf) >= 0;
  77. if (!header_1_ok) {
  78. TRACE(ft_t_warn, "Warning: "
  79.       "update of first header segment failed");
  80. }
  81. if (!header_2_ok) {
  82. TRACE(ft_t_warn, "Warning: "
  83.       "update of second header segment failed");
  84. }
  85. if (!header_1_ok && !header_2_ok) {
  86. TRACE_ABORT(-EIO, ft_t_err, "Error: "
  87.       "update of both header segments failed.");
  88. }
  89. TRACE_EXIT 0;
  90. }
  91. int zft_update_header_segments(void)
  92. {
  93. TRACE_FUN(ft_t_noise);
  94. /*  must NOT use zft_write_protected, as it also includes the
  95.  *  file access mode. But we also want to update when soft
  96.  *  write protection is enabled (O_RDONLY)
  97.  */
  98. if (ft_write_protected || zft_old_ftape) {
  99. TRACE_ABORT(0, ft_t_noise, "Tape set read-only: no update");
  100. if (!zft_header_read) {
  101. TRACE_ABORT(0, ft_t_noise, "Nothing to update");
  102. }
  103. if (!zft_header_changed) {
  104. zft_header_changed = zft_written_segments > 0;
  105. }
  106. if (!zft_header_changed && !zft_volume_table_changed) {
  107. TRACE_ABORT(0, ft_t_noise, "Nothing to update");
  108. }
  109. TRACE(ft_t_noise, "Updating header segments");
  110. if (ftape_get_status()->fti_state == writing) {
  111. TRACE_CATCH(ftape_loop_until_writes_done(),);
  112. }
  113. TRACE_CATCH(ftape_abort_operation(),);
  114. zft_deblock_segment = -1; /* invalidate the cache */
  115. if (zft_header_changed) {
  116. TRACE_CATCH(zft_write_header_segments(zft_hseg_buf),);
  117. }
  118. if (zft_volume_table_changed) {
  119. TRACE_CATCH(zft_update_volume_table(ft_first_data_segment),);
  120. }
  121. zft_header_changed =
  122. zft_volume_table_changed = 
  123. zft_label_changed        =
  124. zft_written_segments     = 0;
  125. TRACE_CATCH(ftape_abort_operation(),);
  126. ftape_seek_to_bot();
  127. TRACE_EXIT 0;
  128. }
  129. static int read_merge_buffer(int seg_pos, __u8 *buffer, int offset, int seg_sz)
  130. {
  131. int result = 0;
  132. const ft_trace_t old_tracing = TRACE_LEVEL;
  133. TRACE_FUN(ft_t_flow);
  134. if (zft_qic_mode) {
  135. /*  writing in the middle of a volume is NOT allowed
  136.  *
  137.  */
  138. TRACE(ft_t_noise, "No need to read a segment");
  139. memset(buffer + offset, 0, seg_sz - offset);
  140. TRACE_EXIT 0;
  141. }
  142. TRACE(ft_t_any, "waiting");
  143. ftape_start_writing(FT_WR_MULTI);
  144. TRACE_CATCH(ftape_loop_until_writes_done(),);
  145. TRACE(ft_t_noise, "trying to read segment %d from offset %d",
  146.       seg_pos, offset);
  147. SET_TRACE_LEVEL(ft_t_bug);
  148. result = zft_fetch_segment_fraction(seg_pos, buffer, 
  149.     FT_RD_SINGLE,
  150.     offset, seg_sz - offset);
  151. SET_TRACE_LEVEL(old_tracing);
  152. if (result != (seg_sz - offset)) {
  153. TRACE(ft_t_noise, "Ignore error: read_segment() result: %d",
  154.       result);
  155. memset(buffer + offset, 0, seg_sz - offset);
  156. }
  157. TRACE_EXIT 0;
  158. }
  159. /* flush the write buffer to tape and write an eof-marker at the
  160.  * current position if not in raw mode.  This function always
  161.  * positions the tape before the eof-marker.  _ftape_close() should
  162.  * then advance to the next segment.
  163.  *
  164.  * the parameter "finish_volume" describes whether to position before
  165.  * or after the possibly created file-mark. We always position after
  166.  * the file-mark when called from ftape_close() and a flush was needed
  167.  * (that is ftape_write() was the last tape operation before calling
  168.  * ftape_flush) But we always position before the file-mark when this
  169.  * function get's called from outside ftape_close() 
  170.  */
  171. int zft_flush_buffers(void)
  172. {
  173. int result;
  174. int data_remaining;
  175. int this_segs_size;
  176. TRACE_FUN(ft_t_flow);
  177. TRACE(ft_t_data_flow,
  178.       "entered, ftape_state = %d", ftape_get_status()->fti_state);
  179. if (ftape_get_status()->fti_state != writing && !need_flush) {
  180. TRACE_ABORT(0, ft_t_noise, "no need for flush");
  181. }
  182. zft_io_state = zft_idle; /*  triggers some initializations for the
  183.   *  read and write routines 
  184.   */
  185. if (last_write_failed) {
  186. ftape_abort_operation();
  187. TRACE_EXIT -EIO;
  188. }
  189. TRACE(ft_t_noise, "flushing write buffers");
  190. this_segs_size = zft_get_seg_sz(zft_pos.seg_pos);
  191. if (this_segs_size == zft_pos.seg_byte_pos) {
  192. zft_pos.seg_pos ++;
  193. data_remaining = zft_pos.seg_byte_pos = 0;
  194. } else {
  195. data_remaining = zft_pos.seg_byte_pos;
  196. }
  197. /* If there is any data not written to tape yet, append zero's
  198.  * up to the end of the sector (if using compression) or merge
  199.  * it with the data existing on the tape Then write the
  200.  * segment(s) to tape.
  201.  */
  202. TRACE(ft_t_noise, "Position:n"
  203.       KERN_INFO "seg_pos  : %dn"
  204.       KERN_INFO "byte pos : %dn"
  205.       KERN_INFO "remaining: %d",
  206.       zft_pos.seg_pos, zft_pos.seg_byte_pos, data_remaining);
  207. if (data_remaining > 0) {
  208. do {
  209. this_segs_size = zft_get_seg_sz(zft_pos.seg_pos);
  210. if (this_segs_size > data_remaining) {
  211. TRACE_CATCH(read_merge_buffer(zft_pos.seg_pos,
  212.       zft_deblock_buf,
  213.       data_remaining,
  214.       this_segs_size),
  215.     last_write_failed = 1);
  216. }
  217. result = ftape_write_segment(zft_pos.seg_pos, 
  218.      zft_deblock_buf,
  219.      FT_WR_MULTI);
  220. if (result != this_segs_size) {
  221. TRACE(ft_t_err, "flush buffers failed");
  222. zft_pos.tape_pos    -= zft_pos.seg_byte_pos;
  223. zft_pos.seg_byte_pos = 0;
  224. last_write_failed = 1;
  225. TRACE_EXIT result;
  226. }
  227. zft_written_segments ++;
  228. TRACE(ft_t_data_flow,
  229.       "flush, moved out buffer: %d", result);
  230. /* need next segment for more data (empty segments?)
  231.  */
  232. if (result < data_remaining) { 
  233. if (result > 0) {       
  234. /* move remainder to buffer beginning 
  235.  */
  236. memmove(zft_deblock_buf, 
  237. zft_deblock_buf + result,
  238. FT_SEGMENT_SIZE - result);
  239. }
  240. data_remaining -= result;
  241. zft_pos.seg_pos ++;
  242. } while (data_remaining > 0);
  243. TRACE(ft_t_any, "result: %d", result);
  244. zft_deblock_segment = --zft_pos.seg_pos;
  245. if (data_remaining == 0) {  /* first byte next segment */
  246. zft_pos.seg_byte_pos = this_segs_size;
  247. } else { /* after data previous segment, data_remaining < 0 */
  248. zft_pos.seg_byte_pos = data_remaining + result;
  249. }
  250. } else {
  251. TRACE(ft_t_noise, "zft_deblock_buf empty");
  252. zft_pos.seg_pos --;
  253. zft_pos.seg_byte_pos = zft_get_seg_sz (zft_pos.seg_pos);
  254. ftape_start_writing(FT_WR_MULTI);
  255. }
  256. TRACE(ft_t_any, "waiting");
  257. if ((result = ftape_loop_until_writes_done()) < 0) {
  258. /* that's really bad. What to to with zft_tape_pos? 
  259.  */
  260. TRACE(ft_t_err, "flush buffers failed");
  261. }
  262. TRACE(ft_t_any, "zft_seg_pos: %d, zft_seg_byte_pos: %d",
  263.       zft_pos.seg_pos, zft_pos.seg_byte_pos);
  264. last_write_failed  =
  265. need_flush = 0;
  266. TRACE_EXIT result;
  267. }
  268. /* return-value: the number of bytes removed from the user-buffer
  269.  *
  270.  * out: 
  271.  *      int *write_cnt: how much actually has been moved to the
  272.  *                      zft_deblock_buf
  273.  *      int req_len  : MUST NOT BE CHANGED, except at EOT, in 
  274.  *                      which case it may be adjusted
  275.  * in : 
  276.  *      char *buff        : the user buffer
  277.  *      int buf_pos_write : copy of buf_len_wr int
  278.  *      this_segs_size    : the size in bytes of the actual segment
  279.  *                          char
  280.  *      *zft_deblock_buf   : zft_deblock_buf
  281.  */
  282. static int zft_simple_write(int *cnt,
  283.     __u8 *dst_buf, const int seg_sz,
  284.     const __u8 *src_buf, const int req_len, 
  285.     const zft_position *pos,const zft_volinfo *volume)
  286. {
  287. int space_left;
  288. TRACE_FUN(ft_t_flow);
  289. /* volume->size holds the tape capacity while volume is open */
  290. if (pos->tape_pos + volume->blk_sz > volume->size) {
  291. TRACE_EXIT -ENOSPC;
  292. }
  293. /*  remaining space in this segment, NOT zft_deblock_buf
  294.  */
  295. space_left = seg_sz - pos->seg_byte_pos;
  296. *cnt = req_len < space_left ? req_len : space_left;
  297. #if LINUX_VERSION_CODE > KERNEL_VER(2,1,3)
  298. if (copy_from_user(dst_buf + pos->seg_byte_pos, src_buf, *cnt) != 0) {
  299. TRACE_EXIT -EFAULT;
  300. }
  301. #else
  302. TRACE_CATCH(verify_area(VERIFY_READ, src_buf, *cnt),);
  303. memcpy_fromfs(dst_buf + pos->seg_byte_pos, src_buf, *cnt);
  304. #endif
  305. TRACE_EXIT *cnt;
  306. }
  307. static int check_write_access(int req_len,
  308.       const zft_volinfo **volume,
  309.       zft_position *pos,
  310.       const unsigned int blk_sz)
  311. {
  312. int result;
  313. TRACE_FUN(ft_t_flow);
  314. if ((req_len % zft_blk_sz) != 0) {
  315. TRACE_ABORT(-EINVAL, ft_t_info,
  316.     "write-count %d must be multiple of block-size %d",
  317.     req_len, blk_sz);
  318. }
  319. if (zft_io_state == zft_writing) {
  320. /*  all other error conditions have been checked earlier
  321.  */
  322. TRACE_EXIT 0;
  323. }
  324. zft_io_state = zft_idle;
  325. TRACE_CATCH(zft_check_write_access(pos),);
  326. /*  If we haven't read the header segment yet, do it now.
  327.  *  This will verify the configuration, get the bad sector
  328.  *  table and read the volume table segment 
  329.  */
  330. if (!zft_header_read) {
  331. TRACE_CATCH(zft_read_header_segments(),);
  332. }
  333. /*  fine. Now the tape is either at BOT or at EOD,
  334.  *  Write start of volume now
  335.  */
  336. TRACE_CATCH(zft_open_volume(pos, blk_sz, zft_use_compression),);
  337. *volume = zft_find_volume(pos->seg_pos);
  338. DUMP_VOLINFO(ft_t_noise, "", *volume);
  339. zft_just_before_eof = 0;
  340. /* now merge with old data if neccessary */
  341. if (!zft_qic_mode && pos->seg_byte_pos != 0){
  342. result = zft_fetch_segment(pos->seg_pos,
  343.    zft_deblock_buf,
  344.    FT_RD_SINGLE);
  345. if (result < 0) {
  346. if (result == -EINTR || result == -ENOSPC) {
  347. TRACE_EXIT result;
  348. }
  349. TRACE(ft_t_noise, 
  350.       "ftape_read_segment() result: %d. "
  351.       "This might be normal when using "
  352.       "a newlynformatted tape", result);
  353. memset(zft_deblock_buf, '', pos->seg_byte_pos);
  354. }
  355. }
  356. zft_io_state = zft_writing;
  357. TRACE_EXIT 0;
  358. }
  359. static int fill_deblock_buf(__u8 *dst_buf, const int seg_sz,
  360.     zft_position *pos, const zft_volinfo *volume,
  361.     const char *usr_buf, const int req_len)
  362. {
  363. int cnt = 0;
  364. int result = 0;
  365. TRACE_FUN(ft_t_flow);
  366. if (seg_sz == 0) {
  367. TRACE_ABORT(0, ft_t_data_flow, "empty segment");
  368. }
  369. TRACE(ft_t_data_flow, "n"
  370.       KERN_INFO "remaining req_len: %dn"
  371.       KERN_INFO "          buf_pos: %d", 
  372.       req_len, pos->seg_byte_pos);
  373. /* zft_deblock_buf will not contain a valid segment any longer */
  374. zft_deblock_segment = -1;
  375. if (zft_use_compression) {
  376. TRACE_CATCH(zft_cmpr_lock(1 /* try to load */),);
  377. TRACE_CATCH(result= (*zft_cmpr_ops->write)(&cnt,
  378.    dst_buf, seg_sz,
  379.    usr_buf, req_len,
  380.    pos, volume),);
  381. } else {
  382. TRACE_CATCH(result= zft_simple_write(&cnt,
  383.      dst_buf, seg_sz,
  384.      usr_buf, req_len,
  385.      pos, volume),);
  386. }
  387. pos->volume_pos   += result;
  388. pos->seg_byte_pos += cnt;
  389. pos->tape_pos     += cnt;
  390. TRACE(ft_t_data_flow, "n"
  391.       KERN_INFO "removed from user-buffer : %d bytes.n"
  392.       KERN_INFO "copied to zft_deblock_buf: %d bytes.n"
  393.       KERN_INFO "zft_tape_pos             : " LL_X " bytes.",
  394.       result, cnt, LL(pos->tape_pos));
  395. TRACE_EXIT result;
  396. }
  397. /*  called by the kernel-interface routine "zft_write()"
  398.  */
  399. int _zft_write(const char* buff, int req_len)
  400. {
  401. int result = 0;
  402. int written = 0;
  403. int write_cnt;
  404. int seg_sz;
  405. static const zft_volinfo *volume = NULL;
  406. TRACE_FUN(ft_t_flow);
  407. zft_resid         = req_len;
  408. last_write_failed = 1; /* reset to 0 when successful */
  409. /* check if write is allowed 
  410.  */
  411. TRACE_CATCH(check_write_access(req_len, &volume,&zft_pos,zft_blk_sz),);
  412. while (req_len > 0) {
  413. /* Allow us to escape from this loop with a signal !
  414.  */
  415. FT_SIGNAL_EXIT(_DONT_BLOCK);
  416. seg_sz = zft_get_seg_sz(zft_pos.seg_pos);
  417. if ((write_cnt = fill_deblock_buf(zft_deblock_buf,
  418.   seg_sz,
  419.   &zft_pos,
  420.   volume,
  421.   buff,
  422.   req_len)) < 0) {
  423. zft_resid -= written;
  424. if (write_cnt == -ENOSPC) {
  425. /* leave the remainder to flush_buffers()
  426.  */
  427. TRACE(ft_t_info, "No space left on device");
  428. last_write_failed = 0;
  429. if (!need_flush) {
  430. need_flush = written > 0;
  431. }
  432. TRACE_EXIT written > 0 ? written : -ENOSPC;
  433. } else {
  434. TRACE_EXIT result;
  435. }
  436. }
  437. if (zft_pos.seg_byte_pos == seg_sz) {
  438. TRACE_CATCH(ftape_write_segment(zft_pos.seg_pos, 
  439. zft_deblock_buf,
  440. FT_WR_ASYNC),
  441.     zft_resid -= written);
  442. zft_written_segments ++;
  443. zft_pos.seg_byte_pos =  0;
  444. zft_deblock_segment  = zft_pos.seg_pos;
  445. ++zft_pos.seg_pos;
  446. }
  447. written += write_cnt;
  448. buff    += write_cnt;
  449. req_len -= write_cnt;
  450. } /* while (req_len > 0) */
  451. TRACE(ft_t_data_flow, "remaining in blocking buffer: %d",
  452.        zft_pos.seg_byte_pos);
  453. TRACE(ft_t_data_flow, "just written bytes: %d", written);
  454. last_write_failed = 0;
  455. zft_resid -= written;
  456. need_flush = need_flush || written > 0;
  457. TRACE_EXIT written;               /* bytes written */
  458. }