Annotation of tme/host/posix/posix-disk.c, revision 1.1.1.2

1.1.1.2 ! root        1: /* $Id: posix-disk.c,v 1.4 2005/02/17 12:42:20 fredette Exp $ */
1.1       root        2: 
                      3: /* host/posix/posix-disk.c - implementation of disks on a POSIX system: */
                      4: 
                      5: /*
                      6:  * Copyright (c) 2003 Matt Fredette
                      7:  * All rights reserved.
                      8:  *
                      9:  * Redistribution and use in source and binary forms, with or without
                     10:  * modification, are permitted provided that the following conditions
                     11:  * are met:
                     12:  * 1. Redistributions of source code must retain the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer.
                     14:  * 2. Redistributions in binary form must reproduce the above copyright
                     15:  *    notice, this list of conditions and the following disclaimer in the
                     16:  *    documentation and/or other materials provided with the distribution.
                     17:  * 3. All advertising materials mentioning features or use of this software
                     18:  *    must display the following acknowledgement:
                     19:  *      This product includes software developed by Matt Fredette.
                     20:  * 4. The name of the author may not be used to endorse or promote products
                     21:  *    derived from this software without specific prior written permission.
                     22:  *
                     23:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     24:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
                     25:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
                     26:  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
                     27:  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
                     28:  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
                     29:  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     30:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
                     31:  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
                     32:  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     33:  * POSSIBILITY OF SUCH DAMAGE.
                     34:  */
                     35: 
                     36: #include <tme/common.h>
