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

1.1     ! root        1: /* $Id: posix-disk.c,v 1.3 2003/10/16 03:02:11 fredette Exp $ */
        !             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>
        !            37: _TME_RCSID("$Id: posix-disk.c,v 1.3 2003/10/16 03:02:11 fredette Exp $");
        !            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;
        !           682:   struct tme_posix_disk *posix_disk;
        !           683:   struct tme_posix_disk_buffer *buffer, **_prev;
        !           684:   int arg_i;
        !           685:   int usage;
        !           686: 
        !           687:   /* check our arguments: */
        !           688:   filename = NULL;
        !           689:   flags = 0;
        !           690:   arg_i = 1;
        !           691:   buffers = TME_POSIX_DISK_BUFFER_DEFAULT_COUNT;
        !           692:   agg_pre = TME_POSIX_DISK_BUFFER_DEFAULT_AGG_PRE;
        !           693:   agg_post = TME_POSIX_DISK_BUFFER_DEFAULT_AGG_POST;
        !           694:   usage = FALSE;
        !           695: 
        !           696:   /* loop reading our arguments: */
        !           697:   for (;;) {
        !           698: 
        !           699:     /* the filename: */
        !           700:     if (TME_ARG_IS(args[arg_i], "file")
        !           701:        && args[arg_i + 1] != NULL
        !           702:        && filename == NULL) {
        !           703:       filename = args[arg_i + 1];
        !           704:       arg_i += 2;
        !           705:     }
        !           706: 
        !           707:     /* the read-only flag: */
        !           708:     else if (TME_ARG_IS(args[arg_i], "read-only")) {
        !           709:       flags |= TME_POSIX_DISK_FLAG_RO;
        !           710:       arg_i++;
        !           711:     }
        !           712: 
        !           713:     /* the buffers count: */
        !           714:     else if (TME_ARG_IS(args[arg_i + 0], "buffers")
        !           715:             && args[arg_i + 1] != NULL
        !           716:             && (buffers = atoi(args[arg_i + 1])) > 0) {
        !           717:       arg_i += 2;
        !           718:     }
        !           719: 
        !           720:     /* the read-behind value, also called the aggregate-pre: */
        !           721:     else if (TME_ARG_IS(args[arg_i + 0], "read-behind")) {
        !           722:       agg_pre = tme_bus_addr_parse_any(args[arg_i + 1], &usage);
        !           723:       if (usage) {
        !           724:        break;
        !           725:       }
        !           726:       arg_i += 2;
        !           727:     }
        !           728: 
        !           729:     /* the read-ahead value, also called the aggregate-post: */
        !           730:     else if (TME_ARG_IS(args[arg_i + 0], "read-ahead")) {
        !           731:       agg_post = tme_bus_addr_parse_any(args[arg_i + 1], &usage);
        !           732:       if (usage) {
        !           733:        break;
        !           734:       }
        !           735:       arg_i += 2;
        !           736:     }
        !           737: 
        !           738:     /* if we've run out of arguments: */
        !           739:     else if (args[arg_i + 0] == NULL) {
        !           740: 
        !           741:       /* we must have been given a filename: */
        !           742:       if (filename == NULL) {
        !           743:        usage = TRUE;
        !           744:       }
        !           745:       break;
        !           746:     }
        !           747: 
        !           748:     /* this is a bad argument: */
        !           749:     else {
        !           750:       tme_output_append_error(_output,
        !           751:                              "%s %s", 
        !           752:                              args[arg_i],
        !           753:                              _("unexpected"));
        !           754:       usage = TRUE;
        !           755:       break;
        !           756:     }
        !           757:   }
        !           758: 
        !           759:   if (usage) {
        !           760:     tme_output_append_error(_output, 
        !           761:                            "%s %s file %s [read-only] [buffers %s] [read-behind %s] [read-ahead %s]",
        !           762:                            _("usage:"),
        !           763:                            args[0],
        !           764:                            _("FILENAME"),
        !           765:                            _("BUFFER-COUNT"),
        !           766:                            _("BYTE-COUNT"),
        !           767:                            _("BYTE-COUNT"));
        !           768:     return (EINVAL);
        !           769:   }
        !           770: 
        !           771:   /* open the file: */
        !           772:   fd = open(filename, ((flags
        !           773:                        & TME_POSIX_DISK_FLAG_RO)
        !           774:                       ? O_RDONLY
        !           775:                       : O_RDWR));
        !           776:   if (fd < 0) {
        !           777:     tme_output_append_error(_output,
        !           778:                            "%s",
        !           779:                            filename);
        !           780:     return (errno);
        !           781:   }
        !           782: 
        !           783:   /* stat the file: */
        !           784:   if (fstat(fd, &statbuf) < 0) {
        !           785:     tme_output_append_error(_output,
        !           786:                            "%s",
        !           787:                            filename);
        !           788:     close(fd);
        !           789:     return (errno);
        !           790:   }
        !           791: 
        !           792:   /* we will handle a character device, but not a block device: */
        !           793:   if (S_ISBLK(statbuf.st_mode)) {
        !           794:     tme_output_append_error(_output,
        !           795:                            "%s",
        !           796:                            filename);
        !           797:     close(fd);
        !           798:     return (EINVAL);
        !           799:   }
        !           800: 
        !           801:   /* if this is a character device, determine its block size: */
        !           802:   statbuf.st_blksize = 1;
        !           803:   if (S_ISCHR(statbuf.st_mode)) {
        !           804: 
        !           805:     /* allocate space for the block: */
        !           806:     block = tme_new(tme_uint8_t, statbuf.st_blksize);
        !           807: 
        !           808:     /* loop trying to read a block at offset zero, doubling the block
        !           809:        size until we succeed: */
        !           810:     for (; statbuf.st_blksize <= TME_POSIX_DISK_BLOCK_SIZE_MAX; ) {
        !           811: 
        !           812:       /* do the read: */
        !           813:       if (read(fd, block, statbuf.st_blksize) >= 0) {
        !           814:        break;
        !           815:       }
        !           816: 
        !           817:       /* seek back to the beginning: */
        !           818:       if (lseek(fd, 0, SEEK_SET) < 0) {
        !           819:        tme_free(block);
        !           820:        tme_output_append_error(_output,
        !           821:                                "%s",
        !           822:                                filename);
        !           823:        close(fd);
        !           824:        return (errno);
        !           825:       }
        !           826: 
        !           827:       /* resize the block: */
        !           828:       statbuf.st_blksize <<= 1;
        !           829:       block = tme_renew(tme_uint8_t, block, statbuf.st_blksize);
        !           830:     }
        !           831: 
        !           832:     /* free the block: */
        !           833:     tme_free(block);
        !           834: 
        !           835:     /* if we failed: */
        !           836:     if (statbuf.st_blksize > TME_POSIX_DISK_BLOCK_SIZE_MAX) {
        !           837:       tme_output_append_error(_output,
        !           838:                              "%s",
        !           839:                              filename);
        !           840:       close(fd);
        !           841:       return (EINVAL);
        !           842:     }
        !           843:   }
        !           844: 
        !           845:   /* start the disk structure: */
        !           846:   posix_disk = tme_new0(struct tme_posix_disk, 1);
        !           847:   posix_disk->tme_posix_disk_element = element;
        !           848:   tme_mutex_init(&posix_disk->tme_posix_disk_mutex);
        !           849:   posix_disk->tme_posix_disk_flags = flags;
        !           850:   posix_disk->tme_posix_disk_fd = fd;
        !           851:   posix_disk->tme_posix_disk_stat = statbuf;
        !           852:   posix_disk->tme_posix_disk_buffer_agg_pre = agg_pre;
        !           853:   posix_disk->tme_posix_disk_buffer_agg_post = agg_post;
        !           854: 
        !           855:   /* allocate the buffers: */
        !           856:   for (_prev = &posix_disk->tme_posix_disk_buffers;
        !           857:        buffers-- > 0;
        !           858:        _prev = &buffer->tme_posix_disk_buffer_next) {
        !           859:     buffer = tme_new0(struct tme_posix_disk_buffer, 1);
        !           860:     buffer->tme_posix_disk_buffer_prev = _prev;
        !           861:     *buffer->tme_posix_disk_buffer_prev = buffer;
        !           862:   }
        !           863:   *_prev = NULL;
        !           864: 
        !           865:   /* fill the element: */
        !           866:   element->tme_element_private = posix_disk;
        !           867:   element->tme_element_connections_new = _tme_posix_disk_connections_new;
        !           868: 
        !           869:   return (TME_OK);
        !           870: }

unix.superglobalmegacorp.com

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