]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/block.c
kes15Jun02
[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    ASSERT(block->binbuf == ((uint32_t) (block->bufp - block->buf)));
263
264    /* dump_block(block, "before write"); */
265    if (dev->state & ST_WEOT) {
266       Dmsg0(90, "return write_block_to_dev with ST_WEOT\n");
267       return 0;
268    }
269    wlen = block->binbuf;
270    if (wlen <= BLKHDR_LENGTH) {       /* Does block have data in it? */
271       Dmsg0(190, "return write_block_to_dev no data to write\n");
272       return 1;
273    }
274    /* 
275     * Clear to the end of the buffer if it is not full,
276     *  and on tape devices, apply min and fixed blocking.
277     */
278    if (wlen != block->buf_len) {
279       uint32_t blen;                  /* current buffer length */
280
281       Dmsg2(200, "binbuf=%d buf_len=%d\n", block->binbuf, block->buf_len);
282       blen = wlen;
283
284       /* Adjust write size to min/max for tapes only */
285       if (dev->state & ST_TAPE) {
286          if (wlen < dev->min_block_size) {
287             wlen =  ((dev->min_block_size + TAPE_BSIZE - 1) / TAPE_BSIZE) * TAPE_BSIZE;
288          }
289          if (dev->min_block_size == dev->max_block_size) {
290             wlen = block->buf_len;    /* fixed block size already rounded */
291          }
292       }
293       if (wlen-blen > 0) {
294          memset(block->bufp, 0, wlen-blen); /* clear garbage */
295       }
296    }  
297
298    dev->block_num++;
299    block->BlockNumber = dev->block_num;
300    ser_block_header(block);
301
302    /* Limit maximum Volume size to value specified by user */
303    if ((dev->max_volume_size > 0) &&
304        ((dev->VolCatInfo.VolCatBytes + block->binbuf)) >= dev->max_volume_size) {
305       dev->state |= ST_WEOT;
306       Dmsg0(10, "==== Output bytes Triggered medium max capacity.\n");
307       Mmsg2(&dev->errmsg, _("Max. Volume capacity %" lld " exceeded on device %s.\n"),
308          dev->max_volume_size, dev->dev_name);
309       block->failed_write = TRUE;
310 /* ****FIXME**** write EOD record here */
311       weof_dev(dev, 1);               /* end the tape */
312       weof_dev(dev, 1);               /* write second eof */
313       return 0;
314    }
315
316    dev->VolCatInfo.VolCatWrites++;
317    if ((uint32_t) (stat=write(dev->fd, block->buf, wlen)) != wlen) {
318       /* We should check for errno == ENOSPC, BUT many 
319        * devices simply report EIO when it is full.
320        * with a little more thought we may be able to check
321        * capacity and distinguish real errors and EOT
322        * conditions.  In any case, we probably want to
323        * simulate an End of Medium.
324        */
325 /***FIXME**** if we wrote a partial record, back up over it */
326       dev->state |= ST_EOF | ST_EOT | ST_WEOT;
327       clrerror_dev(dev, -1);
328
329       Dmsg2(0, "=== Write error %d: ERR=%s\n", dev->dev_errno,
330          strerror(dev->dev_errno));
331
332       if (dev->dev_errno == 0) {
333          dev->dev_errno = ENOSPC;        /* out of space */
334       }
335       Mmsg2(&dev->errmsg, _("Write error on device %s. ERR=%s.\n"), 
336          dev->dev_name, strerror(dev->dev_errno));
337       block->failed_write = TRUE;
338       weof_dev(dev, 1);               /* end the tape */
339       weof_dev(dev, 1);               /* write second eof */
340       return 0;
341    }
342    dev->VolCatInfo.VolCatBytes += block->binbuf;
343    dev->VolCatInfo.VolCatBlocks++;   
344    dev->file_bytes += block->binbuf;
345
346    /* Limit maximum File size on volume to user specified value */
347    if ((dev->max_file_size > 0) &&
348        dev->file_bytes >= dev->max_file_size) {
349       weof_dev(dev, 1);               /* write eof */
350    }
351
352    Dmsg2(190, "write_block: wrote block %d bytes=%d\n", dev->block_num,
353       wlen);
354    empty_block(block);
355    return 1;
356 }
357
358 /*  
359  * Read block with locking
360  *
361  */
362 int read_block_from_device(DEVICE *dev, DEV_BLOCK *block)
363 {
364    int stat;
365    Dmsg0(90, "Enter read_block_from_device\n");
366    lock_device(dev);
367    stat = read_block_from_dev(dev, block);
368    unlock_device(dev);
369    Dmsg0(90, "Leave read_block_from_device\n");
370    return stat;
371 }
372
373 /*
374  * Read the next block into the block structure and unserialize
375  *  the block header.  For a file, the block may be partially
376  *  or completely in the current buffer.
377  */
378 int read_block_from_dev(DEVICE *dev, DEV_BLOCK *block)
379 {
380    int stat;
381
382    Dmsg0(90, "Full read() in read_block_from_device()\n");
383    if ((stat=read(dev->fd, block->buf, block->buf_len)) < 0) {
384
385 /* ***FIXME****  add code to detect buffer too small, and
386    reallocate buffer, backspace, and reread.
387    ENOMEM
388  */
389
390       Dmsg1(90, "Read device got: ERR=%s\n", strerror(errno));
391       clrerror_dev(dev, -1);
392       block->read_len = 0;
393       Mmsg2(&dev->errmsg, _("Read error on device %s. ERR=%s.\n"), 
394          dev->dev_name, strerror(dev->dev_errno));
395       return 0;
396    }
397    Dmsg1(90, "Read device got %d bytes\n", stat);
398    if (stat == 0) {             /* Got EOF ! */
399       dev->block_num = block->read_len = 0;
400       Mmsg1(&dev->errmsg, _("Read zero bytes on device %s.\n"), dev->dev_name);
401       if (dev->state & ST_EOF) { /* EOF alread read? */
402          dev->state |= ST_EOT;  /* yes, 2 EOFs => EOT */
403          return 0;
404       }
405       dev->file++;              /* increment file */
406       dev->state |= ST_EOF;     /* set EOF read */
407       return 0;                 /* return eof */
408    }
409    /* Continue here for successful read */
410    block->read_len = stat;      /* save length read */
411    if (block->read_len < BLKHDR_LENGTH) {
412       Mmsg2(&dev->errmsg, _("Very short block of %d bytes on device %s discarded.\n"), 
413          block->read_len, dev->dev_name);
414       dev->state |= ST_SHORT;   /* set short block */
415       block->read_len = block->binbuf = 0;
416       return 0;                 /* return error */
417    }  
418    if (!unser_block_header(dev, block)) {
419       return 0;
420    }
421
422    if (block->block_len > block->read_len) {
423       Mmsg2(&dev->errmsg, _("Short block of %d bytes on device %s discarded.\n"), 
424          block->read_len, dev->dev_name);
425       dev->state |= ST_SHORT;   /* set short block */
426       block->read_len = block->binbuf = 0;
427       return 0;                 /* return error */
428    }  
429
430    /* Make sure block size is not too big (temporary
431     * sanity check) and that we read the full block.
432     */
433    ASSERT(block->block_len < MAX_BLOCK_LENGTH);
434
435    dev->state &= ~(ST_EOF|ST_SHORT); /* clear EOF and short block */
436    dev->block_num++;
437
438    /*
439     * If we read a short block on disk,
440     * seek to beginning of next block. This saves us
441     * from shuffling blocks around in the buffer. Take a
442     * look at this from an efficiency stand point later, but
443     * it should only happen once at the end of each job.
444     */
445    Dmsg0(200, "At end of read block\n");
446    if (block->read_len > block->block_len && !(dev->state & ST_TAPE)) {
447
448       Dmsg3(200, "Block: %d read_len %d > %d block_len\n", dev->block_num,
449 block->read_len, block->block_len);
450       lseek(dev->fd, block->block_len-block->read_len, SEEK_CUR);   
451       Dmsg2(90, "Did lseek blk_size=%d rdlen=%d\n", block->block_len,
452             block->read_len);
453    }
454    Dmsg2(200, "Exit read_block read_len=%d block_len=%d\n",
455       block->read_len, block->block_len);
456    return 1;
457 }