/*===========================================================================* * fs_breadwrite * *===========================================================================*/ PUBLIC int fs_breadwrite(void) { int r, rw_flag, completed; cp_grant_id_t gid; u64_t position; unsigned int off, cum_io, chunk, block_size; size_t nrbytes; /* Pseudo inode for rw_chunk */ struct inode rip; r = OK; /* Get the values from the request message */ rw_flag = (fs_m_in.m_type == REQ_BREAD ? READING : WRITING); gid = (cp_grant_id_t) fs_m_in.REQ_GRANT; position = make64((unsigned long) fs_m_in.REQ_SEEK_POS_LO, (unsigned long) fs_m_in.REQ_SEEK_POS_HI); nrbytes = (size_t) fs_m_in.REQ_NBYTES; block_size = get_block_size( (dev_t) fs_m_in.REQ_DEV2); rip.i_zone[0] = (zone_t) fs_m_in.REQ_DEV2; rip.i_mode = I_BLOCK_SPECIAL; rip.i_size = 0; rdwt_err = OK; /* set to EIO if disk error occurs */ cum_io = 0; /* Split the transfer into chunks that don't span two blocks. */ while (nrbytes > 0) { off = rem64u(position, block_size); /* offset in blk*/ chunk = min(nrbytes, block_size - off); /* Read or write 'chunk' bytes. */ r = rw_chunk(&rip, position, off, chunk, nrbytes, rw_flag, gid, cum_io, block_size, &completed); if (r != OK) break; /* EOF reached */ if (rdwt_err < 0) break; /* Update counters and pointers. */ nrbytes -= chunk; /* bytes yet to be read */ cum_io += chunk; /* bytes read so far */ position = add64ul(position, chunk); /* position within the file */ } fs_m_out.RES_SEEK_POS_LO = ex64lo(position); fs_m_out.RES_SEEK_POS_HI = ex64hi(position); if (rdwt_err != OK) r = rdwt_err; /* check for disk error */ if (rdwt_err == END_OF_FILE) r = OK; fs_m_out.RES_NBYTES = cum_io; return(r); }
static __inline u32_t makehash(u32_t p1, u64_t p2) { u32_t offlo = ex64lo(p2), offhi = ex64hi(p2), v = 0x12345678; hash_mix(p1, offlo, offhi); hash_final(offlo, offhi, v); return v % HASHSIZE; }
/*===========================================================================* * do_read * *===========================================================================*/ int do_read() { /* Read data from a file. */ struct inode *ino; u64_t pos; size_t count, size; vir_bytes off; char *ptr; int r, chunk; if ((ino = find_inode(m_in.REQ_INODE_NR)) == NULL) return EINVAL; if (IS_DIR(ino)) return EISDIR; if ((r = get_handle(ino)) != OK) return r; pos = make64(m_in.REQ_SEEK_POS_LO, m_in.REQ_SEEK_POS_HI); count = m_in.REQ_NBYTES; assert(count > 0); /* Use the buffer from below to eliminate extra copying. */ size = sffs_table->t_readbuf(&ptr); off = 0; while (count > 0) { chunk = MIN(count, size); if ((r = sffs_table->t_read(ino->i_file, ptr, chunk, pos)) <= 0) break; chunk = r; r = sys_safecopyto(m_in.m_source, m_in.REQ_GRANT, off, (vir_bytes) ptr, chunk, D); if (r != OK) break; count -= chunk; off += chunk; pos = add64u(pos, chunk); } if (r < 0) return r; m_out.RES_SEEK_POS_HI = ex64hi(pos); m_out.RES_SEEK_POS_LO = ex64lo(pos); m_out.RES_NBYTES = off; return OK; }
static void testdiv(void) { u64_t q, r; #if TIMED struct timeval tvstart, tvend; printf("i=0x%.8x%.8x; j=0x%.8x%.8x\n", ex64hi(i), ex64lo(i), ex64hi(j), ex64lo(j)); fflush(stdout); if (gettimeofday(&tvstart, NULL) < 0) ERR; #endif /* division by zero has a separate test */ if (cmp64u(j, 0) == 0) { testdiv0(); return; } /* perform division, store q in k to make ERR more informative */ q = div64(i, j); r = rem64(i, j); k = q; #if TIMED if (gettimeofday(&tvend, NULL) < 0) ERR; tvend.tv_sec -= tvstart.tv_sec; tvend.tv_usec -= tvstart.tv_usec; if (tvend.tv_usec < 0) { tvend.tv_sec -= 1; tvend.tv_usec += 1000000; } printf("q=0x%.8x%.8x; r=0x%.8x%.8x; time=%d.%.6d\n", ex64hi(q), ex64lo(q), ex64hi(r), ex64lo(r), tvend.tv_sec, tvend.tv_usec); fflush(stdout); #endif /* compare to 64/32-bit division if possible */ if (!ex64hi(j)) { if (cmp64(q, div64u64(i, ex64lo(j))) != 0) ERR; if (!ex64hi(q)) { if (cmp64u(q, div64u(i, ex64lo(j))) != 0) ERR; } if (cmp64u(r, rem64u(i, ex64lo(j))) != 0) ERR; /* compare to 32-bit division if possible */ if (!ex64hi(i)) { if (cmp64u(q, ex64lo(i) / ex64lo(j)) != 0) ERR; if (cmp64u(r, ex64lo(i) % ex64lo(j)) != 0) ERR; } } /* check results using i = q j + r and r < j */ if (cmp64(i, add64(mul64(q, j), r)) != 0) ERR; if (cmp64(r, j) >= 0) ERR; }
/*===========================================================================* * do_lseek * *===========================================================================*/ int do_lseek() { /* Perform the lseek(ls_fd, offset, whence) system call. */ register struct filp *rfilp; int r = OK, seekfd, seekwhence; off_t offset; u64_t pos, newpos; seekfd = job_m_in.ls_fd; seekwhence = job_m_in.whence; offset = (off_t) job_m_in.offset_lo; /* Check to see if the file descriptor is valid. */ if ( (rfilp = get_filp(seekfd, VNODE_READ)) == NULL) return(err_code); /* No lseek on pipes. */ if (S_ISFIFO(rfilp->filp_vno->v_mode)) { unlock_filp(rfilp); return(ESPIPE); } /* The value of 'whence' determines the start position to use. */ switch(seekwhence) { case SEEK_SET: pos = cvu64(0); break; case SEEK_CUR: pos = rfilp->filp_pos; break; case SEEK_END: pos = cvul64(rfilp->filp_vno->v_size); break; default: unlock_filp(rfilp); return(EINVAL); } if (offset >= 0) newpos = add64ul(pos, offset); else newpos = sub64ul(pos, -offset); /* Check for overflow. */ if (ex64hi(newpos) != 0) { r = EOVERFLOW; } else if ((off_t) ex64lo(newpos) < 0) { /* no negative file size */ r = EOVERFLOW; } else { /* insert the new position into the output message */ m_out.reply_l1 = ex64lo(newpos); if (cmp64(newpos, rfilp->filp_pos) != 0) { rfilp->filp_pos = newpos; /* Inhibit read ahead request */ r = req_inhibread(rfilp->filp_vno->v_fs_e, rfilp->filp_vno->v_inode_nr); } } unlock_filp(rfilp); return(r); }
/*===========================================================================* * do_readsuper * *===========================================================================*/ PUBLIC int do_readsuper() { /* Mount the file system. */ char path[PATH_MAX]; struct inode *ino; struct hgfs_attr attr; int r; dprintf(("HGFS: readsuper (dev %x, flags %x)\n", (dev_t) m_in.REQ_DEV, m_in.REQ_FLAGS)); if (m_in.REQ_FLAGS & REQ_ISROOT) { printf("HGFS: attempt to mount as root device\n"); return EINVAL; } state.read_only = !!(m_in.REQ_FLAGS & REQ_RDONLY); state.dev = m_in.REQ_DEV; init_dentry(); ino = init_inode(); attr.a_mask = HGFS_ATTR_MODE | HGFS_ATTR_SIZE; /* We cannot continue if we fail to get the properties of the root inode at * all, because we cannot guess the details of the root node to return to * VFS. Print a (hopefully) helpful error message, and abort the mount. */ if ((r = verify_inode(ino, path, &attr)) != OK) { if (r == EAGAIN) printf("HGFS: shared folders disabled\n"); else if (opt.prefix[0] && (r == ENOENT || r == EACCES)) printf("HGFS: unable to access the given prefix directory\n"); else printf("HGFS: unable to access shared folders\n"); return r; } m_out.RES_INODE_NR = INODE_NR(ino); m_out.RES_MODE = get_mode(ino, attr.a_mode); m_out.RES_FILE_SIZE_HI = ex64hi(attr.a_size); m_out.RES_FILE_SIZE_LO = ex64lo(attr.a_size); m_out.RES_UID = opt.uid; m_out.RES_GID = opt.gid; m_out.RES_DEV = NO_DEV; m_out.RES_CONREQS = 1; /* We can handle only 1 request at a time */ state.mounted = TRUE; return OK; }
/*===========================================================================* * scall_lseek * *===========================================================================*/ int scall_lseek() { /* Perform the lseek(ls_fd, offset, whence) system call. */ register struct filp *rfilp; int r; long offset; u64_t pos, newpos; /* Check to see if the file descriptor is valid. */ if ( (rfilp = get_filp(m_in.ls_fd)) == NIL_FILP) return(err_code); /* No lseek on pipes. */ if (rfilp->filp_vno->v_pipe == I_PIPE) return -ESPIPE; /* The value of 'whence' determines the start position to use. */ switch(m_in.whence) { case SEEK_SET: pos = cvu64(0); break; case SEEK_CUR: pos = rfilp->filp_pos; break; case SEEK_END: pos = cvul64(rfilp->filp_vno->v_size); break; default: return(-EINVAL); } offset= m_in.offset_lo; if (offset >= 0) newpos= add64ul(pos, offset); else newpos= sub64ul(pos, -offset); /* Check for overflow. */ if (ex64hi(newpos) != 0) return -EINVAL; if (cmp64(newpos, rfilp->filp_pos) != 0) { /* Inhibit read ahead request */ r = req_inhibread(rfilp->filp_vno->v_fs_e, rfilp->filp_vno->v_inode_nr); if (r != 0) return r; } rfilp->filp_pos = newpos; return ex64lo(newpos); }
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; } }
/*===========================================================================* * print64 * *===========================================================================*/ char *print64(u64_t p) { #define NB 10 static int n = 0; static char buf[NB][100]; u32_t lo = ex64lo(p), hi = ex64hi(p); n = (n+1) % NB; if(!hi) sprintf(buf[n], "%lx", lo); else sprintf(buf[n], "%lx%08lx", hi, lo); return buf[n]; }
/*===========================================================================* * fs_bread * *===========================================================================*/ int fs_bread(void) { int r, rw_flag, chunk, block_size; cp_grant_id_t gid; int nrbytes; u64_t position; unsigned int off, cum_io; int completed; struct dir_record *dir; r = OK; rw_flag = (fs_m_in.m_type == REQ_BREAD ? READING : WRITING); gid = fs_m_in.REQ_GRANT; position = make64(fs_m_in.REQ_SEEK_POS_LO, fs_m_in.REQ_SEEK_POS_HI); nrbytes = (unsigned) fs_m_in.REQ_NBYTES; block_size = v_pri.logical_block_size_l; dir = v_pri.dir_rec_root; if(rw_flag == WRITING) return (EIO); /* Not supported */ rdwt_err = OK; /* set to EIO if disk error occurs */ cum_io = 0; /* Split the transfer into chunks that don't span two blocks. */ while (nrbytes != 0) { off = rem64u(position, block_size); /* offset in blk*/ chunk = MIN(nrbytes, block_size - off); if (chunk < 0) chunk = block_size - off; /* Read 'chunk' bytes. */ r = read_chunk(dir, position, off, chunk, (unsigned) nrbytes, gid, cum_io, block_size, &completed); if (r != OK) break; /* EOF reached */ if (rdwt_err < 0) break; /* Update counters and pointers. */ nrbytes -= chunk; /* bytes yet to be read */ cum_io += chunk; /* bytes read so far */ position= add64ul(position, chunk); /* position within the file */ } fs_m_out.RES_SEEK_POS_LO = ex64lo(position); fs_m_out.RES_SEEK_POS_HI = ex64hi(position); if (rdwt_err != OK) r = rdwt_err; /* check for disk error */ if (rdwt_err == END_OF_FILE) r = OK; fs_m_out.RES_NBYTES = cum_io; return(r); }
/*===========================================================================* * do_llseek * *===========================================================================*/ PUBLIC int do_llseek() { /* Perform the llseek(ls_fd, offset, whence) system call. */ register struct filp *rfilp; u64_t pos, newpos; int r = OK; /* Check to see if the file descriptor is valid. */ if ( (rfilp = get_filp(m_in.ls_fd, VNODE_READ)) == NULL) return(err_code); /* No lseek on pipes. */ if (rfilp->filp_vno->v_pipe == I_PIPE) { unlock_filp(rfilp); return(ESPIPE); } /* The value of 'whence' determines the start position to use. */ switch(m_in.whence) { case SEEK_SET: pos = cvu64(0); break; case SEEK_CUR: pos = rfilp->filp_pos; break; case SEEK_END: pos = cvul64(rfilp->filp_vno->v_size); break; default: unlock_filp(rfilp); return(EINVAL); } newpos = add64(pos, make64(m_in.offset_lo, m_in.offset_high)); /* Check for overflow. */ if (( (long) m_in.offset_high > 0) && cmp64(newpos, pos) < 0) r = EINVAL; else if (( (long) m_in.offset_high < 0) && cmp64(newpos, pos) > 0) r = EINVAL; else { rfilp->filp_pos = newpos; /* insert the new position into the output message */ m_out.reply_l1 = ex64lo(newpos); m_out.reply_l2 = ex64hi(newpos); if (cmp64(newpos, rfilp->filp_pos) != 0) { /* Inhibit read ahead request */ r = req_inhibread(rfilp->filp_vno->v_fs_e, rfilp->filp_vno->v_inode_nr); } } unlock_filp(rfilp); return(r); }
/*===========================================================================* * fbd_transfer * *===========================================================================*/ static int fbd_transfer(dev_t UNUSED(minor), int do_write, u64_t position, endpoint_t endpt, iovec_t *iov, unsigned int nr_req, int flags) { /* Transfer data from or to the device. */ unsigned count; size_t size, osize; int i, hooks; ssize_t r; /* Compute the total size of the request. */ for (size = i = 0; i < nr_req; i++) size += iov[i].iov_size; osize = size; count = nr_req; hooks = rule_find(position, size, do_write ? FBD_FLAG_WRITE : FBD_FLAG_READ); #if DEBUG printf("FBD: %s operation for pos %lx:%08lx size %u -> hooks %x\n", do_write ? "write" : "read", ex64hi(position), ex64lo(position), size, hooks); #endif if (hooks & PRE_HOOK) rule_pre_hook(iov, &count, &size, &position); if (count > 0) { if (hooks & IO_HOOK) { r = fbd_transfer_copy(do_write, position, endpt, iov, count, size, flags); } else { r = fbd_transfer_direct(do_write, position, endpt, iov, count, flags); } } else r = 0; if (hooks & POST_HOOK) rule_post_hook(osize, &r); #if DEBUG printf("FBD: returning %d\n", r); #endif return r; }
static double make_double(u64_t d) { /* Convert a 64-bit fixed point value into a double. * This whole thing should be replaced by something better eventually. */ double value; size_t i; value = (double) ex64hi(d); for (i = 0; i < sizeof(unsigned long); i += 2) value *= 65536.0; value += (double) ex64lo(d); return value; }
/*===========================================================================* * vfs_request * *===========================================================================*/ int vfs_request(int reqno, int fd, struct vmproc *vmp, u64_t offset, u32_t len, vfs_callback_t reply_callback, void *cbarg, void *state, int statelen) { /* Perform an asynchronous request to VFS. * We send a message of type VFS_VMCALL to VFS. VFS will respond * with message type VM_VFS_REPLY. We send the request asynchronously * and then handle the reply as it if were a VM_VFS_REPLY request. */ message *m; static int reqid = 0; struct vfs_request_node *reqnode; reqid++; assert(statelen <= STATELEN); if(!SLABALLOC(reqnode)) { printf("vfs_request: no memory for request node\n"); return ENOMEM; } m = &reqnode->reqmsg; m->m_type = VFS_VMCALL; m->VFS_VMCALL_REQ = reqno; m->VFS_VMCALL_FD = fd; m->VFS_VMCALL_REQID = reqid; m->VFS_VMCALL_ENDPOINT = vmp->vm_endpoint; m->VFS_VMCALL_OFFSET_LO = ex64lo(offset); m->VFS_VMCALL_OFFSET_HI = ex64hi(offset); m->VFS_VMCALL_LENGTH = len; reqnode->who = vmp->vm_endpoint; reqnode->req_id = reqid; reqnode->next = first_queued; reqnode->callback = reply_callback; reqnode->opaque = cbarg; if(state) memcpy(reqnode->reqstate, state, statelen); first_queued = reqnode; /* Send the request message if none pending. */ if(!active) activate(); return OK; }
/*===========================================================================* * req_bpeek * *===========================================================================*/ int req_bpeek(endpoint_t fs_e, dev_t dev, u64_t pos, unsigned int num_of_bytes) { message m; memset(&m, 0, sizeof(m)); /* Fill in request message */ m.m_type = REQ_BPEEK; m.REQ_DEV2 = dev; m.REQ_SEEK_POS_LO = ex64lo(pos); m.REQ_SEEK_POS_HI = ex64hi(pos); m.REQ_NBYTES = num_of_bytes; /* Send/rec request */ return fs_sendrec(fs_e, &m); return(OK); }
/*===========================================================================* * get_range * *===========================================================================*/ static size_t get_range(struct fbd_rule *rule, u64_t pos, size_t *size, u64_t *skip) { /* Compute the range within the given request range that is affected * by the given rule, and optionally the number of bytes preceding * the range that are also affected by the rule. */ u64_t delta; size_t off; int to_eof; to_eof = cmp64(rule->start, rule->end) >= 0; if (cmp64(pos, rule->start) > 0) { if (skip != NULL) *skip = sub64(pos, rule->start); off = 0; } else { if (skip != NULL) *skip = cvu64(0); delta = sub64(rule->start, pos); assert(ex64hi(delta) == 0); off = ex64lo(delta); } if (!to_eof) { assert(cmp64(pos, rule->end) < 0); delta = sub64(rule->end, pos); if (cmp64u(delta, *size) < 0) *size = ex64lo(delta); } assert(*size > off); *size -= off; return off; }
/*===========================================================================* * fbd_transfer_direct * *===========================================================================*/ static ssize_t fbd_transfer_direct(int do_write, u64_t position, endpoint_t endpt, iovec_t *iov, unsigned int count, int flags) { /* Forward the entire transfer request, without any intervention. */ iovec_s_t iovec[NR_IOREQS]; cp_grant_id_t grant; message m; int i, r; for (i = 0; i < count; i++) { iovec[i].iov_size = iov[i].iov_size; iovec[i].iov_grant = cpf_grant_indirect(driver_endpt, endpt, iov[i].iov_addr); assert(iovec[i].iov_grant != GRANT_INVALID); } grant = cpf_grant_direct(driver_endpt, (vir_bytes) iovec, count * sizeof(iovec[0]), CPF_READ); assert(grant != GRANT_INVALID); m.m_type = do_write ? BDEV_SCATTER : BDEV_GATHER; m.BDEV_MINOR = driver_minor; m.BDEV_COUNT = count; m.BDEV_GRANT = grant; m.BDEV_FLAGS = flags; m.BDEV_ID = 0; m.BDEV_POS_LO = ex64lo(position); m.BDEV_POS_HI = ex64hi(position); if ((r = sendrec(driver_endpt, &m)) != OK) panic("sendrec to driver failed (%d)\n", r); if (m.m_type != BDEV_REPLY) panic("invalid reply from driver (%d)\n", m.m_type); cpf_revoke(grant); for (i = 0; i < count; i++) cpf_revoke(iovec[i].iov_grant); return m.BDEV_STATUS; }
static void dump_entry(btrace_entry *entry) { switch (entry->request) { case BTREQ_OPEN: printf("OPEN"); break; case BTREQ_CLOSE: printf("CLOSE"); break; case BTREQ_READ: printf("READ"); break; case BTREQ_WRITE: printf("WRITE"); break; case BTREQ_GATHER: printf("GATHER"); break; case BTREQ_SCATTER: printf("SCATTER"); break; case BTREQ_IOCTL: printf("IOCTL"); break; } printf(" request\n"); switch (entry->request) { case BTREQ_OPEN: printf("- access:\t%x\n", entry->size); break; case BTREQ_READ: case BTREQ_WRITE: case BTREQ_GATHER: case BTREQ_SCATTER: printf("- position:\t%08lx%08lx\n", ex64hi(entry->position), ex64lo(entry->position)); printf("- size:\t\t%u\n", entry->size); printf("- flags:\t%x\n", entry->flags); break; case BTREQ_IOCTL: printf("- request:\t%08x\n", entry->size); break; } printf("- start:\t%u us\n", entry->start_time); printf("- finish:\t%u us\n", entry->finish_time); if (entry->result == BTRES_INPROGRESS) printf("- result:\t(in progress)\n"); else printf("- result:\t%d\n", entry->result); printf("\n"); }
/*===========================================================================* * req_breadwrite * *===========================================================================*/ PUBLIC int req_breadwrite( endpoint_t fs_e, endpoint_t user_e, dev_t dev, u64_t pos, unsigned int num_of_bytes, char *user_addr, int rw_flag, u64_t *new_posp, unsigned int *cum_iop ) { int r; cp_grant_id_t grant_id; message m; grant_id = cpf_grant_magic(fs_e, user_e, (vir_bytes) user_addr, num_of_bytes, (rw_flag == READING ? CPF_WRITE : CPF_READ)); if(grant_id == -1) panic("req_breadwrite: cpf_grant_magic failed"); /* Fill in request message */ m.m_type = rw_flag == READING ? REQ_BREAD : REQ_BWRITE; m.REQ_DEV2 = dev; m.REQ_GRANT = grant_id; m.REQ_SEEK_POS_LO = ex64lo(pos); m.REQ_SEEK_POS_HI = ex64hi(pos); m.REQ_NBYTES = num_of_bytes; /* Send/rec request */ r = fs_sendrec(fs_e, &m); cpf_revoke(grant_id); if (r != OK) return(r); /* Fill in response structure */ *new_posp = make64(m.RES_SEEK_POS_LO, m.RES_SEEK_POS_HI); *cum_iop = m.RES_NBYTES; return(OK); }
PUBLIC void print_proc(struct proc *pp) { struct proc *depproc = NULL; endpoint_t dep; printf("%d: %s %d prio %d time %d/%d cycles 0x%x%08x cpu %2d " "cr3 0x%lx rts %s misc %s sched %s ", proc_nr(pp), pp->p_name, pp->p_endpoint, pp->p_priority, pp->p_user_time, pp->p_sys_time, ex64hi(pp->p_cycles), ex64lo(pp->p_cycles), pp->p_cpu, pp->p_seg.p_cr3, rtsflagstr(pp->p_rts_flags), miscflagstr(pp->p_misc_flags), schedulerstr(pp->p_scheduler)); print_sigmgr(pp); dep = P_BLOCKEDON(pp); if(dep != NONE) { printf(" blocked on: "); print_endpoint(dep); } printf("\n"); }
int startsim(void){ message m; int i,j=0,piReady = -1; u64_t cpuTimeDiff; FILE *fp; fp = fopen("/home/out","w"); for(i=0;i<HISTORY;i++){ pInfoPtrs[i] = (struct pi *) &pInfo[i][0]; } for(i=0;i<HISTORY;i++){ pQhPtrs[i] = (struct qh*) &pQh[i][0]; } /* Copy the pointer arrays so that you can go backward and forward through the history */ struct pi *pInfoPtrsCopy[HISTORY]; struct qh *pQhPtrsCopy[HISTORY]; for(i=0;i<HISTORY;i++){ pInfoPtrsCopy[i] = pInfoPtrs[i]; pQhPtrsCopy[i] = pQhPtrs[i]; } m.m1_p1 = (char *) &pInfoPtrs; m.m1_p2 = (char *) &piReady; m.m1_i2 = SELF; m.m1_i3 = HISTORY; m.m2_p1 = (char *) &pQhPtrs; m.m3_p1 = (char *) &cpuFreq; int error = _syscall(PM_PROC_NR,STARTRECORD,&m); procs(); for(j;j<HISTORY;j++){ while(piReady < j){ } if(j==0){ fprintf(fp,"CPU frequency is: %lu Mhz\n",div64u(cpuFreq, 1000000)); } printf("Simulation is %d%% complete.\n",(j*2)+2); fprintf(fp,"Proc Table %d\n\n",j); fprintf(fp,"Queue heads: "); for(i=0;i<NR_SCHED_QUEUES;i++){ if(pQhPtrsCopy[j]->p_endpoint!=-1){ fprintf(fp,"Queue: %d %d ",i,pQhPtrsCopy[j]->p_endpoint); } pQhPtrsCopy[j]++; } fprintf(fp,"\n\n"); pQhPtrsCopy[j] = pQhPtrs[j]; /*Write out the runable queues in order */ for(i=0; i<NR_SCHED_QUEUES; i++){ fprintf(fp,"Priority Queue %d: ",i); if(pQhPtrsCopy[j]->p_endpoint != -1){ printQ(pInfoPtrsCopy[j],pQhPtrsCopy[j]->p_endpoint,fp); } else{ fprintf(fp,"\n"); } pQhPtrsCopy[j]++; } pQhPtrsCopy[j] = pQhPtrs[j]; /* Reset the Qh Pointers */ for (i=0;i<ALL_PROCS;i++){ if (!(pInfoPtrsCopy[j]->p_rts_flags == RTS_SLOT_FREE)){ if(j>0){ cpuTimeDiff = sub64(pInfoPtrsCopy[j]->p_cycles,pInfoPtrsCopy[j-1]->p_cycles); } fprintf(fp,"Process: %s, Endpoint: %d, Enter queue: %lu%lu, Time in Queue: %lu%lu, Dequeues: %lu, IPC Sync: %lu, IPC Async: %lu,Preempted: %lu,RTS: %x\n\t\t, Priority: %d, Next: %s Endpoint: %d, User time: %d, Sys Time: %d, CPU Cycles Elaps: %lu%lu\n", pInfoPtrsCopy[j]->p_name,pInfoPtrsCopy[j]->p_endpoint,ex64hi(pInfoPtrsCopy[j]->p_times.enter_queue),ex64lo(pInfoPtrsCopy[j]->p_times.enter_queue), ex64hi(pInfoPtrsCopy[j]->p_times.time_in_queue),ex64lo(pInfoPtrsCopy[j]->p_times.time_in_queue), pInfoPtrsCopy[j]->p_times.dequeues,pInfoPtrsCopy[j]->p_times.ipc_sync,pInfoPtrsCopy[j]->p_times.ipc_async, pInfoPtrsCopy[j]->p_times.preempted,pInfoPtrsCopy[j]->p_rts_flags,pInfoPtrsCopy[j]->p_priority, pInfoPtrsCopy[j]->p_nextready, pInfoPtrsCopy[j]->p_nextready_endpoint,pInfoPtrsCopy[j]->p_user_time,pInfoPtrsCopy[j]->p_sys_time,ex64hi(cpuTimeDiff), ex64lo(cpuTimeDiff)); } pInfoPtrsCopy[j]++; if(j>0){ pInfoPtrsCopy[j-1]++; } } pInfoPtrsCopy[j] = pInfoPtrs[j]; } m.m1_i3 = -1; _syscall(PM_PROC_NR,STARTRECORD,&m); return(0); }
PUBLIC void context_stop(struct proc * p) { u64_t tsc, tsc_delta; u64_t * __tsc_ctr_switch = get_cpulocal_var_ptr(tsc_ctr_switch); #ifdef CONFIG_SMP unsigned cpu = cpuid; /* * This function is called only if we switch from kernel to user or idle * or back. Therefore this is a perfect location to place the big kernel * lock which will hopefully disappear soon. * * If we stop accounting for KERNEL we must unlock the BKL. If account * for IDLE we must not hold the lock */ if (p == proc_addr(KERNEL)) { u64_t tmp; read_tsc_64(&tsc); tmp = sub64(tsc, *__tsc_ctr_switch); kernel_ticks[cpu] = add64(kernel_ticks[cpu], tmp); p->p_cycles = add64(p->p_cycles, tmp); BKL_UNLOCK(); } else { u64_t bkl_tsc; atomic_t succ; read_tsc_64(&bkl_tsc); /* this only gives a good estimate */ succ = big_kernel_lock.val; BKL_LOCK(); read_tsc_64(&tsc); bkl_ticks[cpu] = add64(bkl_ticks[cpu], sub64(tsc, bkl_tsc)); bkl_tries[cpu]++; bkl_succ[cpu] += !(!(succ == 0)); p->p_cycles = add64(p->p_cycles, sub64(tsc, *__tsc_ctr_switch)); #ifdef CONFIG_SMP /* * Since at the time we got a scheduling IPI we might have been * waiting for BKL already, we may miss it due to a similar IPI to * the cpu which is already waiting for us to handle its. This * results in a live-lock of these two cpus. * * Therefore we always check if there is one pending and if so, * we handle it straight away so the other cpu can continue and * we do not deadlock. */ smp_sched_handler(); #endif } #else read_tsc_64(&tsc); p->p_cycles = add64(p->p_cycles, sub64(tsc, *__tsc_ctr_switch)); #endif tsc_delta = sub64(tsc, *__tsc_ctr_switch); if(kbill_ipc) { kbill_ipc->p_kipc_cycles = add64(kbill_ipc->p_kipc_cycles, tsc_delta); kbill_ipc = NULL; } if(kbill_kcall) { kbill_kcall->p_kcall_cycles = add64(kbill_kcall->p_kcall_cycles, tsc_delta); kbill_kcall = NULL; } /* * deduct the just consumed cpu cycles from the cpu time left for this * process during its current quantum. Skip IDLE and other pseudo kernel * tasks */ if (p->p_endpoint >= 0) { #if DEBUG_RACE make_zero64(p->p_cpu_time_left); #else /* if (tsc_delta < p->p_cpu_time_left) in 64bit */ if (ex64hi(tsc_delta) < ex64hi(p->p_cpu_time_left) || (ex64hi(tsc_delta) == ex64hi(p->p_cpu_time_left) && ex64lo(tsc_delta) < ex64lo(p->p_cpu_time_left))) p->p_cpu_time_left = sub64(p->p_cpu_time_left, tsc_delta); else { make_zero64(p->p_cpu_time_left); } #endif } *__tsc_ctr_switch = tsc; }
/*===========================================================================* * do_fcntl * *===========================================================================*/ PUBLIC int do_fcntl() { /* Perform the fcntl(fd, request, ...) system call. */ register struct filp *f; int new_fd, r, fl; struct filp *dummy; /* Is the file descriptor valid? */ if ((f = get_filp(m_in.fd)) == NULL) return(err_code); switch (m_in.request) { case F_DUPFD: /* This replaces the old dup() system call. */ if (m_in.addr < 0 || m_in.addr >= OPEN_MAX) return(EINVAL); if ((r = get_fd(m_in.addr, 0, &new_fd, &dummy)) != OK) return(r); f->filp_count++; fp->fp_filp[new_fd] = f; return(new_fd); case F_GETFD: /* Get close-on-exec flag (FD_CLOEXEC in POSIX Table 6-2). */ return( FD_ISSET(m_in.fd, &fp->fp_cloexec_set) ? FD_CLOEXEC : 0); case F_SETFD: /* Set close-on-exec flag (FD_CLOEXEC in POSIX Table 6-2). */ if(m_in.addr & FD_CLOEXEC) FD_SET(m_in.fd, &fp->fp_cloexec_set); else FD_CLR(m_in.fd, &fp->fp_cloexec_set); return(OK); case F_GETFL: /* Get file status flags (O_NONBLOCK and O_APPEND). */ fl = f->filp_flags & (O_NONBLOCK | O_APPEND | O_ACCMODE); return(fl); case F_SETFL: /* Set file status flags (O_NONBLOCK and O_APPEND). */ fl = O_NONBLOCK | O_APPEND | O_REOPEN; f->filp_flags = (f->filp_flags & ~fl) | (m_in.addr & fl); return(OK); case F_GETLK: case F_SETLK: case F_SETLKW: /* Set or clear a file lock. */ r = lock_op(f, m_in.request); return(r); case F_FREESP: { /* Free a section of a file. Preparation is done here, actual freeing * in freesp_inode(). */ off_t start, end; struct flock flock_arg; signed long offset; /* Check if it's a regular file. */ if((f->filp_vno->v_mode & I_TYPE) != I_REGULAR) return(EINVAL); if (!(f->filp_mode & W_BIT)) return(EBADF); /* Copy flock data from userspace. */ if((r = sys_datacopy(who_e, (vir_bytes) m_in.name1, SELF, (vir_bytes) &flock_arg, (phys_bytes) sizeof(flock_arg))) != OK) return(r); /* Convert starting offset to signed. */ offset = (signed long) flock_arg.l_start; /* Figure out starting position base. */ switch(flock_arg.l_whence) { case SEEK_SET: start = 0; break; case SEEK_CUR: if (ex64hi(f->filp_pos) != 0) panic("do_fcntl: position in file too high"); start = ex64lo(f->filp_pos); break; case SEEK_END: start = f->filp_vno->v_size; break; default: return EINVAL; } /* Check for overflow or underflow. */ if(offset > 0 && start + offset < start) return EINVAL; if(offset < 0 && start + offset > start) return EINVAL; start += offset; if(start < 0) return EINVAL; if(flock_arg.l_len != 0) { if(start >= f->filp_vno->v_size) return EINVAL; end = start + flock_arg.l_len; if(end <= start) return EINVAL; if(end > f->filp_vno->v_size) end = f->filp_vno->v_size; } else { end = 0; } r = req_ftrunc(f->filp_vno->v_fs_e, f->filp_vno->v_inode_nr, start, end); if(r == OK && flock_arg.l_len == 0) f->filp_vno->v_size = start; return(r); } default: return(EINVAL); } }
/*===========================================================================* * m_transfer * *===========================================================================*/ static int m_transfer( endpoint_t endpt, /* endpoint of grant owner */ int opcode, /* DEV_GATHER_S or DEV_SCATTER_S */ u64_t pos64, /* offset on device to read or write */ iovec_t *iov, /* pointer to read or write request vector */ unsigned int nr_req, /* length of request vector */ endpoint_t UNUSED(user_endpt),/* endpoint of user process */ unsigned int UNUSED(flags) ) { /* Read or write one the driver's character devices. */ unsigned count, left, chunk; vir_bytes vir_offset = 0; struct device *dv; unsigned long dv_size; int s, r; off_t position; cp_grant_id_t grant; vir_bytes dev_vaddr; /* ZERO_DEV and NULL_DEV are infinite in size. */ if (m_device != ZERO_DEV && m_device != NULL_DEV && ex64hi(pos64) != 0) return OK; /* Beyond EOF */ position= cv64ul(pos64); /* Get minor device number and check for /dev/null. */ dv = &m_geom[m_device]; dv_size = cv64ul(dv->dv_size); dev_vaddr = m_vaddrs[m_device]; while (nr_req > 0) { /* How much to transfer and where to / from. */ count = iov->iov_size; grant = (cp_grant_id_t) iov->iov_addr; switch (m_device) { /* No copying; ignore request. */ case NULL_DEV: if (opcode == DEV_GATHER_S) return(OK); /* always at EOF */ break; /* Virtual copying. For kernel memory. */ default: case KMEM_DEV: if(!dev_vaddr || dev_vaddr == (vir_bytes) MAP_FAILED) { printf("MEM: dev %d not initialized\n", m_device); return EIO; } if (position >= dv_size) return(OK); /* check for EOF */ if (position + count > dv_size) count = dv_size - position; if (opcode == DEV_GATHER_S) { /* copy actual data */ r=sys_safecopyto(endpt, grant, vir_offset, dev_vaddr + position, count); } else { r=sys_safecopyfrom(endpt, grant, vir_offset, dev_vaddr + position, count); } if(r != OK) { panic("I/O copy failed: %d", r); } break; /* Physical copying. Only used to access entire memory. * Transfer one 'page window' at a time. */ case MEM_DEV: { u32_t pagestart, page_off; static u32_t pagestart_mapped; static int any_mapped = 0; static char *vaddr; int r; u32_t subcount; phys_bytes mem_phys; if (position >= dv_size) return(OK); /* check for EOF */ if (position + count > dv_size) count = dv_size - position; mem_phys = position; page_off = mem_phys % PAGE_SIZE; pagestart = mem_phys - page_off; /* All memory to the map call has to be page-aligned. * Don't have to map same page over and over. */ if(!any_mapped || pagestart_mapped != pagestart) { if(any_mapped) { if(vm_unmap_phys(SELF, vaddr, PAGE_SIZE) != OK) panic("vm_unmap_phys failed"); any_mapped = 0; } vaddr = vm_map_phys(SELF, (void *) pagestart, PAGE_SIZE); if(vaddr == MAP_FAILED) r = ENOMEM; else r = OK; if(r != OK) { printf("memory: vm_map_phys failed\n"); return r; } any_mapped = 1; pagestart_mapped = pagestart; } /* how much to be done within this page. */ subcount = PAGE_SIZE-page_off; if(subcount > count) subcount = count; if (opcode == DEV_GATHER_S) { /* copy data */ s=sys_safecopyto(endpt, grant, vir_offset, (vir_bytes) vaddr+page_off, subcount); } else { s=sys_safecopyfrom(endpt, grant, vir_offset, (vir_bytes) vaddr+page_off, subcount); } if(s != OK) return s; count = subcount; break; } /* Null byte stream generator. */ case ZERO_DEV: if (opcode == DEV_GATHER_S) { size_t suboffset = 0; left = count; while (left > 0) { chunk = (left > ZERO_BUF_SIZE) ? ZERO_BUF_SIZE : left; s=sys_safecopyto(endpt, grant, vir_offset+suboffset, (vir_bytes) dev_zero, chunk); if(s != OK) return s; left -= chunk; suboffset += chunk; } } break; } /* Book the number of bytes transferred. */ position += count; vir_offset += count; if ((iov->iov_size -= count) == 0) { iov++; nr_req--; vir_offset = 0; } } return(OK); }
/*===========================================================================* * do_fcntl * *===========================================================================*/ int do_fcntl() { /* Perform the fcntl(fd, request, ...) system call. */ register struct filp *f; int new_fd, fl, r = OK, fcntl_req, fcntl_argx; tll_access_t locktype; scratch(fp).file.fd_nr = job_m_in.fd; scratch(fp).io.io_buffer = job_m_in.buffer; scratch(fp).io.io_nbytes = job_m_in.nbytes; /* a.k.a. m_in.request */ fcntl_req = job_m_in.request; fcntl_argx = job_m_in.addr; /* Is the file descriptor valid? */ locktype = (fcntl_req == F_FREESP) ? VNODE_WRITE : VNODE_READ; if ((f = get_filp(scratch(fp).file.fd_nr, locktype)) == NULL) return(err_code); switch (fcntl_req) { case F_DUPFD: /* This replaces the old dup() system call. */ if (fcntl_argx < 0 || fcntl_argx >= OPEN_MAX) r = EINVAL; else if ((r = get_fd(fcntl_argx, 0, &new_fd, NULL)) == OK) { f->filp_count++; fp->fp_filp[new_fd] = f; FD_SET(new_fd, &fp->fp_filp_inuse); r = new_fd; } break; case F_GETFD: /* Get close-on-exec flag (FD_CLOEXEC in POSIX Table 6-2). */ r = 0; if (FD_ISSET(scratch(fp).file.fd_nr, &fp->fp_cloexec_set)) r = FD_CLOEXEC; break; case F_SETFD: /* Set close-on-exec flag (FD_CLOEXEC in POSIX Table 6-2). */ if (fcntl_argx & FD_CLOEXEC) FD_SET(scratch(fp).file.fd_nr, &fp->fp_cloexec_set); else FD_CLR(scratch(fp).file.fd_nr, &fp->fp_cloexec_set); break; case F_GETFL: /* Get file status flags (O_NONBLOCK and O_APPEND). */ fl = f->filp_flags & (O_NONBLOCK | O_APPEND | O_ACCMODE); r = fl; break; case F_SETFL: /* Set file status flags (O_NONBLOCK and O_APPEND). */ fl = O_NONBLOCK | O_APPEND | O_REOPEN; f->filp_flags = (f->filp_flags & ~fl) | (fcntl_argx & fl); break; case F_GETLK: case F_SETLK: case F_SETLKW: /* Set or clear a file lock. */ r = lock_op(f, fcntl_req); break; case F_FREESP: { /* Free a section of a file */ off_t start, end; struct flock flock_arg; signed long offset; /* Check if it's a regular file. */ if (!S_ISREG(f->filp_vno->v_mode)) r = EINVAL; else if (!(f->filp_mode & W_BIT)) r = EBADF; else /* Copy flock data from userspace. */ r = sys_datacopy(who_e, (vir_bytes) scratch(fp).io.io_buffer, SELF, (vir_bytes) &flock_arg, sizeof(flock_arg)); if (r != OK) break; /* Convert starting offset to signed. */ offset = (signed long) flock_arg.l_start; /* Figure out starting position base. */ switch(flock_arg.l_whence) { case SEEK_SET: start = 0; break; case SEEK_CUR: if (ex64hi(f->filp_pos) != 0) panic("do_fcntl: position in file too high"); start = ex64lo(f->filp_pos); break; case SEEK_END: start = f->filp_vno->v_size; break; default: r = EINVAL; } if (r != OK) break; /* Check for overflow or underflow. */ if (offset > 0 && start + offset < start) r = EINVAL; else if (offset < 0 && start + offset > start) r = EINVAL; else { start += offset; if (start < 0) r = EINVAL; } if (r != OK) break; if (flock_arg.l_len != 0) { if (start >= f->filp_vno->v_size) r = EINVAL; else if ((end = start + flock_arg.l_len) <= start) r = EINVAL; else if (end > f->filp_vno->v_size) end = f->filp_vno->v_size; } else { end = 0; } if (r != OK) break; r = req_ftrunc(f->filp_vno->v_fs_e, f->filp_vno->v_inode_nr,start,end); if (r == OK && flock_arg.l_len == 0) f->filp_vno->v_size = start; break; } case F_GETNOSIGPIPE: /* POSIX: return value other than -1 is flag is set, else -1 */ r = -1; if (f->filp_flags & O_NOSIGPIPE) r = 0; break; case F_SETNOSIGPIPE: fl = (O_NOSIGPIPE); f->filp_flags = (f->filp_flags & ~fl) | (fcntl_argx & fl); break; default: r = EINVAL; } unlock_filp(f); return(r); }
/*===========================================================================* * m_block_transfer * *===========================================================================*/ static int m_block_transfer( dev_t minor, /* minor device number */ int do_write, /* read or write? */ u64_t pos64, /* offset on device to read or write */ endpoint_t endpt, /* process doing the request */ iovec_t *iov, /* pointer to read or write request vector */ unsigned int nr_req, /* length of request vector */ int UNUSED(flags) /* transfer flags */ ) { /* Read or write one the driver's block devices. */ unsigned count; vir_bytes vir_offset = 0; struct device *dv; unsigned long dv_size; int r; off_t position; vir_bytes dev_vaddr; cp_grant_id_t grant; ssize_t total = 0; /* Get minor device information. */ if ((dv = m_block_part(minor)) == NULL) return(ENXIO); dv_size = cv64ul(dv->dv_size); dev_vaddr = m_vaddrs[minor]; if (ex64hi(pos64) != 0) return OK; /* Beyond EOF */ position= cv64ul(pos64); while (nr_req > 0) { /* How much to transfer and where to / from. */ count = iov->iov_size; grant = (cp_grant_id_t) iov->iov_addr; /* Virtual copying. For RAM disks and internal FS. */ if(!dev_vaddr || dev_vaddr == (vir_bytes) MAP_FAILED) { printf("MEM: dev %d not initialized\n", minor); return EIO; } if (position >= dv_size) return(total); /* check for EOF */ if (position + count > dv_size) count = dv_size - position; if (!do_write) { /* copy actual data */ r=sys_safecopyto(endpt, grant, vir_offset, dev_vaddr + position, count); } else { r=sys_safecopyfrom(endpt, grant, vir_offset, dev_vaddr + position, count); } if(r != OK) { panic("I/O copy failed: %d", r); } /* Book the number of bytes transferred. */ position += count; vir_offset += count; total += count; if ((iov->iov_size -= count) == 0) { iov++; nr_req--; vir_offset = 0; } } return(total); }
/*===========================================================================* * m_block_ioctl * *===========================================================================*/ static int m_block_ioctl(dev_t minor, unsigned int request, endpoint_t endpt, cp_grant_id_t grant) { /* I/O controls for the block devices of the memory driver. Currently there is * one I/O control specific to the memory driver: * - MIOCRAMSIZE: to set the size of the RAM disk. */ struct device *dv; u32_t ramdev_size; int s; void *mem; if (request != MIOCRAMSIZE) return EINVAL; /* Someone wants to create a new RAM disk with the given size. * A ramdisk can be created only once, and only on RAM disk device. */ if ((dv = m_block_part(minor)) == NULL) return ENXIO; if((minor < RAM_DEV_FIRST || minor > RAM_DEV_LAST) && minor != RAM_DEV_OLD) { printf("MEM: MIOCRAMSIZE: %d not a ramdisk\n", minor); return EINVAL; } /* Get request structure */ s= sys_safecopyfrom(endpt, grant, 0, (vir_bytes)&ramdev_size, sizeof(ramdev_size)); if (s != OK) return s; if(m_vaddrs[minor] && !cmp64(dv->dv_size, cvul64(ramdev_size))) { return(OK); } /* openct is 1 for the ioctl(). */ if(openct[minor] != 1) { printf("MEM: MIOCRAMSIZE: %d in use (count %d)\n", minor, openct[minor]); return(EBUSY); } if(m_vaddrs[minor]) { u32_t size; if(ex64hi(dv->dv_size)) { panic("huge old ramdisk"); } size = ex64lo(dv->dv_size); minix_munmap((void *) m_vaddrs[minor], size); m_vaddrs[minor] = (vir_bytes) NULL; } #if DEBUG printf("MEM:%d: allocating ramdisk of size 0x%x\n", minor, ramdev_size); #endif /* Try to allocate a piece of memory for the RAM disk. */ if((mem = minix_mmap(NULL, ramdev_size, PROT_READ|PROT_WRITE, MAP_PREALLOC|MAP_ANON, -1, 0)) == MAP_FAILED) { printf("MEM: failed to get memory for ramdisk\n"); return(ENOMEM); } m_vaddrs[minor] = (vir_bytes) mem; dv->dv_size = cvul64(ramdev_size); return(OK); }
/*===========================================================================* * fs_breadwrite_o * *===========================================================================*/ PUBLIC int fs_breadwrite_o(void) { int r, usr, rw_flag, chunk, block_size; int nrbytes; u64_t position; unsigned int off, cum_io; mode_t mode_word; int completed, r2 = OK; char *user_addr; /* Pseudo inode for rw_chunk */ struct inode rip; r = OK; /* Get the values from the request message */ rw_flag = (fs_m_in.m_type == REQ_BREAD_O ? READING : WRITING); usr = fs_m_in.REQ_XFD_WHO_E; position = make64(fs_m_in.REQ_XFD_POS_LO, fs_m_in.REQ_XFD_POS_HI); nrbytes = (unsigned) fs_m_in.REQ_XFD_NBYTES; user_addr = fs_m_in.REQ_XFD_USER_ADDR; block_size = get_block_size(fs_m_in.REQ_XFD_BDEV); rip.i_zone[0] = fs_m_in.REQ_XFD_BDEV; rip.i_mode = I_BLOCK_SPECIAL; rip.i_size = 0; rdwt_err = OK; /* set to EIO if disk error occurs */ cum_io = 0; /* Split the transfer into chunks that don't span two blocks. */ while (nrbytes != 0) { off = rem64u(position, block_size); /* offset in blk*/ chunk = MIN(nrbytes, block_size - off); if (chunk < 0) chunk = block_size - off; /* Read or write 'chunk' bytes. */ r = rw_chunk(&rip, position, off, chunk, (unsigned) nrbytes, rw_flag, user_addr, D, usr, block_size, &completed); if (r != OK) break; /* EOF reached */ if (rdwt_err < 0) break; /* Update counters and pointers. */ user_addr += chunk; /* user buffer address */ nrbytes -= chunk; /* bytes yet to be read */ cum_io += chunk; /* bytes read so far */ position= add64ul(position, chunk); /* position within the file */ } fs_m_out.RES_XFD_POS_LO = ex64lo(position); fs_m_out.RES_XFD_POS_HI = ex64hi(position); if (rdwt_err != OK) r = rdwt_err; /* check for disk error */ if (rdwt_err == END_OF_FILE) r = OK; fs_m_out.RES_XFD_CUM_IO = cum_io; return(r); }
/*===========================================================================* * read_write * *===========================================================================*/ int read_write(u64_t pos, char *bufa, char *bufb, size_t *sizep, int request) { iovec_s_t vectors[2][NR_IOREQS]; message m1, m2; cp_grant_id_t gids[2]; int r, both, count; gids[0] = gids[1] = GRANT_INVALID; /* Send two requests only if mirroring is enabled and the given request * is either FLT_READ2 or FLT_WRITE. */ both = (USE_MIRROR && request != FLT_READ); count = paired_grant(bufa, bufb, request, gids, vectors, *sizep, both); memset(&m1, 0, sizeof(m1)); m1.m_type = (request == FLT_WRITE) ? BDEV_SCATTER : BDEV_GATHER; m1.BDEV_COUNT = count; m1.BDEV_POS_LO = ex64lo(pos); m1.BDEV_POS_HI = ex64hi(pos); m2 = m1; m1.BDEV_GRANT = gids[0]; m2.BDEV_GRANT = gids[1]; r = paired_sendrec(&m1, &m2, both); paired_revoke(gids, vectors, count, both); if(r != OK) { #if DEBUG if (r != RET_REDO) printf("Filter: paired_sendrec returned %d\n", r); #endif return r; } if (m1.m_type != BDEV_REPLY || m1.BDEV_STATUS < 0) { printf("Filter: unexpected/invalid reply from main driver: " "(%x, %d)\n", m1.m_type, m1.BDEV_STATUS); return bad_driver(DRIVER_MAIN, BD_PROTO, (m1.m_type == BDEV_REPLY) ? m1.BDEV_STATUS : EFAULT); } if (m1.BDEV_STATUS != (ssize_t) *sizep) { printf("Filter: truncated reply from main driver\n"); /* If the driver returned a value *larger* than we requested, * OR if we did NOT exceed the disk size, then we should * report the driver for acting strangely! */ if (m1.BDEV_STATUS > (ssize_t) *sizep || cmp64(add64u(pos, m1.BDEV_STATUS), disk_size) < 0) return bad_driver(DRIVER_MAIN, BD_PROTO, EFAULT); /* Return the actual size. */ *sizep = m1.BDEV_STATUS; } if (both) { if (m2.m_type != BDEV_REPLY || m2.BDEV_STATUS < 0) { printf("Filter: unexpected/invalid reply from " "backup driver (%x, %d)\n", m2.m_type, m2.BDEV_STATUS); return bad_driver(DRIVER_BACKUP, BD_PROTO, m2.m_type == BDEV_REPLY ? m2.BDEV_STATUS : EFAULT); } if (m2.BDEV_STATUS != (ssize_t) *sizep) { printf("Filter: truncated reply from backup driver\n"); /* As above */ if (m2.BDEV_STATUS > (ssize_t) *sizep || cmp64(add64u(pos, m2.BDEV_STATUS), disk_size) < 0) return bad_driver(DRIVER_BACKUP, BD_PROTO, EFAULT); /* Return the actual size. */ if ((ssize_t) *sizep >= m2.BDEV_STATUS) *sizep = m2.BDEV_STATUS; } } return OK; }
/*===========================================================================* * do_create * *===========================================================================*/ PUBLIC int do_create() { /* Create a new file. */ char path[PATH_MAX], name[NAME_MAX+1]; struct inode *parent, *ino; struct hgfs_attr attr; hgfs_file_t handle; int r; /* We cannot create files on a read-only file system. */ if (state.read_only) return EROFS; /* Get path, name, parent inode and possibly inode for the given path. */ if ((r = get_name(m_in.REQ_GRANT, m_in.REQ_PATH_LEN, name)) != OK) return r; if (!strcmp(name, ".") || !strcmp(name, "..")) return EEXIST; if ((parent = find_inode(m_in.REQ_INODE_NR)) == NULL) return EINVAL; if ((r = verify_dentry(parent, name, path, &ino)) != OK) return r; /* Are we going to need a new inode upon success? * Then make sure there is one available before trying anything. */ if (ino == NULL || ino->i_ref > 1 || HAS_CHILDREN(ino)) { if (!have_free_inode()) { if (ino != NULL) put_inode(ino); return ENFILE; } } /* Perform the actual create call. */ r = hgfs_open(path, O_CREAT | O_EXCL | O_RDWR, m_in.REQ_MODE, &handle); if (r != OK) { /* Let's not try to be too clever with error codes here. If something * is wrong with the directory, we'll find out later anyway. */ if (ino != NULL) put_inode(ino); return r; } /* Get the created file's attributes. */ attr.a_mask = HGFS_ATTR_MODE | HGFS_ATTR_SIZE; r = hgfs_getattr(path, &attr); /* If this fails, or returns a directory, we have a problem. This * scenario is in fact possible with race conditions. * Simulate a close and return a somewhat appropriate error. */ if (r != OK || S_ISDIR(attr.a_mode)) { printf("HGFS: lost file after creation!\n"); hgfs_close(handle); if (ino != NULL) { del_dentry(ino); put_inode(ino); } return (r == OK) ? EEXIST : r; } /* We do assume that the HGFS open(O_CREAT|O_EXCL) did its job. * If we previousy found an inode, get rid of it now. It's old. */ if (ino != NULL) { del_dentry(ino); put_inode(ino); } /* Associate the open file handle with an inode, and reply with its details. */ ino = get_free_inode(); assert(ino != NULL); /* we checked before whether we had a free one */ ino->i_file = handle; ino->i_flags = I_HANDLE; add_dentry(parent, name, ino); m_out.RES_INODE_NR = INODE_NR(ino); m_out.RES_MODE = get_mode(ino, attr.a_mode); m_out.RES_FILE_SIZE_HI = ex64hi(attr.a_size); m_out.RES_FILE_SIZE_LO = ex64lo(attr.a_size); m_out.RES_UID = opt.uid; m_out.RES_GID = opt.gid; m_out.RES_DEV = NO_DEV; return OK; }