|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.