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