]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/block.c
ea1335509cb556bc439dfa03eed6153168d22ee5
[bacula/bacula] / bacula / src / stored / block.c
1 /*
2  *
3  *   block.c -- tape block handling functions
4  *
5  *              Kern Sibbald, March MMI
6  *
7  *   Version $Id$
8  *
9  */
10 /*
11    Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
12
13    This program is free software; you can redistribute it and/or
14    modify it under the terms of the GNU General Public License as
15    published by the Free Software Foundation; either version 2 of
16    the License, or (at your option) any later version.
17
18    This program is distributed in the hope that it will be useful,
19    but WITHOUT ANY WARRANTY; without even the implied warranty of
20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21    General Public License for more details.
22
23    You should have received a copy of the GNU General Public
24    License along with this program; if not, write to the Free
25    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
26    MA 02111-1307, USA.
27
28  */
29
30
31 #include "bacula.h"
32 #include "stored.h"
33
34 extern int debug_level;
35
36 /*
37  * Dump the block header, then walk through
38  * the block printing out the record headers.
39  */
40 void dump_block(DEV_BLOCK *b, char *msg)
41 {
42    ser_declare;
43    char *p;
44    char Id[BLKHDR_ID_LENGTH+1];
45    uint32_t CheckSum, BlockCheckSum;
46    uint32_t block_len;
47    uint32_t BlockNumber;
48    uint32_t VolSessionId, VolSessionTime, data_len;
49    int32_t  FileIndex;
50    int32_t  Stream;
51
52    unser_begin(b->buf, BLKHDR_LENGTH);
53    unser_uint32(CheckSum);
54    unser_uint32(block_len);
55    unser_uint32(BlockNumber);
56    unser_bytes(Id, BLKHDR_ID_LENGTH);
57    ASSERT(unser_length(b->buf) == BLKHDR_LENGTH);
58    Id[BLKHDR_ID_LENGTH] = 0;
59
60    if (block_len > 100000) {
61       Dmsg3(20, "Dump block %s %s blocksize too big %d\n", msg, b, block_len);
62       return;
63    }
64
65    BlockCheckSum = bcrc32((uint8_t *)b->buf+BLKHDR_CS_LENGTH,
66                          block_len-BLKHDR_CS_LENGTH);
67    Dmsg6(10, "Dump block %s %x: size=%d BlkNum=%d\n\
68                Hdrcksum=%x cksum=%x\n",
69       msg, b, block_len, BlockNumber, CheckSum, BlockCheckSum);
70    p = b->buf + BLKHDR_LENGTH;
71    while (p < (b->buf + block_len+RECHDR_LENGTH)) { 
72       unser_begin(p, RECHDR_LENGTH);
73       unser_uint32(VolSessionId);
74       unser_uint32(VolSessionTime);
75       unser_int32(FileIndex);
76       unser_int32(Stream);
77       unser_uint32(data_len);
78       Dmsg6(10, "Rec: VId=%d VT=%d FI=%s Strm=%s len=%d p=%x\n",
79            VolSessionId, VolSessionTime, FI_to_ascii(FileIndex), stream_to_ascii(Stream),
80            data_len, p);
81       p += data_len + RECHDR_LENGTH;
82   }
83
84 }
85     
86 /*
87  * Create a new block structure.                           
88  * We pass device so that the block can inherit the
89  * min and max block sizes.
90  */
91 DEV_BLOCK *new_block(DEVICE *dev)
92 {
93    DEV_BLOCK *block = (DEV_BLOCK *)get_memory(sizeof(DEV_BLOCK));
94
95    memset(block, 0, sizeof(DEV_BLOCK));
96
97    if (dev->max_block_size == 0) {
98       block->buf_len = DEFAULT_BLOCK_SIZE;
99    } else {
100       block->buf_len = dev->max_block_size;
101    }
102    if (block->buf_len % TAPE_BSIZE != 0) {
103       Mmsg2(&dev->errmsg, _("Block size %d forced to be multiple of %d\n"), 
104          block->buf_len, TAPE_BSIZE);
105       Emsg0(M_WARNING, 0, dev->errmsg);
106       block->buf_len = ((block->buf_len + TAPE_BSIZE - 1) / TAPE_BSIZE) * TAPE_BSIZE;
107    }
108    block->block_len = block->buf_len;  /* default block size */
109    block->buf = get_memory(block->buf_len); 
110    if (block->buf == NULL) {
111       Mmsg0(&dev->errmsg, _("Unable to malloc block buffer.\n"));
112       Emsg0(M_FATAL, 0, dev->errmsg);
113       return NULL;
114    }
115    empty_block(block);
116    Dmsg1(90, "Returning new block=%x\n", block);
117    return block;
118 }
119
120 /*
121  * Free block 
122  */
123 void free_block(DEV_BLOCK *block)
124 {
125    Dmsg1(199, "free_block buffer %x\n", block->buf);
126    free_memory(block->buf);
127    Dmsg1(199, "free_block block %x\n", block);
128    free_memory((POOLMEM *)block);
129 }
130
131 /* Empty the block -- for writing */
132 void empty_block(DEV_BLOCK *block)
133 {
134    block->binbuf = BLKHDR_LENGTH;
135    block->bufp = block->buf + block->binbuf;
136    block->read_len = 0;
137    block->failed_write = FALSE;
138 }
139
140 /*
141  * Create block header just before write. The space
142  * in the buffer should have already been reserved by
143  * init_block.
144  */
145 static void ser_block_header(DEV_BLOCK *block)
146 {
147    ser_declare;
148    uint32_t CheckSum = 0;
149    uint32_t block_len = block->binbuf;
150    
151    Dmsg1(190, "ser_block_header: block_len=%d\n", block_len);
152    ser_begin(block->buf, BLKHDR_LENGTH);
153    ser_uint32(CheckSum);
154    ser_uint32(block_len);
155    ser_uint32(block->BlockNumber);
156    ser_bytes(BLKHDR_ID, BLKHDR_ID_LENGTH);
157    ASSERT(ser_length(block->buf) == BLKHDR_LENGTH);
158
159    /* Checksum whole block except for the checksum */
160    CheckSum = bcrc32((uint8_t *)block->buf+BLKHDR_CS_LENGTH, 
161                  block_len-BLKHDR_CS_LENGTH);
162    Dmsg1(190, "ser_bloc_header: checksum=%x\n", CheckSum);
163    ser_begin(block->buf, BLKHDR_LENGTH);
164    ser_uint32(CheckSum);
165 }
166
167 /*
168  * Unserialized the block header for reading block.
169  *  This includes setting all the buffer pointers correctly.
170  *
171  *  Returns: 0 on failure (not a block)
172  *           1 on success
173  */
174 static int unser_block_header(DEVICE *dev, DEV_BLOCK *block)
175 {
176    ser_declare;
177    char Id[BLKHDR_ID_LENGTH+1];
178    uint32_t CheckSum, BlockCheckSum;
179    uint32_t block_len;
180    uint32_t EndBlock;
181    uint32_t BlockNumber;
182
183    unser_begin(block->buf, BLKHDR_LENGTH);
184    unser_uint32(CheckSum);
185    unser_uint32(block_len);
186    unser_uint32(BlockNumber);
187    unser_bytes(Id, BLKHDR_ID_LENGTH);
188    ASSERT(unser_length(block->buf) == BLKHDR_LENGTH);
189
190    Id[BLKHDR_ID_LENGTH] = 0;
191    block->bufp = block->buf + BLKHDR_LENGTH;
192    if (strncmp(Id, BLKHDR_ID, BLKHDR_ID_LENGTH) != 0) {
193       Mmsg2(&dev->errmsg, _("Buffer ID error. Wanted: %s, got %s. Buffer discarded.\n"),
194          BLKHDR_ID, Id);
195       Emsg0(M_ERROR, 0, dev->errmsg);
196       return 0;
197    }
198
199    ASSERT(block_len < MAX_BLOCK_LENGTH);    /* temp sanity check */
200
201    Dmsg1(190, "unser_block_header block_len=%d\n", block_len);
202    /* Find end of block or end of buffer whichever is smaller */
203    if (block_len > block->read_len) {
204       EndBlock = block->read_len;
205    } else {
206       EndBlock = block_len;
207    }
208    block->binbuf = EndBlock - BLKHDR_LENGTH;
209    block->block_len = block_len;
210    block->BlockNumber = BlockNumber;
211    Dmsg3(190, "Read binbuf = %d %d block_len=%d\n", block->binbuf,
212       BLKHDR_LENGTH, block_len);
213    if (block_len > block->buf_len) {
214       Mmsg2(&dev->errmsg,  _("Block length %d is greater than buffer %d\n"),
215          block_len, block->buf_len);
216       Emsg0(M_ERROR, 0, dev->errmsg);
217       return 0;
218    }
219    if (block_len <= block->read_len) {
220       BlockCheckSum = bcrc32((uint8_t *)block->buf+BLKHDR_CS_LENGTH,
221                          block_len-BLKHDR_CS_LENGTH);
222       if (BlockCheckSum != CheckSum) {
223          Dmsg2(00, "Block checksum mismatch: calc=%x blk=%x\n", BlockCheckSum,
224             CheckSum);
225          Mmsg2(&dev->errmsg, _("Block checksum mismatch: calc=%x blk=%x\n"), BlockCheckSum,
226             CheckSum);
227          return 0;
228       }
229    }
230    return 1;
231 }
232
233 /*  
234  * Write a block to the device, with locking and unlocking
235  *
236  * Returns: 1 on success
237  *        : 0 on failure
238  *
239  */
240 int write_block_to_device(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
241 {
242    int stat = 1;
243    lock_device(dev);
244    if (!write_block_to_dev(dev, block)) {
245        stat = fixup_device_block_write_error(jcr, dev, block);
246    }
247    unlock_device(dev);
248    return stat;
249 }
250
251 /*
252  * Write a block to the device 
253  *
254  *  Returns: 1 on success or EOT
255  *           0 on hard error
256  */
257 int write_block_to_dev(DEVICE *dev, DEV_BLOCK *block)
258 {
259    int stat = 0;
260    uint32_t wlen;                     /* length to write */
261
262 #ifdef NO_TAPE_WRITE_TEST
263    empty_block(block);
264    return 1;
265 #endif
266    ASSERT(block->binbuf == ((uint32_t) (block->bufp - block->buf)));
267
268    /* dump_block(block, "before write"); */
269    if (dev->state & ST_WEOT) {
270       Dmsg0(90, "return write_block_to_dev with ST_WEOT\n");
271       return 0;
272    }
273    wlen = block->binbuf;
274    if (wlen <= BLKHDR_LENGTH) {       /* Does block have data in it? */
275       Dmsg0(190, "return write_block_to_dev no data to write\n");
276       return 1;
277    }
278    /* 
279     * Clear to the end of the buffer if it is not full,
280     *  and on tape devices, apply min and fixed blocking.
281     */
282    if (wlen != block->buf_len) {
283       uint32_t blen;                  /* current buffer length */
284
285       Dmsg2(200, "binbuf=%d buf_len=%d\n", block->binbuf, block->buf_len);
286       blen = wlen;
287
288       /* Adjust write size to min/max for tapes only */
289       if (dev->state & ST_TAPE) {
290          if (wlen < dev->min_block_size) {
291             wlen =  ((dev->min_block_size + TAPE_BSIZE - 1) / TAPE_BSIZE) * TAPE_BSIZE;
292          }
293          if (dev->min_block_size == dev->max_block_size) {
294             wlen = block->buf_len;    /* fixed block size already rounded */
295          }
296       }
297       if (wlen-blen > 0) {
298          memset(block->bufp, 0, wlen-blen); /* clear garbage */
299       }
300    }  
301
302    dev->block_num++;
303    block->BlockNumber = dev->block_num;
304    ser_block_header(block);
305
306    /* Limit maximum Volume size to value specified by user */
307    if ((dev->max_volume_size > 0) &&
308        ((dev->VolCatInfo.VolCatBytes + block->binbuf)) >= dev->max_volume_size) {
309       dev->state |= ST_WEOT;
310       Dmsg0(10, "==== Output bytes Triggered medium max capacity.\n");
311       Mmsg2(&dev->errmsg, _("Max. Volume capacity %" lld " exceeded on device %s.\n"),
312          dev->max_volume_size, dev->dev_name);
313       block->failed_write = TRUE;
314 /* ****FIXME**** write EOD record here */
315       weof_dev(dev, 1);               /* end the tape */
316       weof_dev(dev, 1);               /* write second eof */
317       return 0;
318    }
319
320    dev->VolCatInfo.VolCatWrites++;
321    if ((uint32_t) (stat=write(dev->fd, block->buf, wlen)) != wlen) {
322       /* We should check for errno == ENOSPC, BUT many 
323        * devices simply report EIO when it is full.
324        * with a little more thought we may be able to check
325        * capacity and distinguish real errors and EOT
326        * conditions.  In any case, we probably want to
327        * simulate an End of Medium.
328        */
329 /***FIXME**** if we wrote a partial record, back up over it */
330       dev->state |= ST_EOF | ST_EOT | ST_WEOT;
331       clrerror_dev(dev, -1);
332
333       if (dev->dev_errno == 0) {
334          dev->dev_errno = ENOSPC;        /* out of space */
335       }
336
337       Dmsg2(0, "=== Write error errno=%d: ERR=%s\n", dev->dev_errno,
338          strerror(dev->dev_errno));
339
340       Mmsg2(&dev->errmsg, _("Write error on device %s. ERR=%s.\n"), 
341          dev->dev_name, strerror(dev->dev_errno));
342       block->failed_write = TRUE;
343       weof_dev(dev, 1);               /* end the tape */
344       weof_dev(dev, 1);               /* write second eof */
345       return 0;
346    }
347    dev->VolCatInfo.VolCatBytes += block->binbuf;
348    dev->VolCatInfo.VolCatBlocks++;   
349    dev->file_bytes += block->binbuf;
350
351    /* Limit maximum File size on volume to user specified value */
352    if ((dev->max_file_size > 0) &&
353        dev->file_bytes >= dev->max_file_size) {
354       weof_dev(dev, 1);               /* write eof */
355    }
356
357    Dmsg2(190, "write_block: wrote block %d bytes=%d\n", dev->block_num,
358       wlen);
359    empty_block(block);
360    return 1;
361 }
362
363 /*  
364  * Read block with locking
365  *
366  */
367 int read_block_from_device(DEVICE *dev, DEV_BLOCK *block)
368 {
369    int stat;
370    Dmsg0(90, "Enter read_block_from_device\n");
371    new_lock_device(dev);
372    lock_device(dev);
373    stat = read_block_from_dev(dev, block);
374    new_unlock_device(dev);
375    unlock_device(dev);
376    Dmsg0(90, "Leave read_block_from_device\n");
377    return stat;
378 }
379
380 /*
381  * Read the next block into the block structure and unserialize
382  *  the block header.  For a file, the block may be partially
383  *  or completely in the current buffer.
384  */
385 int read_block_from_dev(DEVICE *dev, DEV_BLOCK *block)
386 {
387    int stat;
388
389    Dmsg0(90, "Full read() in read_block_from_device()\n");
390    if ((stat=read(dev->fd, block->buf, block->buf_len)) < 0) {
391
392 /* ***FIXME****  add code to detect buffer too small, and
393    reallocate buffer, backspace, and reread.
394    ENOMEM
395  */
396
397       Dmsg1(90, "Read device got: ERR=%s\n", strerror(errno));
398       clrerror_dev(dev, -1);
399       block->read_len = 0;
400       Mmsg2(&dev->errmsg, _("Read error on device %s. ERR=%s.\n"), 
401          dev->dev_name, strerror(dev->dev_errno));
402       return 0;
403    }
404    Dmsg1(90, "Read device got %d bytes\n", stat);
405    if (stat == 0) {             /* Got EOF ! */
406       dev->block_num = block->read_len = 0;
407       Mmsg1(&dev->errmsg, _("Read zero bytes on device %s.\n"), dev->dev_name);
408       if (dev->state & ST_EOF) { /* EOF alread read? */
409          dev->state |= ST_EOT;  /* yes, 2 EOFs => EOT */
410          return 0;
411       }
412       dev->file++;              /* increment file */
413       dev->state |= ST_EOF;     /* set EOF read */
414       return 0;                 /* return eof */
415    }
416    /* Continue here for successful read */
417    block->read_len = stat;      /* save length read */
418    if (block->read_len < BLKHDR_LENGTH) {
419       Mmsg2(&dev->errmsg, _("Very short block of %d bytes on device %s discarded.\n"), 
420          block->read_len, dev->dev_name);
421       dev->state |= ST_SHORT;   /* set short block */
422       block->read_len = block->binbuf = 0;
423       return 0;                 /* return error */
424    }  
425    if (!unser_block_header(dev, block)) {
426       return 0;
427    }
428
429    if (block->block_len > block->read_len) {
430       Mmsg2(&dev->errmsg, _("Short block of %d bytes on device %s discarded.\n"), 
431          block->read_len, dev->dev_name);
432       dev->state |= ST_SHORT;   /* set short block */
433       block->read_len = block->binbuf = 0;
434       return 0;                 /* return error */
435    }  
436
437    /* Make sure block size is not too big (temporary
438     * sanity check) and that we read the full block.
439     */
440    ASSERT(block->block_len < MAX_BLOCK_LENGTH);
441
442    dev->state &= ~(ST_EOF|ST_SHORT); /* clear EOF and short block */
443    dev->block_num++;
444
445    /*
446     * If we read a short block on disk,
447     * seek to beginning of next block. This saves us
448     * from shuffling blocks around in the buffer. Take a
449     * look at this from an efficiency stand point later, but
450     * it should only happen once at the end of each job.
451     */
452    Dmsg0(200, "At end of read block\n");
453    if (block->read_len > block->block_len && !(dev->state & ST_TAPE)) {
454
455       Dmsg3(200, "Block: %d read_len %d > %d block_len\n", dev->block_num,
456 block->read_len, block->block_len);
457       lseek(dev->fd, block->block_len-block->read_len, SEEK_CUR);   
458       Dmsg2(90, "Did lseek blk_size=%d rdlen=%d\n", block->block_len,
459             block->read_len);
460    }
461    Dmsg2(200, "Exit read_block read_len=%d block_len=%d\n",
462       block->read_len, block->block_len);
463    return 1;
464 }