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