SMREmulator 1.0
ShingledMagneticRecordingEmulator

ediv0.c

Go to the documentation of this file.
00001 
00012 #include <fcntl.h>
00013 #include <errno.h>
00014 #include <unistd.h>
00015 #include <string.h>
00016 
00017 #include <ediversion.h>
00018 
00019 
00020 
00021 /* -- Macro Definitions -- */
00022 #define EDIVERSION 0
00023 
00024 #define HEADER          ediv0_header
00025 
00026 #define OFF_META        OFF_HEADER + sizeof(ediv0_header_t)
00027 #define OFF_DATA    OFF_META + sizeof(ediv0_metadata_t) * HEADER.band_count
00028 
00029 
00030 /* -- Type Definitions -- */
00031 
00044 typedef struct {
00045     uint32_t blk_size;
00046     band_t band_count;
00047     rba_t band_size;
00048 } ediv0_header_t;
00049 
00050 
00061 typedef struct {
00062     rba_t write_ptr;
00063 } ediv0_metadata_t;
00064 
00065 
00066 
00067 /* -- Static Variables -- */
00068 static edi_vops_t ediv0_ops;
00069 static ediv0_header_t ediv0_header;
00070 
00071 
00072 
00073 /* -- Function Prototypes -- */
00074 static int is_valid_band(band_t);
00075 static int get_meta_rec(int, band_t, ediv0_metadata_t*);
00076 static int set_meta_rec(int, band_t, ediv0_metadata_t*);
00077 
00078 
00079 /* -- Function Implementations -- */
00080 
00089 static int ediv0_create(int fd, va_list args) {
00090         ediv0_header_t header;
00091         ediv0_metadata_t metadata;
00092         size_t size;
00093     uint32_t blk_size;
00094     band_t band_count;
00095     rba_t band_size;
00096     int i;
00097 
00098 
00099         /* Verify if all the required arguments are present and valid */
00100     blk_size = va_arg(args, uint32_t);
00101     band_count = va_arg(args, band_t);
00102     band_size = va_arg(args, rba_t);
00103     dbg("Arguments received: blk_size: %d, band_count: %d, band_size: %d\n",
00104                 blk_size, band_count, band_size);
00105 
00106     if ((blk_size & (blk_size - 1)))    /* Block size must be a power of 2 */
00107         return -1;
00108 
00109     if (band_count <= 0)                                /* Band count must be greater than 0 */
00110         return -1;
00111 
00112     if (band_size <= 0)                                 /* Band size must be greater than 0 */
00113         return -1;
00114 
00115 
00116     /* Write out the EDI header */
00117     header.blk_size = blk_size;
00118     header.band_count = band_count;
00119     header.band_size = band_size;
00120 
00121     size = sizeof(ediv0_header_t);
00122     if (pwrite(fd, &header, size, OFF_HEADER) != size)
00123         return -1;
00124     dbg("Header written out!\n");
00125 
00126 
00127     /* Write out the metadata */
00128     metadata.write_ptr = 0;
00129     size = sizeof(ediv0_metadata_t);
00130 
00131     if (lseek(fd, 0, SEEK_END) < 0) {
00132         dbg("Unable to see to end of file!\n");
00133         return -1;
00134     }
00135 
00136     for(i=0; i<band_count; i++) {
00137         if (write(fd, &metadata, size) != size) {
00138             dbg("Metadata record %d failed to be written out!\n", i);
00139                 return -1;
00140         }
00141         dbg("Wrote metadata record for band %d\n", i);
00142     }
00143 
00144         return 0;
00145 }
00146 
00147 
00148 
00157 static int ediv0_dump(int fd) {
00158         ediv0_metadata_t metadata;
00159     int i;
00160     int cols = 4;
00161 
00162 
00163     /* Display the EDI Version and basics */
00164     fprintf(stdout, "EDI INFORMATION\n===============\n");
00165     fprintf(stdout, "EDI Version: 0\n");
00166     fprintf(stdout, "Block Size: %d bytes\n", ediv0_header.blk_size);
00167     fprintf(stdout, "No. of bands: %d\n", ediv0_header.band_count);
00168     fprintf(stdout, "Write Pointers for bands:");
00169 
00170 
00171     /* Display the write pointers for each band */
00172     for (i=0; i<ediv0_header.band_count; i++) {
00173         /* Display the row header */
00174         if (!(i % cols))
00175                 fprintf(stdout, "\nBand %4d:", i);
00176 
00177         /* Read the band meta data for the current band */
00178         if (get_meta_rec(fd, i, &metadata) < 0) {
00179                 dbg("Error reading metadata for band %d: %s\n", i, strerror(errno));
00180                 return -1;
00181         }
00182         fprintf(stdout, "    %8d", metadata.write_ptr);
00183     }
00184     fprintf(stdout, "\n\n");
00185 
00186         return 0;
00187 }
00188 
00189 
00190 
00198 static int ediv0_open(int fd) {
00199         int size;
00200 
00201 
00202         /* Read the header data from disk */
00203         size = sizeof(ediv0_header_t);
00204         if (pread(fd, &ediv0_header, size, OFF_HEADER) < size) {
00205         dbg("Cannot read v0 header!\n");
00206                 errno = EFAIL;
00207                 return -1;
00208         }
00209         dbg("Loaded header into memory!\n");
00210 
00211         return 0;
00212 }
00213 
00214 
00215 
00233 static int ediv0_modesense(int fd, inq_t inq, void* data) {
00234         /* Check the operation requested */
00235         switch(inq) {
00236         case INQ_BLKSIZE:               /* Block Size */
00237                 *((uint32_t *)data) = ediv0_header.blk_size;
00238                 dbg("Returning block size as %d.\n", *((uint32_t *)data));
00239                 return 0;
00240 
00241         case INQ_BNDCOUNT:              /* Band Count */
00242                 *((band_t *)data) = ediv0_header.band_count;
00243                 dbg("Returning band count as %d.\n", *((band_t *)data));
00244                 return 0;
00245 
00246         default:                                /* Unsupported Operation */
00247                 errno = EUNSUPPORTED;
00248                 return -1;
00249         }
00250 }
00251 
00252 
00253 
00268 static int ediv0_managebands(int fd, svc_act_t action, band_t* band, rba_t* rba,
00269                 int len) {
00270         ediv0_metadata_t metadata;
00271         int i, rba_zero = 0, retval = 0;
00272 
00273 
00274         /* Check the action requested */
00275         switch (action) {
00276         case SVC_GETPTR:                /* Get Write Pointer for band */
00277                 /* Read the metadata for the band */
00278                 if (get_meta_rec(fd, *band, &metadata) < 0)
00279                         return -1;
00280 
00281                 /* Return the Write Pointer */
00282                 *rba = metadata.write_ptr;
00283                 dbg("Write pointer for band %d returned as %d\n", *band, *rba);
00284                 return 0;
00285 
00286 
00287         case SVC_SETPTR:                /* Set Write Pointer for band */
00288                 /* Verify that the rba is valid */
00289                 if ((*rba < 0) || (*rba >= ediv0_header.band_size)) {
00290                         dbg("Invalid RBA (%d) specified!", *rba);
00291                         errno = ERBA;
00292                         return -1;
00293                 }
00294 
00295                 /* Read the metadata for the band */
00296                 if (get_meta_rec(fd, *band, &metadata) < 0)
00297                         return -1;
00298 
00299                 /* Update the Write Pointer */
00300                 metadata.write_ptr = *rba;
00301 
00302                 /* Write the metadata for the band */
00303                 if (set_meta_rec(fd, *band, &metadata) < 0)
00304                         return -1;
00305 
00306                 dbg("Write pointer for band %d set as %d\n", *band, *rba);
00307                 return 0;
00308 
00309 
00310         case SVC_GETMULTIPLE:   /* Get Write Pointer for bands */
00311                 /* Loop over all the bands passed */
00312                 for(i=0; i<len; i++) {
00313                         /* Retrieve the Write Pointer for the current band */
00314                         if (ediv0_managebands(fd, SVC_GETPTR, &band[i], &rba[i], 0) < 0) {
00315                                 rba[i] = -1;
00316                                 retval = -1;
00317                                 dbg("Unable to retrieve Write Pointer for band %d\n", band[i]);
00318                         }
00319                         dbg("Write pointer for band %d returned as %d\n", band[i], rba[i]);
00320                 }
00321 
00322                 return retval;
00323 
00324 
00325         case SVC_RESETALL:              /* Set Write Pointers for all bands */
00326                 /* Loop over all the bands */
00327                 for(i=0; i<ediv0_header.band_count; i++) {
00328                         /* Retrieve the Write Pointer for the current band */
00329                         if (ediv0_managebands(fd, SVC_SETPTR, &band[i], &rba_zero, 0) < 0) {
00330                                 rba[i] = -1;
00331                                 retval = -1;
00332                                 dbg("Unable to retrieve Write Pointer for band %d\n", band[i]);
00333                         }
00334                         dbg("Write pointer for band %d set as %d\n", band[i], rba_zero);
00335                 }
00336 
00337                 return 0;
00338 
00339 
00340         case SVC_GETBANDCONFIG: /* Returns the size of a band */
00341                 /* Validate the band */
00342                 if (!is_valid_band(*band)) {
00343                         dbg("Band %d is not valid!\n", *band);
00344                         errno = EBAND;
00345                         return -1;
00346                 }
00347 
00348                 /* Return the size of the band */
00349                 *rba = ediv0_header.band_size;
00350                 dbg("Band size returned as %d.\n", *rba);
00351                 return 0;
00352 
00353 
00354         default:                                /* Unsupported Operation */
00355                 dbg("Unsupported operation %x requested for band %d\n", action, *rba);
00356                 errno = EUNSUPPORTED;
00357                 return -1;
00358         }
00359 }
00360 
00361 
00362 
00382 static int ediv0_read(int fd, band_t band, rba_t rba, char* buf, rba_t count) {
00383         ediv0_metadata_t metadata;
00384         off_t offset;
00385         size_t size = count * HEADER.blk_size;
00386 
00387 
00388         dbg("Reading data in band %d from block %d to %d\n", band, rba, rba+count);
00389 
00390         /* Read the metadata for the band */
00391         if (get_meta_rec(fd, band, &metadata) < 0) {
00392                 return -1;
00393         }
00394 
00395         /* Verify that the rba is valid */
00396         if ((rba < 0) || (rba >= HEADER.band_size)) {
00397                 errno = ERBA;
00398                 return -1;
00399         }
00400 
00401         if (rba >= metadata.write_ptr) {
00402                 errno = EOOB;
00403                 return -1;
00404         }
00405 
00406         /* Check the validity of the read length */
00407         if (rba + count > metadata.write_ptr) {
00408                 errno = EOOB;
00409                 return -1;
00410         }
00411 
00412 
00413         /* Read the data into the buffer */
00414         offset = OFF_DATA + ((off_t)band * HEADER.band_size * HEADER.blk_size);
00415     dbg("Data for band begins at %lld bytes. ", (long long)offset);
00416         offset += ((off_t)rba * HEADER.blk_size);
00417     dbg("Data for block begins at %lld bytes. ", (long long)offset);
00418         if (pread(fd, buf, size, offset) != size)
00419                 return -1;
00420 
00421         return 0;
00422 }
00423 
00424 
00425 
00447 static int ediv0_write(int fd, band_t band, rba_t rba, char* buf, rba_t count) {
00448         ediv0_metadata_t metadata;
00449         off_t offset;
00450         off_t size = count * HEADER.blk_size;
00451 
00452 
00453         dbg("Writing data to band %d from block %d to %d\n", band, rba, rba+count);
00454 
00455         /* Check the validity of the write length */
00456         if ((rba + count > rba) && (rba + count > ediv0_header.band_size)) {
00457                 dbg("rba+count (%d) exceed band size (%d)!\n",
00458                                 rba+count, ediv0_header.band_size);
00459                 errno = EOOB;
00460                 return -1;
00461         }
00462 
00463         /* Read the metadata for the band */
00464         if (get_meta_rec(fd, band, &metadata) < 0) {
00465                 dbg("Cannot fetch metadata record for band %d\n", band);
00466                 return -1;
00467         }
00468 
00469         /* Verify that the rba is valid */
00470         if (rba != metadata.write_ptr) {
00471                 dbg("rba passed (%d) does not match write pointer (%d)\n",
00472                                 rba, metadata.write_ptr);
00473                 errno = ERBA;
00474                 return -1;
00475         }
00476 
00477         /* Write the data from the buffer */
00478         offset = OFF_DATA + ((off_t)band * HEADER.band_size * HEADER.blk_size);
00479     dbg("Data for band begins at %lld bytes. ", (long long)offset);
00480         offset += ((off_t)rba * HEADER.blk_size);
00481     dbg("Data for block begins at %lld bytes. ", (long long)offset);
00482         if (pwrite(fd, buf, size, offset) != size) {
00483                 dbg("pwrite() failed to writedata: %s\n", strerror(errno));
00484                 return -1;
00485         }
00486 
00487         /* Update the write pointer for the band */
00488         metadata.write_ptr += count;
00489         if (set_meta_rec(fd, band, &metadata) < 0) {
00490                 dbg("Failed to update write pointer (%d)\n", metadata.write_ptr);
00491                 errno = EUPDATE;
00492                 return -1;
00493         }
00494 
00495         return 0;
00496 }
00497 
00498 
00499 
00505 edi_vops_t* ediv0_init() {
00506         /* Initialize all data structures */
00507         memset(&ediv0_header, 0, sizeof(ediv0_header_t));
00508 
00509 
00510         /* Initialize the Call-back Functions object and return it to the caller */
00511         ediv0_ops.create = ediv0_create;
00512         ediv0_ops.dump = ediv0_dump;
00513         ediv0_ops.open = ediv0_open;
00514         ediv0_ops.modesense = ediv0_modesense;
00515         ediv0_ops.managebands = ediv0_managebands;
00516         ediv0_ops.read = ediv0_read;
00517         ediv0_ops.write = ediv0_write;
00518 
00519         return &ediv0_ops;
00520 }
00521 
00522 
00523 
00531 static int is_valid_band(band_t band) {
00532         /* Ensure that the band number is less than the band count for the EDI */
00533         return ((band >= 0) && (band < ediv0_header.band_count));
00534 }
00535 
00536 
00537 
00554 static int get_meta_rec(int fd, band_t band, ediv0_metadata_t* metadata) {
00555         int len;
00556         size_t offset;
00557 
00558 
00559         /* Validate the band */
00560         if (!is_valid_band(band)) {
00561                 errno = EBAND;
00562                 return -1;
00563         }
00564 
00565         /* Read the metadata record */
00566         offset = OFF_META + sizeof(ediv0_metadata_t) * band;
00567         len = pread(fd, metadata, sizeof(ediv0_metadata_t), offset);
00568         if (len < sizeof(ediv0_metadata_t))
00569                 return -1;
00570 
00571         return 0;
00572 }
00573 
00574 
00575 
00592 static int set_meta_rec(int fd, band_t band, ediv0_metadata_t* metadata) {
00593         int len;
00594         size_t offset;
00595 
00596 
00597         /* Validate the band */
00598         if (!is_valid_band(band)) {
00599                 errno = EBAND;
00600                 return -1;
00601         }
00602 
00603         /* Read the metadata record */
00604         offset = OFF_META + sizeof(ediv0_metadata_t) * band;
00605         len = pwrite(fd, metadata, sizeof(ediv0_metadata_t), offset);
00606         if (len < sizeof(ediv0_metadata_t))
00607                 return -1;
00608 
00609         return 0;
00610 }