u32_t fs_bufs_heuristic(int minbufs, u32_t btotal, u32_t bfree, int blocksize, dev_t majordev) { struct vm_stats_info vsi; int bufs; u32_t kbytes_used_fs, kbytes_total_fs, kbcache, kb_fsmax; u32_t kbytes_remain_mem, bused; bused = btotal-bfree; /* but we simply need minbufs no matter what, and we don't * want more than that if we're a memory device */ if(majordev == MEMORY_MAJOR) { return minbufs; } /* set a reasonable cache size; cache at most a certain * portion of the used FS, and at most a certain %age of remaining * memory */ if((vm_info_stats(&vsi) != OK)) { bufs = 1024; printf("fslib: heuristic info fail: default to %d bufs\n", bufs); return bufs; } kbytes_remain_mem = div64u(mul64u(vsi.vsi_free, vsi.vsi_pagesize), 1024); /* check fs usage. */ kbytes_used_fs = div64u(mul64u(bused, blocksize), 1024); kbytes_total_fs = div64u(mul64u(btotal, blocksize), 1024); /* heuristic for a desired cache size based on FS usage; * but never bigger than half of the total filesystem */ kb_fsmax = sqrt_approx(kbytes_used_fs)*40; kb_fsmax = MIN(kb_fsmax, kbytes_total_fs/2); /* heuristic for a maximum usage - 10% of remaining memory */ kbcache = MIN(kbytes_remain_mem/10, kb_fsmax); bufs = kbcache * 1024 / blocksize; /* but we simply need MINBUFS no matter what */ if(bufs < minbufs) bufs = minbufs; return bufs; }
u32_t fs_bufs_heuristic(int minbufs, u32_t btotal, u32_t bfree, int blocksize, dev_t majordev) { struct vm_stats_info vsi; int bufs; u32_t kbytes_used_fs, kbytes_total_fs, kbcache, kb_fsmax; u32_t kbytes_remain_mem, bused; bused = btotal-bfree; /* set a reasonable cache size; cache at most a certain * portion of the used FS, and at most a certain %age of remaining * memory */ if(vm_info_stats(&vsi) != OK) { bufs = 1024; if(!quiet) printf("fslib: heuristic info fail: default to %d bufs\n", bufs); return bufs; } /* remaining free memory is unused memory plus memory in used for cache, * as the cache can be evicted */ kbytes_remain_mem = (u64_t)(vsi.vsi_free + vsi.vsi_cached) * vsi.vsi_pagesize / 1024; /* check fs usage. */ kbytes_used_fs = div64u(mul64u(bused, blocksize), 1024); kbytes_total_fs = div64u(mul64u(btotal, blocksize), 1024); /* heuristic for a desired cache size based on FS usage; * but never bigger than half of the total filesystem */ kb_fsmax = sqrt_approx(kbytes_used_fs)*40; kb_fsmax = MIN(kb_fsmax, kbytes_total_fs/2); /* heuristic for a maximum usage - 10% of remaining memory */ kbcache = MIN(kbytes_remain_mem/10, kb_fsmax); bufs = kbcache * 1024 / blocksize; /* but we simply need MINBUFS no matter what */ if(bufs < minbufs) bufs = minbufs; return bufs; }
/* Write a block. */ void put_block(block_t n, void *buf) { (void) read_and_set(n); mkfs_seek(mul64u(n, block_size), SEEK_SET); mkfs_write(buf, block_size); }
u32_t micros_to_ticks(u32_t micros) { u32_t ticks; ticks = div64u(mul64u(micros, sys_hz()), 1000000); if(ticks < 1) ticks = 1; return ticks; }
/* Write a block. */ void put_block(block_t n, void *buf) { (void) read_and_set(n); if (lseek64(fd, mul64u(n, block_size), SEEK_SET, NULL) == (off_t) -1) pexit("put_block couldn't seek"); if (write(fd, buf, block_size)!= block_size) pexit("put_block couldn't write block #%u", (unsigned)n); }
/*================================================================ * sizeup - determine device size *===============================================================*/ block_t sizeup(char * device) { block_t d; #if defined(__minix) u64_t bytes, resize; u32_t rem; #else off_t size; #endif if ((fd = open(device, O_RDONLY)) == -1) { if (errno != ENOENT) perror("sizeup open"); return 0; } #if defined(__minix) if(minix_sizeup(device, &bytes) < 0) { perror("sizeup"); return 0; } d = div64u(bytes, block_size); rem = rem64u(bytes, block_size); resize = add64u(mul64u(d, block_size), rem); if(cmp64(resize, bytes) != 0) { /* Assume block_t is unsigned */ d = (block_t)(-1ul); fprintf(stderr, "%s: truncating FS at %lu blocks\n", progname, (unsigned long)d); } #else size = lseek(fd, 0, SEEK_END); if (size == (off_t) -1) err(1, "cannot get device size fd=%d: %s", fd, device); /* Assume block_t is unsigned */ if (size / block_size > (block_t)(-1ul)) { d = (block_t)(-1ul); fprintf(stderr, "%s: truncating FS at %lu blocks\n", progname, (unsigned long)d); } else d = size / block_size; #endif return d; }
/* Read a block. */ void get_block(block_t n, void *buf) { ssize_t k; /* First access returns a zero block */ if (read_and_set(n) == 0) { memcpy(buf, zero, block_size); return; } mkfs_seek(mul64u(n, block_size), SEEK_SET); k = read(fd, buf, block_size); if (k != block_size) pexit("get_block couldn't read block #%u", (unsigned)n); }
/* Read a block. */ void get_block(block_t n, void *buf) { ssize_t k; /* First access returns a zero block */ if (read_and_set(n) == 0) { memcpy(buf, zero, block_size); return; } if (lseek64(fd, mul64u(n, block_size), SEEK_SET, NULL) == (off_t)(-1)) pexit("get_block couldn't seek"); k = read(fd, buf, block_size); if (k != block_size) pexit("get_block couldn't read block #%u", (unsigned)n); }
static void testmul(void) { int kdone, kidx; u32_t ilo = ex64lo(i), jlo = ex64lo(j); u64_t prod = mul64(i, j); int prodbits; /* compute maximum index of highest-order bit */ prodbits = bsr64(i) + bsr64(j) + 1; if (cmp64u(i, 0) == 0 || cmp64u(j, 0) == 0) prodbits = -1; if (bsr64(prod) > prodbits) ERR; /* compare to 32-bit multiplication if possible */ if (ex64hi(i) == 0 && ex64hi(j) == 0) { if (cmp64(prod, mul64u(ilo, jlo)) != 0) ERR; /* if there is no overflow we can check against pure 32-bit */ if (prodbits < 32 && cmp64u(prod, ilo * jlo) != 0) ERR; } /* in 32-bit arith low-order DWORD matches regardless of overflow */ if (ex64lo(prod) != ilo * jlo) ERR; /* multiplication by zero yields zero */ if (prodbits < 0 && cmp64u(prod, 0) != 0) ERR; /* if there is no overflow, check absence of zero divisors */ if (prodbits >= 0 && prodbits < 64 && cmp64u(prod, 0) == 0) ERR; /* commutativity */ if (cmp64(prod, mul64(j, i)) != 0) ERR; /* loop though all argument value combinations for third argument */ for (kdone = 0, kidx = 0; k = getargval(kidx, &kdone), !kdone; kidx++) { /* associativity */ if (cmp64(mul64(mul64(i, j), k), mul64(i, mul64(j, k))) != 0) ERR; /* left and right distributivity */ if (cmp64(mul64(add64(i, j), k), add64(mul64(i, k), mul64(j, k))) != 0) ERR; if (cmp64(mul64(i, add64(j, k)), add64(mul64(i, j), mul64(i, k))) != 0) ERR; } }
/*===========================================================================* * rw_block * *===========================================================================*/ static void rw_block( register struct buf *bp, /* buffer pointer */ int rw_flag /* READING or WRITING */ ) { /* Read or write a disk block. This is the only routine in which actual disk * I/O is invoked. If an error occurs, a message is printed here, but the error * is not reported to the caller. If the error occurred while purging a block * from the cache, it is not clear what the caller could do about it anyway. */ int r, op_failed = 0; u64_t pos; dev_t dev; if ( (dev = bp->b_dev) != NO_DEV) { pos = mul64u(bp->b_blocknr, fs_block_size); if (rw_flag == READING) r = bdev_read(dev, pos, bp->b_data, fs_block_size, BDEV_NOFLAGS); else r = bdev_write(dev, pos, bp->b_data, fs_block_size, BDEV_NOFLAGS); if (r < 0) { printf("Ext2(%d) I/O error on device %d/%d, block %u\n", SELF_E, major(dev), minor(dev), bp->b_blocknr); op_failed = 1; } else if (r != (ssize_t) fs_block_size) { r = END_OF_FILE; op_failed = 1; } if (op_failed) { bp->b_dev = NO_DEV; /* invalidate block */ /* Report read errors to interested parties. */ if (rw_flag == READING) rdwt_err = r; } } bp->b_dirt = CLEAN; }
/*===========================================================================* * action_pre_misdir * *===========================================================================*/ static void action_pre_misdir(struct fbd_rule *rule, iovec_t *UNUSED(iov), unsigned *UNUSED(count), size_t *UNUSED(size), u64_t *pos) { /* Randomize the request position to fall within the range (and have * the alignment) given by the rule. */ u32_t range, choice; /* Unfortunately, we cannot interpret 0 as end as "up to end of disk" * here, because we have no idea about the actual disk size, and the * resulting address must of course be valid.. */ range = div64u(add64u(sub64(rule->params.misdir.end, rule->params.misdir.start), 1), rule->params.misdir.align); if (range > 0) choice = get_rand(range - 1); else choice = 0; *pos = add64(rule->params.misdir.start, mul64u(choice, rule->params.misdir.align)); }
/*===========================================================================* * driver_open * *===========================================================================*/ static int driver_open(int which) { /* Perform an open or close operation on the driver. This is * unfinished code: we should never be doing a blocking sendrec() to * the driver. */ message msg; cp_grant_id_t gid; struct partition part; sector_t sectors; int r; memset(&msg, 0, sizeof(msg)); msg.m_type = BDEV_OPEN; msg.BDEV_MINOR = driver[which].minor; msg.BDEV_ACCESS = R_BIT | W_BIT; msg.BDEV_ID = 0; r = sendrec(driver[which].endpt, &msg); if (r != OK) { /* Should we restart the driver now? */ printf("Filter: driver_open: sendrec returned %d\n", r); return RET_REDO; } if(msg.m_type != BDEV_REPLY || msg.BDEV_STATUS != OK) { printf("Filter: driver_open: sendrec returned %d, %d\n", msg.m_type, msg.BDEV_STATUS); return RET_REDO; } /* Take the opportunity to retrieve the hard disk size. */ gid = cpf_grant_direct(driver[which].endpt, (vir_bytes) &part, sizeof(part), CPF_WRITE); if(!GRANT_VALID(gid)) panic("invalid grant: %d", gid); memset(&msg, 0, sizeof(msg)); msg.m_type = BDEV_IOCTL; msg.BDEV_MINOR = driver[which].minor; msg.BDEV_REQUEST = DIOCGETP; msg.BDEV_GRANT = gid; msg.BDEV_ID = 0; r = sendrec(driver[which].endpt, &msg); cpf_revoke(gid); if (r != OK || msg.m_type != BDEV_REPLY || msg.BDEV_STATUS != OK) { /* Not sure what to do here, either. */ printf("Filter: ioctl(DIOCGETP) returned (%d, %d)\n", r, msg.m_type); return RET_REDO; } if(!size_known) { disk_size = part.size; size_known = 1; sectors = div64u(disk_size, SECTOR_SIZE); if(cmp64(mul64u(sectors, SECTOR_SIZE), disk_size)) { printf("Filter: partition too large\n"); return RET_REDO; } #if DEBUG printf("Filter: partition size: 0x%s / %lu sectors\n", print64(disk_size), sectors); #endif } else { if(cmp64(disk_size, part.size)) { printf("Filter: partition size mismatch (%s != %s)\n", print64(part.size), print64(disk_size)); return RET_REDO; } } return OK; }
PUBLIC u64_t ms_2_cpu_time(unsigned ms) { return mul64u(tsc_per_ms[cpuid], ms); }
/*===========================================================================* * rw_scattered * *===========================================================================*/ PUBLIC void rw_scattered( dev_t dev, /* major-minor device number */ struct buf **bufq, /* pointer to array of buffers */ int bufqsize, /* number of buffers */ int rw_flag /* READING or WRITING */ ) { /* Read or write scattered data from a device. */ register struct buf *bp; int gap; register int i; register iovec_t *iop; static iovec_t *iovec = NULL; int j, r; STATICINIT(iovec, NR_IOREQS); /* (Shell) sort buffers on b_blocknr. */ gap = 1; do gap = 3 * gap + 1; while (gap <= bufqsize); while (gap != 1) { gap /= 3; for (j = gap; j < bufqsize; j++) { for (i = j - gap; i >= 0 && bufq[i]->b_blocknr > bufq[i + gap]->b_blocknr; i -= gap) { bp = bufq[i]; bufq[i] = bufq[i + gap]; bufq[i + gap] = bp; } } } /* Set up I/O vector and do I/O. The result of dev_io is OK if everything * went fine, otherwise the error code for the first failed transfer. */ while (bufqsize > 0) { for (j = 0, iop = iovec; j < NR_IOREQS && j < bufqsize; j++, iop++) { bp = bufq[j]; if (bp->b_blocknr != (block_t) bufq[0]->b_blocknr + j) break; iop->iov_addr = (vir_bytes) bp->b_data; iop->iov_size = (vir_bytes) fs_block_size; } r = block_dev_io(rw_flag == WRITING ? MFS_DEV_SCATTER : MFS_DEV_GATHER, dev, SELF_E, iovec, mul64u(bufq[0]->b_blocknr, fs_block_size), j); /* Harvest the results. Dev_io reports the first error it may have * encountered, but we only care if it's the first block that failed. */ for (i = 0, iop = iovec; i < j; i++, iop++) { bp = bufq[i]; if (iop->iov_size != 0) { /* Transfer failed. An error? Do we care? */ if (r != OK && i == 0) { printf( "fs: I/O error on device %d/%d, block %lu\n", major(dev), minor(dev), bp->b_blocknr); bp->b_dev = NO_DEV; /* invalidate block */ vm_forgetblocks(); } break; } if (rw_flag == READING) { bp->b_dev = dev; /* validate block */ put_block(bp, PARTIAL_DATA_BLOCK); } else { bp->b_dirt = CLEAN; } } bufq += i; bufqsize -= i; if (rw_flag == READING) { /* Don't bother reading more than the device is willing to * give at this time. Don't forget to release those extras. */ while (bufqsize > 0) { put_block(*bufq++, PARTIAL_DATA_BLOCK); bufqsize--; } } if (rw_flag == WRITING && i == 0) { /* We're not making progress, this means we might keep * looping. Buffers remain dirty if un-written. Buffers are * lost if invalidate()d or LRU-removed while dirty. This * is better than keeping unwritable blocks around forever.. */ break; } } }
/*================================================================ * mkfs - make filesystem *===============================================================*/ int main(int argc, char *argv[]) { int nread, mode, usrid, grpid, ch, extra_space_percent, Tflag = 0; block_t blocks, maxblocks, bblocks; ino_t inodes, root_inum; char *token[MAX_TOKENS], line[LINE_LEN], *sfx; struct fs_size fssize; int insertmode = 0; progname = argv[0]; /* Process switches. */ blocks = 0; inodes = 0; bblocks = 0; #ifndef MFS_STATIC_BLOCK_SIZE block_size = 0; #endif zone_shift = 0; extra_space_percent = 0; while ((ch = getopt(argc, argv, "B:b:di:ltvx:z:I:T:")) != EOF) switch (ch) { #ifndef MFS_STATIC_BLOCK_SIZE case 'B': block_size = strtoul(optarg, &sfx, 0); switch(*sfx) { case 'b': case 'B': /* bytes; NetBSD-compatible */ case '\0': break; case 'K': case 'k': block_size*=1024; break; case 's': block_size*=SECTOR_SIZE; break; default: usage(); } break; #else case 'B': if (block_size != strtoul(optarg, (char **) NULL, 0)) errx(4, "block size must be exactly %d bytes", MFS_STATIC_BLOCK_SIZE); break; (void)sfx; /* shut up warnings about unused variable...*/ #endif case 'I': fs_offset_bytes = strtoul(optarg, (char **) NULL, 0); insertmode = 1; break; case 'b': blocks = bblocks = strtoul(optarg, (char **) NULL, 0); break; case 'T': Tflag = 1; current_time = strtoul(optarg, (char **) NULL, 0); break; case 'd': dflag = 1; break; case 'i': inodes = strtoul(optarg, (char **) NULL, 0); break; case 'l': print = 1; break; case 't': donttest = 1; break; case 'v': ++verbose; break; case 'x': extra_space_percent = atoi(optarg); break; case 'z': zone_shift = atoi(optarg); break; default: usage(); } if (argc == optind) usage(); /* Get the current time, set it to the mod time of the binary of * mkfs itself when the -d flag is used. The 'current' time is put into * the i_mtimes of all the files. This -d feature is useful when * producing a set of file systems, and one wants all the times to be * identical. First you set the time of the mkfs binary to what you * want, then go. */ if(Tflag) { if(dflag) errx(1, "-T and -d both specify a time and so are mutually exclusive"); } else if(dflag) { struct stat statbuf; if (stat(progname, &statbuf)) { err(1, "stat of itself"); } current_time = statbuf.st_mtime; } else { current_time = time((time_t *) 0); /* time mkfs is being run */ } /* Percentage of extra size must be nonnegative. * It can legitimately be bigger than 100 but has to make some sort of sense. */ if(extra_space_percent < 0 || extra_space_percent > 2000) usage(); #ifdef DEFAULT_BLOCK_SIZE if(!block_size) block_size = DEFAULT_BLOCK_SIZE; #endif if (block_size % SECTOR_SIZE) errx(4, "block size must be multiple of sector (%d bytes)", SECTOR_SIZE); #ifdef MIN_BLOCK_SIZE if (block_size < MIN_BLOCK_SIZE) errx(4, "block size must be at least %d bytes", MIN_BLOCK_SIZE); #endif #ifdef MAX_BLOCK_SIZE if (block_size > MAX_BLOCK_SIZE) errx(4, "block size must be at most %d bytes", MAX_BLOCK_SIZE); #endif if(block_size%INODE_SIZE) errx(4, "block size must be a multiple of inode size (%d bytes)", INODE_SIZE); if(zone_shift < 0 || zone_shift > 14) errx(4, "zone_shift must be a small non-negative integer"); zone_per_block = 1 << zone_shift; /* nr of blocks per zone */ inodes_per_block = INODES_PER_BLOCK(block_size); indir_per_block = INDIRECTS(block_size); indir_per_zone = INDIRECTS(block_size) << zone_shift; /* number of file zones we can address directly and with a single indirect*/ nr_indirzones = NR_DZONES + indir_per_zone; zone_size = block_size << zone_shift; /* Checks for an overflow: only with very big block size */ if (zone_size <= 0) errx(4, "Zones are too big for this program; smaller -B or -z, please!"); /* now that the block size is known, do buffer allocations where * possible. */ zero = alloc_block(); fs_offset_blocks = roundup(fs_offset_bytes, block_size) / block_size; /* Determine the size of the device if not specified as -b or proto. */ maxblocks = sizeup(argv[optind]); if (bblocks != 0 && bblocks + fs_offset_blocks > maxblocks && !insertmode) { errx(4, "Given size -b %d exeeds device capacity(%d)\n", bblocks, maxblocks); } if (argc - optind == 1 && bblocks == 0) { blocks = maxblocks; /* blocks == 0 is checked later, but leads to a funny way of * reporting a 0-sized device (displays usage). */ if(blocks < 1) { errx(1, "zero size device."); } } /* The remaining args must be 'special proto', or just 'special' if the * no. of blocks has already been specified. */ if (argc - optind != 2 && (argc - optind != 1 || blocks == 0)) usage(); if (maxblocks && blocks > maxblocks && !insertmode) { errx(1, "%s: number of blocks too large for device.", argv[optind]); } /* Check special. */ check_mtab(argv[optind]); /* Check and start processing proto. */ optarg = argv[++optind]; if (optind < argc && (proto = fopen(optarg, "r")) != NULL) { /* Prototype file is readable. */ lct = 1; get_line(line, token); /* skip boot block info */ /* Read the line with the block and inode counts. */ get_line(line, token); if (bblocks == 0){ blocks = strtol(token[0], (char **) NULL, 10); } else { if(bblocks < strtol(token[0], (char **) NULL, 10)) { errx(1, "%s: number of blocks given as parameter(%d)" " is too small for given proto file(%d).", argv[optind], bblocks, strtol(token[0], (char **) NULL, 10)); }; } inodes = strtol(token[1], (char **) NULL, 10); /* Process mode line for root directory. */ get_line(line, token); mode = mode_con(token[0]); usrid = atoi(token[1]); grpid = atoi(token[2]); if(blocks <= 0 && inodes <= 0){ detect_fs_size(&fssize); blocks = fssize.blockcount; inodes = fssize.inocount; blocks += blocks*extra_space_percent/100; inodes += inodes*extra_space_percent/100; /* XXX is it OK to write on stdout? Use warn() instead? Also consider using verbose */ fprintf(stderr, "dynamically sized filesystem: %u blocks, %u inodes\n", (unsigned int) blocks, (unsigned int) inodes); } } else { lct = 0; if (optind < argc) { /* Maybe the prototype file is just a size. Check. */ blocks = strtoul(optarg, (char **) NULL, 0); if (blocks == 0) errx(2, "Can't open prototype file"); } /* Make simple file system of the given size, using defaults. */ mode = 040777; usrid = BIN; grpid = BINGRP; simple = 1; } if (inodes == 0) { long long kb = ((unsigned long long)blocks*block_size) / 1024; inodes = kb / 2; if (kb >= 100000) inodes = kb / 4; if (kb >= 1000000) inodes = kb / 6; if (kb >= 10000000) inodes = kb / 8; if (kb >= 100000000) inodes = kb / 10; if (kb >= 1000000000) inodes = kb / 12; /* XXX check overflow: with very large number of blocks, this results in insanely large number of inodes */ /* XXX check underflow (if/when ino_t is signed), else the message below will look strange */ /* round up to fill inode block */ inodes += inodes_per_block - 1; inodes = inodes / inodes_per_block * inodes_per_block; } if (blocks < 5) errx(1, "Block count too small"); if (inodes < 1) errx(1, "Inode count too small"); nrblocks = blocks; nrinodes = inodes; umap_array_elements = 1 + blocks/8; if(!(umap_array = malloc(umap_array_elements))) err(1, "can't allocate block bitmap (%u bytes).", (unsigned)umap_array_elements); /* Open special. */ special(argv[--optind], insertmode); if (!donttest) { uint16_t *testb; ssize_t w; testb = alloc_block(); /* Try writing the last block of partition or diskette. */ mkfs_seek(mul64u(blocks - 1, block_size), SEEK_SET); testb[0] = 0x3245; testb[1] = 0x11FF; testb[block_size/2-1] = 0x1F2F; w=mkfs_write(testb, block_size); sync(); /* flush write, so if error next read fails */ mkfs_seek(mul64u(blocks - 1, block_size), SEEK_SET); testb[0] = 0; testb[1] = 0; testb[block_size/2-1] = 0; nread = read(fd, testb, block_size); if (nread != block_size || testb[0] != 0x3245 || testb[1] != 0x11FF || testb[block_size/2-1] != 0x1F2F) { warn("nread = %d\n", nread); warnx("testb = 0x%x 0x%x 0x%x\n", testb[0], testb[1], testb[block_size-1]); errx(1, "File system is too big for minor device (read)"); } mkfs_seek(mul64u(blocks - 1, block_size), SEEK_SET); testb[0] = 0; testb[1] = 0; testb[block_size/2-1] = 0; mkfs_write(testb, block_size); mkfs_seek(0L, SEEK_SET); free(testb); } /* Make the file-system */ put_block(BOOT_BLOCK, zero); /* Write a null boot block. */ put_block(BOOT_BLOCK+1, zero); /* Write another null block. */ super(nrblocks >> zone_shift, inodes); root_inum = alloc_inode(mode, usrid, grpid); rootdir(root_inum); if (simple == 0) eat_dir(root_inum); if (print) print_fs(); else if (verbose > 1) { if (zone_shift) fprintf(stderr, "%d inodes used. %u zones (%u blocks) used.\n", (int)next_inode-1, next_zone, next_zone*zone_per_block); else fprintf(stderr, "%d inodes used. %u zones used.\n", (int)next_inode-1, next_zone); } if(insertmode) printf("%ld\n", written_fs_size); return(0); /* NOTREACHED */ } /* end main */
/* * Convert a POSIX timespec structure to a VirtualBox timestamp. */ static u64_t set_time(struct timespec *tsp) { return add64u(mul64u(tsp->tv_sec, 1000000000), tsp->tv_nsec); }
/* * Convert a POSIX timespec structure to a VirtualBox timestamp. */ static u64_t set_time(struct timespec *tsp) { return mul64u(tsp->tv_sec, 1000000000) + tsp->tv_nsec; }
/*===========================================================================* * rw_scattered * *===========================================================================*/ void rw_scattered( dev_t dev, /* major-minor device number */ struct buf **bufq, /* pointer to array of buffers */ int bufqsize, /* number of buffers */ int rw_flag /* READING or WRITING */ ) { /* Read or write scattered data from a device. */ register struct buf *bp; int gap; register int i; register iovec_t *iop; static iovec_t *iovec = NULL; u64_t pos; int j, r; STATICINIT(iovec, NR_IOREQS); assert(bufq != NULL); /* (Shell) sort buffers on b_blocknr. */ gap = 1; do gap = 3 * gap + 1; while (gap <= bufqsize); while (gap != 1) { gap /= 3; for (j = gap; j < bufqsize; j++) { for (i = j - gap; i >= 0 && bufq[i]->b_blocknr > bufq[i + gap]->b_blocknr; i -= gap) { bp = bufq[i]; bufq[i] = bufq[i + gap]; bufq[i + gap] = bp; } } } /* Set up I/O vector and do I/O. The result of dev_io is OK if everything * went fine, otherwise the error code for the first failed transfer. */ while (bufqsize > 0) { for (j = 0, iop = iovec; j < NR_IOREQS && j < bufqsize; j++, iop++) { bp = bufq[j]; if (bp->b_blocknr != (block_t) bufq[0]->b_blocknr + j) break; iop->iov_addr = (vir_bytes) bp->b_data; iop->iov_size = (vir_bytes) fs_block_size; } pos = mul64u(bufq[0]->b_blocknr, fs_block_size); if (rw_flag == READING) r = bdev_gather(dev, pos, iovec, j, BDEV_NOFLAGS); else r = bdev_scatter(dev, pos, iovec, j, BDEV_NOFLAGS); /* Harvest the results. The driver may have returned an error, or it * may have done less than what we asked for. */ if (r < 0) { printf("ext2: I/O error %d on device %d/%d, block %u\n", r, major(dev), minor(dev), bufq[0]->b_blocknr); } for (i = 0; i < j; i++) { bp = bufq[i]; if (r < (ssize_t) fs_block_size) { /* Transfer failed. */ if (i == 0) { bp->b_dev = NO_DEV; /* invalidate block */ vm_forgetblocks(); } break; } if (rw_flag == READING) { bp->b_dev = dev; /* validate block */ put_block(bp, PARTIAL_DATA_BLOCK); } else { bp->b_dirt = CLEAN; } r -= fs_block_size; } bufq += i; bufqsize -= i; if (rw_flag == READING) { /* Don't bother reading more than the device is willing to * give at this time. Don't forget to release those extras. */ while (bufqsize > 0) { put_block(*bufq++, PARTIAL_DATA_BLOCK); bufqsize--; } } if (rw_flag == WRITING && i == 0) { /* We're not making progress, this means we might keep * looping. Buffers remain dirty if un-written. Buffers are * lost if invalidate()d or LRU-removed while dirty. This * is better than keeping unwritable blocks around forever.. */ break; } } }