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