/* * Internal function to read from swap file into a page table entry */ static void readFromSwap(int swapIndex,int pagetableIndex, int writeToSwap,L4_ThreadId_t tid,L4_Fpage_t fpage) { //Initialise swap if not initialised if(!swapInitialised) { initialise_swap(); } struct page_token *token_val; page_table[pagetableIndex].read_bytes_transferred = 0; page_table[pagetableIndex].being_updated = 1; page_table[pagetableIndex].error_in_transfer = 0; for(int i=0;i<PAGESIZE/NFS_READ_SIZE;i++) { //Set the token value token_val = (struct page_token *) malloc(sizeof(struct page_token)); token_val -> pageIndex = pagetableIndex; token_val -> swapIndex = swapIndex; //Read will always be the last to reply so it always replies token_val -> send_reply = 1; token_val -> chunk_index = i; //Set bit whether the read from swap occurs after a swap write token_val -> writeToSwapIssued = writeToSwap; token_val -> destination_tid = tid; token_val -> destination_page = fpage; token_val -> source_tid = page_table[pagetableIndex].tid; token_val -> source_page = page_table[pagetableIndex].pageNo; //Issue all the nfs reads for the chunks at once nfs_read(swapcookie,swap_table[swapIndex].offset+i*NFS_READ_SIZE,NFS_READ_SIZE,pager_read_callback,(uintptr_t) token_val); } send = 0; }
/* Run the actual read request */ static void rq_read_run(NFS_ReadRequest *rq) { dprintf(2, "run NFS Read request\n"); NFS_File *nf = (NFS_File *) rq->p.vnode->extra; nfs_read(&(nf->fh), rq->pos, rq->nbyte, read_cb, rq->p.token); }
static void read_callback (void *arg, struct nfs_client *client, READ3res *result) { struct http_cache_entry *e = arg; assert( e != NULL); assert (result != NULL); assert (result->status == NFS3_OK); READ3resok *res = &result->READ3res_u.resok; assert(res->count == res->data.data_len); assert (e->hbuff != NULL); assert (e->hbuff->data != NULL ); assert (e->hbuff->len >= e->copied + res->data.data_len); memcpy (e->hbuff->data + e->copied, res->data.data_val, res->data.data_len); e->copied += res->data.data_len; // DEBUGPRINT ("got response of len %d, filesize %lu\n", // res->data.data_len, e->copied); // free arguments xdr_READ3res(&xdr_free, result); if (!res->eof) { // more data to come, read the next chunk err_t err = nfs_read(client, e->file_handle, e->copied, MAX_NFS_READ, read_callback, e); assert(err == ERR_OK); return; } /* This is the end-of-file, so deal with it. */ e->valid = 1; e->loading = 0; decrement_buff_holder_ref (e->hbuff); #ifdef PRELOAD_WEB_CACHE if (!cache_loading_phase) { handle_pending_list (e); /* done! */ return; } /* This is cache loading going on... */ printf("Copied %zu bytes for file [%s] of length: %zu\n", e->copied, e->name, e->hbuff->len); ++cache_loaded_counter; handle_cache_load_done(); #else // PRELOAD_WEB_CACHE handle_pending_list(e); /* done! */ #endif // PRELOAD_WEB_CACHE }
/** * Called by the pager. Reads a given page back into memory. * * @param page the page we wan't to read back into memory * @return SWAPPING_PENDING */ int swap_in(page_queue_item* page) { assert(page != NULL); file_table_entry* swap_fd = get_process(root_thread_g)->filetable[SWAP_FD]; assert(swap_fd != NULL); page->to_swap = 0; // to keep track of how many bytes are read TAILQ_INSERT_TAIL(&swapping_pages_head, page, entries); nfs_read(&swap_fd->file->nfs_handle, page->swap_offset+page->to_swap, BATCH_SIZE, &swap_read_callback, (int)page); return SWAPPING_PENDING; }
ssize_t read(int fd, void *buf, size_t count) { if (nfs_fd_list[fd].is_nfs == 1) { int ret; LD_NFS_DPRINTF(9, "read(fd:%d count:%d)", fd, (int)count); if ((ret = nfs_read(nfs_fd_list[fd].nfs, nfs_fd_list[fd].fh, count, buf)) < 0) { errno = -ret; return -1; } return ret; } return real_read(fd, buf, count); }
/** * Read Callback for the NFS library if we're reading a page back into memory. * Again we split the NFS calls up and always read BATCH_SIZE bytes per call. * Note that once the page is competely swapped in it is inserted back into * the page queue which holds all the active pages at any given time. * * @param token pointer to the page item * @param bytes_read should always be BATCH_SIZE * @param data pointer to the data */ static void swap_read_callback(uintptr_t token, int status, fattr_t *attr, int bytes_read, char *data) { page_queue_item* page = (page_queue_item*) token; page_table_entry* pte = pager_table_lookup(page->tid, page->virtual_address); file_table_entry* swap_fd = get_process(root_thread_g)->filetable[SWAP_FD]; if(page->process_deleted) { TAILQ_REMOVE(&swapping_pages_head, page, entries); free(page); return; } switch (status) { case NFS_OK: { assert(bytes_read == BATCH_SIZE); memcpy( ((char*)pte->address_ptr)+page->to_swap, data, bytes_read); page->to_swap += bytes_read; // swapping in complete if(page->to_swap == PAGESIZE) { // restart the thread because the page is in memory again TAILQ_REMOVE(&swapping_pages_head, page, entries); TAILQ_INSERT_TAIL(&active_pages_head, page, entries); send_ipc_reply(page->tid, L4_PAGEFAULT, 0); } else { // read next batch nfs_read(&swap_fd->file->nfs_handle, page->swap_offset+page->to_swap, BATCH_SIZE, &swap_read_callback, (int)page); } } break; default: dprintf(0, "%s: Bad NFS status (%d) from callback.\n", __FUNCTION__, status); assert(FALSE); // We could probably try to restart swapping here but since it failed before // we don't see much point in this. break; } }
//keep alive the filehandles nfs connection //by blindly doing a read 32bytes - seek back to where //we were before void CNFSConnection::keepAlive(std::string _exportPath, struct nfsfh *_pFileHandle) { uint64_t offset = 0; char buffer[32]; // this also refreshs the last accessed time for the context // true forces a cachehit regardless the context is timedout // on this call we are sure its not timedout even if the last accessed // time suggests it. struct nfs_context *pContext = getContextFromMap(_exportPath, true); if (!pContext)// this should normally never happen - paranoia pContext = m_pNfsContext; XBMC->Log(ADDON::LOG_NOTICE, "NFS: sending keep alive after %i s.",KEEP_ALIVE_TIMEOUT/2); PLATFORM::CLockObject lock(*this); nfs_lseek(pContext, _pFileHandle, 0, SEEK_CUR, &offset); nfs_read(pContext, _pFileHandle, 32, buffer); nfs_lseek(pContext, _pFileHandle, offset, SEEK_SET, &offset); }
/* * Read a small block of data from the input file. */ int fileread(oskit_addr_t file_ofs, void *buf, oskit_size_t size, oskit_size_t *out_actual) { int n, bytes_read; int offset; char *bufp = buf; int chunk_size; int readahead; #ifdef CYCLECOUNTS unsigned long long before_cycles; #endif bytes_read = 0; offset = file_ofs; while (size > 0) { chunk_size = min(NFS_READ_SIZE, size); if (kimg_readahead < 0) readahead = (size / NFS_READ_SIZE) - 1; else readahead = kimg_readahead; GETCSTAMP(before_cycles); n = nfs_read(ipaddr, nfs_port, filefh, offset, chunk_size, bufp, readahead); UPDATECSTAMP(total_readwait_cycles, before_cycles); if (n < 0) { printf("Unable to read text: %s\n", nfs_strerror(n)); return 1; /* XXX Should be an EX_ constant */ } if (n == 0) break; /* hit eof */ offset += n; bufp += n; size -= n; bytes_read += n; } *out_actual = bytes_read; return 0; }
void nfsload(length) { int err, read_size; while (length > 0) { read_size = length > NFS_READ_SIZE ? NFS_READ_SIZE : length; if ((err = nfs_read(ARP_ROOTSERVER, root_nfs_port, &kernel_handle, offset, read_size, loadpoint)) != read_size) { if (err < 0) { printf("Unable to read data: "); nfs_err(err); } longjmp(jmp_bootmenu, 1); } loadpoint += err; length -= err; offset += err; } }
static void lookup_callback (void *arg, struct nfs_client *client, LOOKUP3res *result) { LOOKUP3resok *resok = &result->LOOKUP3res_u.resok; err_t r; struct http_cache_entry *e = arg; DEBUGPRINT ("inside lookup_callback_file for file %s\n", e->name); assert(result != NULL ); /* initiate a read for every regular file */ if ( result->status == NFS3_OK && resok->obj_attributes.attributes_follow && resok->obj_attributes.post_op_attr_u.attributes.type == NF3REG) { /* FIXME: check if the file is recently modified or not. */ // resok->obj_attributes.post_op_attr_u.attributes.ctime; DEBUGPRINT("Copying %s of size %lu\n", e->name, resok->obj_attributes.post_op_attr_u.attributes.size ); /* Store the nfs directory handle in current_session (cs) */ nfs_copyfh (&e->file_handle, resok->object); /* GLOBAL: Storing the global reference for cache entry */ /* NOTE: this memory is freed in reset_cache_entry() */ /* Allocate memory for holding the file-content */ /* Allocate the buff_holder */ e->hbuff = allocate_buff_holder( resok->obj_attributes.post_op_attr_u.attributes.size ); /* NOTE: this memory will be freed by decrement_buff_holder_ref */ /* increment buff_holder reference */ increment_buff_holder_ref (e->hbuff); e->hbuff->len = resok->obj_attributes.post_op_attr_u.attributes.size; /* Set the size of the how much data is read till now. */ e->copied = 0; r = nfs_read (client, e->file_handle, 0, MAX_NFS_READ, read_callback, e); assert (r == ERR_OK); // free arguments xdr_LOOKUP3res(&xdr_free, result); return; } /* Most probably the file does not exist */ DEBUGPRINT ("Error: file [%s] does not exist, or wrong type\n", e->name); #ifdef PRELOAD_WEB_CACHE if (cache_loading_phase){ ++cache_loading_probs; handle_cache_load_done(); return; } #endif // PRELOAD_WEB_CACHE if (e->conn == NULL) { /* No connection is waiting for this loading */ return; } /* as file does not exist, send all the http_conns to error page. */ error_cache->conn = e->conn; error_cache->last = e->last; handle_pending_list (error_cache); /* done! */ /* free this cache entry as it is pointing to invalid page */ e->conn = NULL; e->last = NULL; delete_cacheline_from_cachelist (e); if (e->name != NULL ) free(e->name); free(e); // free arguments xdr_LOOKUP3res(&xdr_free, result); return; } /* end function: lookup_callback_file */
/************************************************************************** LOAD - Try to get booted **************************************************************************/ load() { char *p,*q; char cfg[64]; int root_mount_port; int swap_nfs_port; int swap_mount_port; char cmd_line[80]; int err, read_size, i; long addr, broadcast; int swsize; unsigned long pad; config_buffer[0]='\0'; /* clear; bootp might fill this up */ /* Initialize this early on */ nfsdiskless.root_args.rsize = 8192; nfsdiskless.root_args.wsize = 8192; nfsdiskless.swap_args.rsize = 8192; nfsdiskless.swap_args.wsize = 8192; nfsdiskless.root_args.sotype = SOCK_DGRAM; nfsdiskless.root_args.flags = (NFSMNT_WSIZE | NFSMNT_RSIZE | NFSMNT_RESVPORT); nfsdiskless.swap_args.sotype = SOCK_DGRAM; nfsdiskless.swap_args.flags = (NFSMNT_WSIZE | NFSMNT_RSIZE | NFSMNT_RESVPORT); /* Find a server to get BOOTP reply from */ if (!arptable[ARP_CLIENT].ipaddr || !arptable[ARP_SERVER].ipaddr) { printf("\nSearching for server...\n"); if (!bootp()) { printf("No Server found.\n"); longjmp(jmp_bootmenu,1); } } printf("My IP %I, Server IP %I, GW IP %I\n", arptable[ARP_CLIENT].ipaddr, arptable[ARP_SERVER].ipaddr, arptable[ARP_GATEWAY].ipaddr); #ifdef MDEBUG printf("\n=>>"); getchar(); #endif /*** check if have got info from bootp ***/ if (config_buffer[0]) goto cfg_done; #ifndef NO_TFTP /* Now use TFTP to load configuration file */ sprintf(cfg,"/tftpboot/freebsd.%I",arptable[ARP_CLIENT].ipaddr); if (tftp(cfg) || tftp(cfg+10)) goto cfg_done; cfg[17]='\0'; if (tftp(cfg) || tftp(cfg+10)) goto cfg_done; sprintf(cfg,"/tftpboot/cfg.%I",arptable[ARP_CLIENT].ipaddr); if (tftp(cfg) || tftp(cfg+10)) goto cfg_done; #endif /* not found; using default values... */ sprintf(config_buffer,"rootfs %I:/usr/diskless_root", arptable[ARP_SERVER].ipaddr); printf("Unable to load config file, guessing:\n\t%s\n", config_buffer); cfg_done: #ifdef MDEBUG printf("\n=>>"); getchar(); #endif p = config_buffer; while(*p) { q = cmd_line; while ((*p != '\n') && (*p)) *(q++) = *(p++); *q = 0; printf("%s\n",cmd_line); execute(cmd_line); if (*p) p++; } #ifdef MDEBUG printf("\n=>>"); getchar(); #endif /* Check to make sure we've got a rootfs */ if (!arptable[ARP_ROOTSERVER].ipaddr) { printf("No ROOT filesystem server!\n"); longjmp(jmp_bootmenu,1); } /* Fill in nfsdiskless.myif */ sprintf(&nfsdiskless.myif.ifra_name,eth_driver); nfsdiskless.myif.ifra_addr.sa_len = sizeof(struct sockaddr); nfsdiskless.myif.ifra_addr.sa_family = AF_INET; addr = htonl(arptable[ARP_CLIENT].ipaddr); bcopy(&addr, &nfsdiskless.myif.ifra_addr.sa_data[2], 4); broadcast = (addr & netmask) | ~netmask; nfsdiskless.myif.ifra_broadaddr.sa_len = sizeof(struct sockaddr); nfsdiskless.myif.ifra_broadaddr.sa_family = AF_INET; bcopy(&broadcast, &nfsdiskless.myif.ifra_broadaddr.sa_data[2], 4); addr = htonl(arptable[ARP_GATEWAY].ipaddr); if (addr) { nfsdiskless.mygateway.sin_len = sizeof(struct sockaddr); nfsdiskless.mygateway.sin_family = AF_INET; bcopy(&addr, &nfsdiskless.mygateway.sin_addr, 4); } else { nfsdiskless.mygateway.sin_len = 0; } nfsdiskless.myif.ifra_mask.sa_len = sizeof(struct sockaddr); nfsdiskless.myif.ifra_mask.sa_family = AF_UNSPEC; bcopy(&netmask, &nfsdiskless.myif.ifra_mask.sa_data[2], 4); rpc_id = currticks(); /* Lookup NFS/MOUNTD ports for SWAP using PORTMAP */ if (arptable[ARP_SWAPSERVER].ipaddr) { char swapfs_fh[32], swapfile[32]; swap_nfs_port = rpclookup(ARP_SWAPSERVER, PROG_NFS, 2); swap_mount_port = rpclookup(ARP_SWAPSERVER, PROG_MOUNT, 1); if ((swap_nfs_port == -1) || (swap_mount_port == -1)) { printf("Unable to get SWAP NFS/MOUNT ports\n"); longjmp(jmp_bootmenu,1); } if (err = nfs_mount(ARP_SWAPSERVER, swap_mount_port, nfsdiskless.swap_hostnam, &swapfs_fh)) { printf("Unable to mount SWAP filesystem: "); nfs_err(err); longjmp(jmp_bootmenu,1); } sprintf(swapfile,"swap.%I",arptable[ARP_CLIENT].ipaddr); if (err = nfs_lookup(ARP_SWAPSERVER, swap_nfs_port, &swapfs_fh, swapfile, &nfsdiskless.swap_fh, &swsize)) { printf("Unable to open %s: ",swapfile); nfs_err(err); longjmp(jmp_bootmenu,1); } if (!nfsdiskless.swap_nblks) { nfsdiskless.swap_nblks = swsize / 1024; printf("Swap size is: %d blocks\n",nfsdiskless.swap_nblks); } nfsdiskless.swap_saddr.sin_len = sizeof(struct sockaddr_in); nfsdiskless.swap_saddr.sin_family = AF_INET; nfsdiskless.swap_saddr.sin_port = htons(swap_nfs_port); nfsdiskless.swap_saddr.sin_addr.s_addr = htonl(arptable[ARP_SWAPSERVER].ipaddr); nfsdiskless.swap_args.timeo = 10; nfsdiskless.swap_args.retrans = 100; } /* Lookup NFS/MOUNTD ports for ROOT using PORTMAP */ root_nfs_port = rpclookup(ARP_ROOTSERVER, PROG_NFS, 2); root_mount_port = rpclookup(ARP_ROOTSERVER, PROG_MOUNT, 1); if ((root_nfs_port == -1) || (root_mount_port == -1)) { printf("Unable to get ROOT NFS/MOUNT ports\n"); longjmp(jmp_bootmenu,1); } if (err = nfs_mount(ARP_ROOTSERVER, root_mount_port, nfsdiskless.root_hostnam, &nfsdiskless.root_fh)) { printf("Unable to mount ROOT filesystem: "); nfs_err(err); longjmp(jmp_bootmenu,1); } nfsdiskless.root_saddr.sin_len = sizeof(struct sockaddr_in); nfsdiskless.root_saddr.sin_family = AF_INET; nfsdiskless.root_saddr.sin_port = htons(root_nfs_port); nfsdiskless.root_saddr.sin_addr.s_addr = htonl(arptable[ARP_ROOTSERVER].ipaddr); nfsdiskless.root_args.timeo = 10; nfsdiskless.root_args.retrans = 100; nfsdiskless.root_time = 0; if (err = nfs_lookup(ARP_ROOTSERVER, root_nfs_port, &nfsdiskless.root_fh, *kernel == '/' ? kernel+1 : kernel, &kernel_handle, NULL)) { printf("Unable to open %s: ",kernel); nfs_err(err); longjmp(jmp_bootmenu,1); } /* Load the kernel using NFS */ printf("Loading %s...\n",kernel); if ((err = nfs_read(ARP_ROOTSERVER, root_nfs_port, &kernel_handle, 0, sizeof(struct exec), &head)) < 0) { printf("Unable to read %s: ",kernel); nfs_err(err); longjmp(jmp_bootmenu,1); } if (N_BADMAG(head)) { printf("Bad executable format!\n"); longjmp(jmp_bootmenu, 1); } loadpoint = (char *)(head.a_entry & 0x00FFFFFF); offset = N_TXTOFF(head); printf("text=0x%X, ",head.a_text); #ifdef PC98 set_twiddle_max(8); #endif nfsload(head.a_text); while (((int)loadpoint) & PAGE_MASK) *(loadpoint++) = 0; printf("data=0x%X, ",head.a_data); nfsload(head.a_data); printf("bss=0x%X, ",head.a_bss); while(head.a_bss--) *(loadpoint++) = 0; while (((int)loadpoint) & PAGE_MASK) *(loadpoint++) = 0; bootinfo.bi_symtab = (int) loadpoint; p = (char*)&head.a_syms; for (i=0;i<sizeof(head.a_syms);i++) *loadpoint++ = *p++; printf("symbols=[+0x%x+0x%x", sizeof(head.a_syms), head.a_syms); nfsload(head.a_syms); i = sizeof(int); p = loadpoint; nfsload(i); i = *(int*)p; printf("+0x%x]\n", i); i -= sizeof(int); nfsload(i); bootinfo.bi_esymtab = (int) loadpoint; printf("entry=0x%X.\n",head.a_entry); /* Jump to kernel */ bootinfo.bi_version = BOOTINFO_VERSION; bootinfo.bi_kernelname = kernel; bootinfo.bi_nfs_diskless = &nfsdiskless; bootinfo.bi_size = sizeof bootinfo; kernelentry = (void *)(head.a_entry & 0x00FFFFFF); (*kernelentry)(howto|RB_BOOTINFO,NODEV,0,0,0,&bootinfo,0,0,0); printf("*** %s execute failure ***\n",kernel); }
/************************************************************************** NFS - Download extended BOOTP data, or kernel image from NFS server **************************************************************************/ int nfs(const char *name, int (*fnc)(unsigned char *, unsigned int, unsigned int, int)) { static int recursion = 0; int sport; int err, namelen = strlen(name); char dirname[300], *fname; char dirfh[NFS_FHSIZE]; /* file handle of directory */ char filefh[NFS_FHSIZE]; /* file handle of kernel image */ unsigned int block; int rlen, size, offs, len; struct rpc_t *rpc; rx_qdrain(); sport = oport++; if (oport > START_OPORT+OPORT_SWEEP) { oport = START_OPORT; } if ( name != dirname ) { memcpy(dirname, name, namelen + 1); } recursion = 0; nfssymlink: if ( recursion > NFS_MAXLINKDEPTH ) { printf ( "\nRecursion: More than %d symlinks followed. Abort.\n", NFS_MAXLINKDEPTH ); return 0; } recursion++; fname = dirname + (namelen - 1); while (fname >= dirname) { if (*fname == '/') { *fname = '\0'; fname++; break; } fname--; } if (fname < dirname) { printf("can't parse file name %s\n", name); return 0; } if (mount_port == -1) { mount_port = rpc_lookup(ARP_SERVER, PROG_MOUNT, 1, sport); } if (nfs_port == -1) { nfs_port = rpc_lookup(ARP_SERVER, PROG_NFS, 2, sport); } if (nfs_port == -1 || mount_port == -1) { printf("can't get nfs/mount ports from portmapper\n"); return 0; } err = nfs_mount(ARP_SERVER, mount_port, dirname, dirfh, sport); if (err) { printf("mounting %s: ", dirname); nfs_printerror(err); /* just to be sure... */ nfs_umountall(ARP_SERVER); return 0; } err = nfs_lookup(ARP_SERVER, nfs_port, dirfh, fname, filefh, sport); if (err) { printf("looking up %s: ", fname); nfs_printerror(err); nfs_umountall(ARP_SERVER); return 0; } offs = 0; block = 1; /* blocks are numbered starting from 1 */ size = -1; /* will be set properly with the first reply */ len = NFS_READ_SIZE; /* first request is always full size */ do { err = nfs_read(ARP_SERVER, nfs_port, filefh, offs, len, sport); if ((err <= -NFSERR_ISDIR)&&(err >= -NFSERR_INVAL) && (offs == 0)) { // An error occured. NFS servers tend to sending // errors 21 / 22 when symlink instead of real file // is requested. So check if it's a symlink! block = nfs_readlink(ARP_SERVER, nfs_port, dirfh, dirname, filefh, sport); if ( 0 == block ) { printf("\nLoading symlink:%s ..",dirname); goto nfssymlink; } nfs_printerror(err); nfs_umountall(ARP_SERVER); return 0; } if (err) { printf("reading at offset %d: ", offs); nfs_printerror(err); nfs_umountall(ARP_SERVER); return 0; } rpc = (struct rpc_t *)&nic.packet[ETH_HLEN]; /* size must be found out early to allow EOF detection */ if (size == -1) { size = ntohl(rpc->u.reply.data[6]); } rlen = ntohl(rpc->u.reply.data[18]); if (rlen > len) { rlen = len; /* shouldn't happen... */ } err = fnc((char *)&rpc->u.reply.data[19], block, rlen, (offs+rlen == size)); if (err <= 0) { nfs_umountall(ARP_SERVER); return err; } block++; offs += rlen; /* last request is done with matching requested read size */ if (size-offs < NFS_READ_SIZE) { len = size-offs; } } while (len != 0); /* len == 0 means that all the file has been read */ return 1; }