1.1.1.2 ! root       37: _TME_RCSID("$Id: posix-disk.c,v 1.4 2005/02/17 12:42:20 fredette Exp $");
1.1       root       38: 
                     39: /* includes: */
                     40: #include <tme/generic/disk.h>
                     41: #include <tme/generic/bus.h>
                     42: #include <fcntl.h>
                     43: #include <stdlib.h>
                     44: #include <strings.h>
                     45: #include <sys/stat.h>
                     46: #include <sys/uio.h>
                     47: #ifdef HAVE_MMAP
                     48: #include <sys/types.h>
                     49: #include <sys/mman.h>
                     50: #endif /* HAVE_MMAP */
                     51: #ifdef HAVE_STDARG_H
                     52: #include <stdarg.h>
                     53: #else  /* HAVE_STDARG_H */
                     54: #include <varargs.h>
                     55: #endif /* HAVE_STDARG_H */
                     56: 
                     57: /* macros: */
                     58: 
                     59: /* the maximum block size: */
                     60: #define TME_POSIX_DISK_BLOCK_SIZE_MAX  (16384)
                     61: 
                     62: /* disk flags: */
                     63: #define TME_POSIX_DISK_FLAG_RO         TME_BIT(0)
                     64: 
                     65: /* buffer flags: */
                     66: #define TME_POSIX_DISK_BUFFER_READABLE TME_BIT(0)
                     67: #define TME_POSIX_DISK_BUFFER_DIRTY    TME_BIT(1)
                     68: #define TME_POSIX_DISK_BUFFER_MMAPPED  TME_BIT(2)
                     69: 
                     70: /* default buffer parameters: */
                     71: #define TME_POSIX_DISK_BUFFER_DEFAULT_COUNT    (16)
                     72: #define TME_POSIX_DISK_BUFFER_DEFAULT_AGG_PRE  (128UL * 1024UL)
                     73: #define TME_POSIX_DISK_BUFFER_DEFAULT_AGG_POST (1UL * 1024UL * 1024UL)
                     74: 
                     75: /* types: */
                     76: 
                     77: /* a posix disk buffer: */
                     78: struct tme_posix_disk_buffer {
                     79: 
                     80:   /* buffers are kept on a doubly linked list: */
                     81:   struct tme_posix_disk_buffer *tme_posix_disk_buffer_next;
                     82:   struct tme_posix_disk_buffer **tme_posix_disk_buffer_prev;
                     83: 
                     84:   /* buffer flags: */
                     85:   int tme_posix_disk_buffer_flags;
                     86: 
                     87:   /* the file position, size, and data of this buffer.  a size of zero
                     88:      means this buffer is free: */
                     89: 
                     90:   /* we're paranoid about autoconf's ability to actually determine if
                     91:      off_t and size_t are available, and it's possible that a system
                     92:      that predates off_t and size_t may use other types to achieve
                     93:      large file support anyways, that autoconf's default off_t = long
                     94:      and size_t = unsigned definitions may not match.  the bizarre
                     95:      solution is to declare structs with appropriately-typed members,
                     96:      and then use those members: */
                     97:   struct stat _tme_posix_disk_buffer_stat;
                     98:   struct iovec _tme_posix_disk_buffer_iov;
                     99: #define tme_posix_disk_buffer_pos _tme_posix_disk_buffer_stat.st_size
                    100: #define tme_posix_disk_buffer_size _tme_posix_disk_buffer_iov.iov_len
                    101: #define tme_posix_disk_buffer_data _tme_posix_disk_buffer_iov.iov_base
                    102: };
                    103: 
                    104: /* a posix disk: */
                    105: struct tme_posix_disk {
                    106: 
                    107:   /* backpointer to our element: */
                    108:   struct tme_element *tme_posix_disk_element;
                    109: 
                    110:   /* our mutex: */
                    111:   tme_mutex_t tme_posix_disk_mutex;
                    112: 
                    113:   /* our flags: */
                    114:   int tme_posix_disk_flags;
                    115: 
                    116:   /* the file descriptor: */
                    117:   int tme_posix_disk_fd;
                    118: 
                    119:   /* the stat buffer: */
                    120:   struct stat tme_posix_disk_stat;
                    121: 
                    122:   /* our connection: */
                    123:   struct tme_disk_connection *tme_posix_disk_connection;
                    124: 
                    125:   /* our disk buffers.  the most-recently-used buffer
                    126:      is at the front of the list: */
                    127:   struct tme_posix_disk_buffer *tme_posix_disk_buffers;
                    128: 
                    129:   /* how much we aggregate behind and ahead when we will
                    130:      a new buffer: */
                    131:   struct stat _tme_posix_disk_stat0;
                    132:   struct stat _tme_posix_disk_stat1;
                    133: #define tme_posix_disk_buffer_agg_pre _tme_posix_disk_stat0.st_size
                    134: #define tme_posix_disk_buffer_agg_post _tme_posix_disk_stat1.st_size
                    135: };
                    136: 
                    137: /* this gets a buffer: */
                    138: static int
                    139: _tme_posix_disk_buffer_get(struct tme_posix_disk *posix_disk,
                    140:                           const union tme_value64 *_pos,
                    141:                           unsigned long _size,
                    142:                           int readable,
                    143:                           tme_uint8_t **_buffer)
                    144: {
                    145:   struct stat statbufs[3];
                    146: #define pos_least statbufs[0].st_size
                    147: #define pos_most statbufs[1].st_size
                    148: #define pos_last statbufs[2].st_size
                    149:   struct iovec iovecs[3];
                    150: #define data iovecs[0].iov_base
                    151: #define size iovecs[0].iov_len
                    152: #define size_agg iovecs[1].iov_len
                    153: #define ssize iovecs[2].iov_len
                    154:   unsigned long agg_pre, agg_post;
                    155:   struct tme_posix_disk_buffer *buffer;
                    156:   struct tme_posix_disk_buffer *buffer_free_nosize;
                    157:   struct tme_posix_disk_buffer *buffer_free_sized;
                    158:   int have_least, have_most;
                    159:   int rc;
                    160: 
                    161:   /* form the size, and least and most positions: */
                    162:   size = _size;
                    163:   assert (size > 0);
                    164: #ifdef TME_HAVE_INT64_T
                    165:   pos_least = _pos->tme_value64_int;
                    166: #else  /* !TME_HAVE_INT64_T */
                    167:   pos_least = _pos->tme_value64_int32_hi;
                    168:   pos_least
                    169:     = ((pos_least << 32)
                    170:        | _pos->tme_value64_int32_lo);
                    171: #endif /* !TME_HAVE_INT64_T */
                    172:   pos_most = (pos_least + size) - 1;
                    173: 
                    174:   /* if we have to fill a new buffer, decide from where and how much
                    175:      we are going to fill: */
                    176:   agg_pre
                    177:     = TME_MIN(pos_least,
                    178:              posix_disk->tme_posix_disk_buffer_agg_pre);
                    179:   agg_pre
                    180:     += ((pos_least - agg_pre)
                    181:        & (posix_disk->tme_posix_disk_stat.st_blksize - 1));
                    182:   agg_post
                    183:     = posix_disk->tme_posix_disk_buffer_agg_post;
                    184:   size_agg
                    185:     = (((agg_pre + size) + agg_post
                    186:        + (posix_disk->tme_posix_disk_stat.st_blksize - 1))
                    187:        & ~(posix_disk->tme_posix_disk_stat.st_blksize - 1));
                    188:   agg_post = (size_agg - (agg_pre + size));
                    189: 
                    190:   /* start with no best free buffers: */
                    191:   buffer_free_nosize = NULL;
                    192:   buffer_free_sized = NULL;
                    193: 
                    194:   /* walk all of the buffers: */
                    195:   for (buffer = posix_disk->tme_posix_disk_buffers;
                    196:        buffer != NULL; ) {
                    197: 
                    198:     /* a buffer with no size is free: */
                    199:     if (buffer->tme_posix_disk_buffer_size == 0) {
                    200:       
                    201:       /* remember this nosize free buffer and continue: */
                    202:       buffer_free_nosize = buffer;
                    203:       buffer = buffer->tme_posix_disk_buffer_next;
                    204:       continue;
                    205:     }
                    206: 
                    207:     /* a buffer with some size, but no flags, is also free: */
                    208:     else if (buffer->tme_posix_disk_buffer_flags == 0) {
                    209: 
                    210:       /* take this buffer as our best sized free buffer, */
                    211: 
                    212:       /* if we have no best sized free buffer yet: */
                    213:       if (buffer_free_sized == NULL
                    214: 
                    215:          || ((buffer->tme_posix_disk_buffer_size
                    216:               >= buffer_free_sized->tme_posix_disk_buffer_size)
                    217: 
                    218:              /* if this buffer is bigger than our best sized free
                    219:                 buffer, and the best sized free buffer is smaller
                    220:                 than the new-fill aggregate buffer size: */
                    221:              ? (buffer_free_sized->tme_posix_disk_buffer_size
                    222:                 < size_agg)
                    223: 
                    224:              /* if this buffer is smaller than our best sized
                    225:                 free buffer, but it is still at least as big as
                    226:                 the new-fill aggregate buffer size: */
                    227:              : (buffer->tme_posix_disk_buffer_size
                    228:                 >= size_agg))) {
                    229:        buffer_free_sized = buffer;
                    230:       }
                    231: 
                    232:       /* continue: */
                    233:       buffer = buffer->tme_posix_disk_buffer_next;
                    234:       continue;
                    235:     }
                    236: 
                    237:     /* calculate the last position in this buffer: */
                    238:     pos_last = ((buffer->tme_posix_disk_buffer_pos
                    239:                 + buffer->tme_posix_disk_buffer_size)
                    240:                - 1);
                    241: 
                    242:     /* see if this buffer contains the least position we want: */
                    243:     have_least
                    244:       = (buffer->tme_posix_disk_buffer_pos <= pos_least
                    245:         && pos_least <= pos_last);
                    246: 
                    247:     /* see if this buffer contains the most position we want: */
                    248:     have_most
                    249:       = (buffer->tme_posix_disk_buffer_pos <= pos_most
                    250:         && pos_most <= pos_last);
                    251: 
                    252:     /* if this buffer covers all of the positions we want, and
                    253:        is readable or we don't need a readable buffer, stop: */
                    254:     if (have_least
                    255:        && have_most
                    256:        && ((buffer->tme_posix_disk_buffer_flags
                    257:             & TME_POSIX_DISK_BUFFER_READABLE)
                    258:            || !readable)) {
                    259:       break;
                    260:     }
                    261:     
                    262:     /* otherwise, if this buffer covers any of the positions we want,
                    263:        or if this is the last buffer on the list and we don't have any
                    264:        best free buffer, we need to free this buffer: */
                    265:     else if (have_least
                    266:             || have_most
                    267:             || (buffer->tme_posix_disk_buffer_next == NULL
                    268:                 && buffer_free_nosize == NULL
                    269:                 && buffer_free_sized == NULL)) {
                    270: 
                    271: #ifdef HAVE_MMAP
                    272:       /* if this buffer is mmapped: */
                    273:       if (buffer->tme_posix_disk_buffer_flags 
                    274:          & TME_POSIX_DISK_BUFFER_MMAPPED) {
                    275:        
                    276:        /* munmap the buffer: */
                    277:        rc = munmap(buffer->tme_posix_disk_buffer_data,
                    278:                    buffer->tme_posix_disk_buffer_size);
                    279:        assert (rc == 0);
                    280:        
                    281:        /* free this buffer: */
                    282:        buffer->tme_posix_disk_buffer_size = 0;
                    283:       }
                    284:       
                    285:       else
                    286: #endif /* HAVE_MMAP */
                    287:        {
                    288: 
                    289:          /* if this buffer is dirty, we need to write it out: */
                    290:          if (buffer->tme_posix_disk_buffer_flags 
                    291:              & TME_POSIX_DISK_BUFFER_DIRTY) {
                    292:            
                    293:            /* seek to the buffer's position: */
                    294:            rc = (lseek(posix_disk->tme_posix_disk_fd,
                    295:                        buffer->tme_posix_disk_buffer_pos,
                    296:                        SEEK_SET) < 0);
                    297:            assert (rc == 0);
                    298:            
                    299:            /* write out the buffer: */
                    300:            ssize = write(posix_disk->tme_posix_disk_fd,
                    301:                          buffer->tme_posix_disk_buffer_data,
                    302:                          buffer->tme_posix_disk_buffer_size);
                    303:            assert (ssize == buffer->tme_posix_disk_buffer_size);
                    304:          }
                    305: 
                    306:          /* free this buffer: */
                    307:          buffer->tme_posix_disk_buffer_flags = 0;
                    308:        }
                    309:       
                    310:       /* continue without updating buffer, so that this now-free
                    311:         buffer is revisited, to possibly become a best free buffer: */
                    312:     }
                    313: 
                    314:     /* otherwise, this is a non-free buffer that doesn't
                    315:        cover any of the positions we want.  just continue: */
                    316:     else {
                    317:       buffer = buffer->tme_posix_disk_buffer_next;
                    318:     }
                    319:   }
                    320: 
                    321:   /* if we didn't find an applicable buffer: */
                    322:   if (buffer == NULL) {
                    323:     
                    324:     /* we must have some free buffer: */
                    325:     assert (buffer_free_nosize != NULL
                    326:            || buffer_free_sized != NULL);
                    327: 
                    328: #ifdef HAVE_MMAP
                    329: 
                    330:     /* try to mmap this region.  if the map fails with more read-ahead
                    331:        than is needed to meet the block size, try the map one more
                    332:        time with just that needed read-ahead: */
                    333:     data = mmap(NULL,
                    334:                size_agg,
                    335:                PROT_READ
                    336:                | ((posix_disk->tme_posix_disk_flags
                    337:                    & TME_POSIX_DISK_FLAG_RO)
                    338:                   ? 0
                    339:                   : PROT_WRITE),
                    340:                MAP_SHARED,
                    341:                posix_disk->tme_posix_disk_fd,
                    342:                (pos_least
                    343:                 - agg_pre));
                    344:     if (data == MAP_FAILED) {
                    345:       size_agg
                    346:        = (((agg_pre + size)
                    347:            + (posix_disk->tme_posix_disk_stat.st_blksize - 1))
                    348:           & ~(posix_disk->tme_posix_disk_stat.st_blksize - 1));
                    349:       data = mmap(NULL,
                    350:                  size_agg,
                    351:                  PROT_READ
                    352:                  | ((posix_disk->tme_posix_disk_flags
                    353:                      & TME_POSIX_DISK_FLAG_RO)
                    354:                     ? 0
                    355:                     : PROT_WRITE),
                    356:                  MAP_SHARED,
                    357:                  posix_disk->tme_posix_disk_fd,
                    358:                  (pos_least
                    359:                   - agg_pre));
                    360:       if (data == MAP_FAILED) {
                    361:        size_agg = (agg_pre + size) + agg_post;
                    362:       }
                    363:       else {
                    364:        agg_post = size_agg - (agg_pre + size);
                    365:       }
                    366:     }
                    367: 
                    368:     /* if we were able to mmap this region: */
                    369:     if (data != MAP_FAILED) {
                    370: 
                    371:       /* if we have a free nosize buffer, reuse it, else free the
                    372:         free sized buffer's data and reuse that: */
                    373:       if (buffer_free_nosize != NULL) {
                    374:        buffer = buffer_free_nosize;
                    375:       }
                    376:       else {
                    377:        tme_free(buffer_free_sized->tme_posix_disk_buffer_data);
                    378:        buffer = buffer_free_sized;
                    379:       }
                    380: 
                    381:       /* do the mmapped-specific initialization of this buffer: */
                    382:       buffer->tme_posix_disk_buffer_flags
                    383:        = (TME_POSIX_DISK_BUFFER_READABLE
                    384:           | TME_POSIX_DISK_BUFFER_MMAPPED);
                    385:     }
                    386: 
                    387:     /* otherwise, we were unable to map this region: */
                    388:     else
                    389: #endif /* HAVE_MMAP */
                    390:       {
                    391: 
                    392:        /* if we have a free sized buffer, resize it, else malloc 
                    393:           data for the free nosize buffer: */
                    394:        if (buffer_free_sized != NULL) {
                    395:          data = buffer_free_sized->tme_posix_disk_buffer_data;
                    396:          if (buffer_free_sized->tme_posix_disk_buffer_size
                    397:              != size_agg) {
                    398:            data = tme_realloc(data, size_agg);
                    399:          }
                    400:          buffer = buffer_free_sized;
                    401:        }
                    402:        else {
                    403:          data = tme_malloc(size_agg);
                    404:          buffer = buffer_free_nosize;
                    405:        }
                    406: 
                    407:        /* do the malloced-specific initialization of this buffer: */
                    408:        buffer->tme_posix_disk_buffer_flags = 0;
                    409:        if (readable) {
                    410:          buffer->tme_posix_disk_buffer_flags
                    411:            = TME_POSIX_DISK_BUFFER_READABLE;
                    412: 
                    413:          /* seek to the buffer's position: */
                    414:          rc = (lseek(posix_disk->tme_posix_disk_fd,
                    415:                      (pos_least
                    416:                       - agg_pre),
                    417:                      SEEK_SET) < 0);
                    418:          assert (rc == 0);
                    419:          
                    420:          /* read in the buffer.  if the read fails with more
                    421:             read-ahead than is needed to meet the block size, try the
                    422:             read one more time with just that needed read-ahead: */
                    423:          for (;;) {
                    424:            ssize = read(posix_disk->tme_posix_disk_fd,
                    425:                         data,
                    426:                         size_agg);
                    427:            if (ssize == size_agg) {
                    428:              break;
                    429:            }
                    430:            size_agg
                    431:              = (((agg_pre + size)
                    432:                  + (posix_disk->tme_posix_disk_stat.st_blksize - 1))
                    433:                 & ~(posix_disk->tme_posix_disk_stat.st_blksize - 1));
                    434:            assert (agg_post > (size_agg - (agg_pre + size)));
                    435:            agg_post = (size_agg - (agg_pre + size));
                    436:          }
                    437:        }
                    438:       }
                    439: 
                    440:     /* do the common initialization of this buffer: */
                    441:     buffer->tme_posix_disk_buffer_pos
                    442:       = (pos_least
                    443:         - agg_pre);
                    444:     buffer->tme_posix_disk_buffer_size
                    445:       = size_agg;
                    446:     buffer->tme_posix_disk_buffer_data
                    447:       = data;
                    448:   }
                    449: 
                    450:   /* if this buffer doesn't need to be readable, that means that it's
                    451:      being written to, so mark it dirty: */
                    452:   if (!readable) {
                    453:     buffer->tme_posix_disk_buffer_flags
                    454:       |= TME_POSIX_DISK_BUFFER_DIRTY;
                    455:   }
                    456: 
                    457:   /* remove this buffer from the list: */
                    458:   *buffer->tme_posix_disk_buffer_prev
                    459:     = buffer->tme_posix_disk_buffer_next;
                    460:   if (buffer->tme_posix_disk_buffer_next != NULL) {
                    461:     buffer->tme_posix_disk_buffer_next->tme_posix_disk_buffer_prev
                    462:       = buffer->tme_posix_disk_buffer_prev;
                    463:   }
                    464: 
                    465:   /* add this buffer to the front of the list: */
                    466:   buffer->tme_posix_disk_buffer_prev
                    467:     = &posix_disk->tme_posix_disk_buffers;
                    468:   buffer->tme_posix_disk_buffer_next
                    469:     = posix_disk->tme_posix_disk_buffers;
                    470:   if (buffer->tme_posix_disk_buffer_next != NULL) {
                    471:     buffer->tme_posix_disk_buffer_next->tme_posix_disk_buffer_prev
                    472:       = &buffer->tme_posix_disk_buffer_next;
                    473:   }
                    474:   *buffer->tme_posix_disk_buffer_prev
                    475:     = buffer;
                    476: 
                    477:   /* return the desired pointer into the buffer: */
                    478:   *_buffer
                    479:     = (buffer->tme_posix_disk_buffer_data
                    480:        + (pos_least
                    481:          - buffer->tme_posix_disk_buffer_pos));
                    482: 
                    483:   return (TME_OK);
                    484: #undef pos_least
                    485: #undef pos_most
                    486: #undef data
                    487: #undef size
                    488: #undef size_agg
                    489: }
                    490: 
                    491: /* this returns a read buffer: */
                    492: static int
                    493: _tme_posix_disk_read(struct tme_disk_connection *conn_disk,
                    494:                     const union tme_value64 *pos,
                    495:                     unsigned long size,
                    496:                     const tme_uint8_t **_buffer)
                    497: {
                    498:   struct tme_posix_disk *posix_disk;
                    499:   tme_uint8_t *buffer;
                    500:   int rc;
                    501: 
                    502:   /* recover our data structure: */
                    503:   posix_disk = (struct tme_posix_disk *) conn_disk->tme_disk_connection.tme_connection_element->tme_element_private;
                    504: 
                    505:   /* lock the mutex: */
                    506:   tme_mutex_lock(&posix_disk->tme_posix_disk_mutex);
                    507: 
                    508:   /* get the buffer: */
                    509:   rc = _tme_posix_disk_buffer_get(posix_disk,
                    510:                                  pos,
                    511:                                  size,
                    512:                                  TRUE,
                    513:                                  &buffer);
                    514:   assert (rc == TME_OK);
                    515: 
                    516:   /* unlock the mutex: */
                    517:   tme_mutex_unlock(&posix_disk->tme_posix_disk_mutex);
                    518: 
                    519:   /* return the buffer: */
                    520:   *_buffer = buffer;
                    521:   return (TME_OK);
                    522: }
                    523: 
                    524: /* this returns a write buffer: */
                    525: static int
                    526: _tme_posix_disk_write(struct tme_disk_connection *conn_disk,
                    527:                      const union tme_value64 *pos,
                    528:                      unsigned long size,
                    529:                      tme_uint8_t **_buffer)
                    530: {
                    531:   struct tme_posix_disk *posix_disk;
                    532:   int rc;
                    533: 
                    534:   /* recover our data structure: */
                    535:   posix_disk = (struct tme_posix_disk *) conn_disk->tme_disk_connection.tme_connection_element->tme_element_private;
                    536: 
                    537:   /* lock the mutex: */
                    538:   tme_mutex_lock(&posix_disk->tme_posix_disk_mutex);
                    539: 
                    540:   /* get the buffer: */
                    541:   rc = _tme_posix_disk_buffer_get(posix_disk,
                    542:                                  pos,
                    543:                                  size,
                    544:                                  FALSE,
                    545:                                  _buffer);
                    546:   assert (rc == TME_OK);
                    547: 
                    548:   /* unlock the mutex: */
                    549:   tme_mutex_unlock(&posix_disk->tme_posix_disk_mutex);
                    550: 
                    551:   return (TME_OK);
                    552: }
                    553: 
                    554: /* the disk control handler: */
                    555: #ifdef HAVE_STDARG_H
                    556: static int _tme_posix_disk_control(struct tme_disk_connection *conn_disk,
                    557:                                   unsigned int control,
                    558:                                   ...)
                    559: #else  /* HAVE_STDARG_H */
                    560: static int _tme_posix_disk_control(conn_disk, control, va_alist)
                    561:      struct tme_disk_connection *conn_disk;
                    562:      unsigned int control;
                    563:      va_dcl
                    564: #endif /* HAVE_STDARG_H */
                    565: {
                    566:   struct tme_posix_disk *posix_disk;
                    567: 
                    568:   /* recover our data structure: */
                    569:   posix_disk = (struct tme_posix_disk *) conn_disk->tme_disk_connection.tme_connection_element->tme_element_private;
                    570: 
                    571:   /* lock the mutex: */
                    572:   tme_mutex_lock(&posix_disk->tme_posix_disk_mutex);
                    573: 
                    574:   /* unlock the mutex: */
                    575:   tme_mutex_unlock(&posix_disk->tme_posix_disk_mutex);
                    576: 
                    577:   return (TME_OK);
                    578: }
                    579: 
                    580: /* this breaks a posix disk connection: */
                    581: static int
                    582: _tme_posix_disk_connection_break(struct tme_connection *conn,
                    583:                                 unsigned int state)
                    584: {
                    585:   abort();
                    586: }
                    587: 
                    588: /* this makes a posix disk connection: */
                    589: static int
                    590: _tme_posix_disk_connection_make(struct tme_connection *conn,
                    591:                                unsigned int state)
                    592: {
                    593:   struct tme_posix_disk *posix_disk;
                    594:   struct tme_disk_connection *conn_disk;
                    595: 
                    596:   /* recover our data structure: */
                    597:   posix_disk = (struct tme_posix_disk *) conn->tme_connection_element->tme_element_private;
                    598: 
                    599:   /* both sides must be disk connections: */
                    600:   assert(conn->tme_connection_type == TME_CONNECTION_DISK);
                    601:   assert(conn->tme_connection_other->tme_connection_type == TME_CONNECTION_DISK);
                    602: 
                    603:   /* we're always set up to answer calls across the connection,
                    604:      so we only have to do work when the connection has gone full,
                    605:      namely taking the other side of the connection: */
                    606:   if (state == TME_CONNECTION_FULL) {
                    607: 
                    608:     /* lock the mutex: */
                    609:     tme_mutex_lock(&posix_disk->tme_posix_disk_mutex);
                    610: 
                    611:     /* save this connection to our list of connections: */
                    612:     conn_disk = (struct tme_disk_connection *) conn->tme_connection_other;
                    613:     posix_disk->tme_posix_disk_connection = conn_disk;
                    614: 
                    615:     /* unlock the mutex: */
                    616:     tme_mutex_unlock(&posix_disk->tme_posix_disk_mutex);
                    617:   }
                    618: 
                    619:   return (TME_OK);
                    620: }
                    621: 
                    622: /* this makes a new connection side for a posix disk: */
                    623: static int
                    624: _tme_posix_disk_connections_new(struct tme_element *element,
                    625:                                const char * const *args,
                    626:                                struct tme_connection **_conns,
                    627:                                char **_output)
                    628: {
                    629:   struct tme_posix_disk *posix_disk;
                    630:   struct tme_disk_connection *conn_disk;
                    631:   struct tme_connection *conn;
                    632: 
                    633:   /* recover our data structure: */
                    634:   posix_disk = (struct tme_posix_disk *) element->tme_element_private;
                    635: 
                    636:   /* if we already have a connection, there's nothing to do: */
                    637:   if (posix_disk->tme_posix_disk_connection != NULL) {
                    638:     return (TME_OK);
                    639:   }
                    640: 
                    641:   /* create our side of a disk connection: */
                    642:   conn_disk = tme_new0(struct tme_disk_connection, 1);
                    643:   conn = &conn_disk->tme_disk_connection;
                    644: 
                    645:   /* fill in the generic connection: */
                    646:   conn->tme_connection_next = *_conns;
                    647:   conn->tme_connection_type = TME_CONNECTION_DISK;
                    648:   conn->tme_connection_score = tme_disk_connection_score;
                    649:   conn->tme_connection_make = _tme_posix_disk_connection_make;
                    650:   conn->tme_connection_break = _tme_posix_disk_connection_break;
                    651: 
                    652:   /* fill in the disk connection: */
                    653:   (void) tme_value64_set(&conn_disk->tme_disk_connection_size,
                    654:                         posix_disk->tme_posix_disk_stat.st_size);
                    655:   conn_disk->tme_disk_connection_read
                    656:     = _tme_posix_disk_read;
                    657:   if (!(posix_disk->tme_posix_disk_flags
                    658:        & TME_POSIX_DISK_FLAG_RO)) {
                    659:     conn_disk->tme_disk_connection_write
                    660:       = _tme_posix_disk_write;
                    661:   }
                    662:   conn_disk->tme_disk_connection_release
                    663:     = NULL;
                    664:   conn_disk->tme_disk_connection_control
                    665:     = _tme_posix_disk_control;
                    666:   
                    667:   /* return the connection side possibility: */
                    668:   *_conns = conn;
                    669:   return (TME_OK);
                    670: }
                    671: 
                    672: /* the new posix disk function: */
                    673: TME_ELEMENT_SUB_NEW_DECL(tme_host_posix,disk) {
                    674:   const char *filename;
                    675:   int flags;
                    676:   int fd;
                    677:   unsigned long agg_pre;
                    678:   unsigned long agg_post;
                    679:   int buffers;
                    680:   struct stat statbuf;
                    681:   tme_uint8_t *block;
1.1.1.2 ! root      682: #ifdef HAVE_MMAP
        !           683:   int page_size;
        !           684: #endif /* HAVE_MMAP */
1.1       root      685:   struct tme_posix_disk *posix_disk;
                    686:   struct tme_posix_disk_buffer *buffer, **_prev;
                    687:   int arg_i;
                    688:   int usage;
                    689: 
                    690:   /* check our arguments: */
                    691:   filename = NULL;
                    692:   flags = 0;
                    693:   arg_i = 1;
                    694:   buffers = TME_POSIX_DISK_BUFFER_DEFAULT_COUNT;
                    695:   agg_pre = TME_POSIX_DISK_BUFFER_DEFAULT_AGG_PRE;
                    696:   agg_post = TME_POSIX_DISK_BUFFER_DEFAULT_AGG_POST;
                    697:   usage = FALSE;
                    698: 
                    699:   /* loop reading our arguments: */
                    700:   for (;;) {
                    701: 
                    702:     /* the filename: */
                    703:     if (TME_ARG_IS(args[arg_i], "file")
                    704:        && args[arg_i + 1] != NULL
                    705:        && filename == NULL) {
                    706:       filename = args[arg_i + 1];
                    707:       arg_i += 2;
                    708:     }
                    709: 
                    710:     /* the read-only flag: */
                    711:     else if (TME_ARG_IS(args[arg_i], "read-only")) {
                    712:       flags |= TME_POSIX_DISK_FLAG_RO;
                    713:       arg_i++;
                    714:     }
                    715: 
                    716:     /* the buffers count: */
                    717:     else if (TME_ARG_IS(args[arg_i + 0], "buffers")
                    718:             && args[arg_i + 1] != NULL
                    719:             && (buffers = atoi(args[arg_i + 1])) > 0) {
                    720:       arg_i += 2;
                    721:     }
                    722: 
                    723:     /* the read-behind value, also called the aggregate-pre: */
                    724:     else if (TME_ARG_IS(args[arg_i + 0], "read-behind")) {
                    725:       agg_pre = tme_bus_addr_parse_any(args[arg_i + 1], &usage);
                    726:       if (usage) {
                    727:        break;
                    728:       }
                    729:       arg_i += 2;
                    730:     }
                    731: 
                    732:     /* the read-ahead value, also called the aggregate-post: */
                    733:     else if (TME_ARG_IS(args[arg_i + 0], "read-ahead")) {
                    734:       agg_post = tme_bus_addr_parse_any(args[arg_i + 1], &usage);
                    735:       if (usage) {
                    736:        break;
                    737:       }
                    738:       arg_i += 2;
                    739:     }
                    740: 
                    741:     /* if we've run out of arguments: */
                    742:     else if (args[arg_i + 0] == NULL) {
                    743: 
                    744:       /* we must have been given a filename: */
                    745:       if (filename == NULL) {
                    746:        usage = TRUE;
                    747:       }
                    748:       break;
                    749:     }
                    750: 
                    751:     /* this is a bad argument: */
                    752:     else {
                    753:       tme_output_append_error(_output,
                    754:                              "%s %s", 
                    755:                              args[arg_i],
                    756:                              _("unexpected"));
                    757:       usage = TRUE;
                    758:       break;
                    759:     }
                    760:   }
                    761: 
                    762:   if (usage) {
                    763:     tme_output_append_error(_output, 
                    764:                            "%s %s file %s [read-only] [buffers %s] [read-behind %s] [read-ahead %s]",
                    765:                            _("usage:"),
                    766:                            args[0],
                    767:                            _("FILENAME"),
                    768:                            _("BUFFER-COUNT"),
                    769:                            _("BYTE-COUNT"),
                    770:                            _("BYTE-COUNT"));
                    771:     return (EINVAL);
                    772:   }
                    773: 
                    774:   /* open the file: */
                    775:   fd = open(filename, ((flags
                    776:                        & TME_POSIX_DISK_FLAG_RO)
                    777:                       ? O_RDONLY
                    778:                       : O_RDWR));
                    779:   if (fd < 0) {
                    780:     tme_output_append_error(_output,
                    781:                            "%s",
                    782:                            filename);
                    783:     return (errno);
                    784:   }
                    785: 
                    786:   /* stat the file: */
                    787:   if (fstat(fd, &statbuf) < 0) {
                    788:     tme_output_append_error(_output,
                    789:                            "%s",
                    790:                            filename);
                    791:     close(fd);
                    792:     return (errno);
                    793:   }
                    794: 
                    795:   /* we will handle a character device, but not a block device: */
                    796:   if (S_ISBLK(statbuf.st_mode)) {
                    797:     tme_output_append_error(_output,
                    798:                            "%s",
                    799:                            filename);
                    800:     close(fd);
                    801:     return (EINVAL);
                    802:   }
                    803: 
                    804:   /* if this is a character device, determine its block size: */
                    805:   if (S_ISCHR(statbuf.st_mode)) {
                    806: 
1.1.1.2 ! root      807:     /* the block size must be at least one: */
        !           808:     statbuf.st_blksize = TME_MAX(statbuf.st_blksize, 1);
        !           809: 
1.1       root      810:     /* allocate space for the block: */
                    811:     block = tme_new(tme_uint8_t, statbuf.st_blksize);
                    812: 
                    813:     /* loop trying to read a block at offset zero, doubling the block
                    814:        size until we succeed: */
                    815:     for (; statbuf.st_blksize <= TME_POSIX_DISK_BLOCK_SIZE_MAX; ) {
                    816: 
                    817:       /* do the read: */
                    818:       if (read(fd, block, statbuf.st_blksize) >= 0) {
                    819:        break;
                    820:       }
                    821: 
                    822:       /* seek back to the beginning: */
                    823:       if (lseek(fd, 0, SEEK_SET) < 0) {
                    824:        tme_free(block);
                    825:        tme_output_append_error(_output,
                    826:                                "%s",
                    827:                                filename);
                    828:        close(fd);
                    829:        return (errno);
                    830:       }
                    831: 
                    832:       /* resize the block: */
                    833:       statbuf.st_blksize <<= 1;
                    834:       block = tme_renew(tme_uint8_t, block, statbuf.st_blksize);
                    835:     }
                    836: 
                    837:     /* free the block: */
                    838:     tme_free(block);
                    839: 
                    840:     /* if we failed: */
                    841:     if (statbuf.st_blksize > TME_POSIX_DISK_BLOCK_SIZE_MAX) {
                    842:       tme_output_append_error(_output,
                    843:                              "%s",
                    844:                              filename);
                    845:       close(fd);
                    846:       return (EINVAL);
                    847:     }
                    848:   }
                    849: 
1.1.1.2 ! root      850: #ifdef HAVE_MMAP
        !           851:   /* if we're mmapping, the block size must be at least the page size: */
        !           852:   for (page_size = getpagesize();
        !           853:        page_size < statbuf.st_blksize;
        !           854:        page_size <<= 1);
        !           855:   statbuf.st_blksize = page_size;
        !           856: #endif /* HAVE_MMAP */
        !           857: 
1.1       root      858:   /* start the disk structure: */
                    859:   posix_disk = tme_new0(struct tme_posix_disk, 1);
                    860:   posix_disk->tme_posix_disk_element = element;
                    861:   tme_mutex_init(&posix_disk->tme_posix_disk_mutex);
                    862:   posix_disk->tme_posix_disk_flags = flags;
                    863:   posix_disk->tme_posix_disk_fd = fd;
                    864:   posix_disk->tme_posix_disk_stat = statbuf;
                    865:   posix_disk->tme_posix_disk_buffer_agg_pre = agg_pre;
                    866:   posix_disk->tme_posix_disk_buffer_agg_post = agg_post;
                    867: 
                    868:   /* allocate the buffers: */
                    869:   for (_prev = &posix_disk->tme_posix_disk_buffers;
                    870:        buffers-- > 0;
                    871:        _prev = &buffer->tme_posix_disk_buffer_next) {
                    872:     buffer = tme_new0(struct tme_posix_disk_buffer, 1);
                    873:     buffer->tme_posix_disk_buffer_prev = _prev;
                    874:     *buffer->tme_posix_disk_buffer_prev = buffer;
                    875:   }
                    876:   *_prev = NULL;
                    877: 
                    878:   /* fill the element: */
                    879:   element->tme_element_private = posix_disk;
                    880:   element->tme_element_connections_new = _tme_posix_disk_connections_new;
                    881: 
                    882:   return (TME_OK);
                    883: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.