📄 nfile.c
字号:
/* * Copyright (C) 1998, 1999, 2001, Jonathan S. Shapiro. * * This file is part of the EROS Operating System. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2, * or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *//* * file.c * * This is the server-based implementation. In this implementation, * a file is actually an object maintained by a server. The purpose * of the server is to amortize the cost of the receive buffer across * a whole bunch of files. * * There is a strictly temporary limitation in the current * implementation that the total size of the served space must not * exceed 134Mbytes. This is because the current kernel omits the * background window capability implementation, so we are temporarily * unable to do windowing tricks. * * The whole shebang is designed around 4Kbyte file blocks. */#include <eros/target.h>#include <domain/Runtime.h>#include <eros/Invoke.h>#include <eros/NumberKey.h>#include <eros/NodeKey.h>#include <eros/ProcessKey.h>#include <eros/Key.h>#include <domain/VcskKey.h>#include <domain/SpaceBankKey.h>#include <domain/ConstructorKey.h>#include <domain/NFileKey.h>#include <domain/domdbg.h>#include <domain/Runtime.h>#include <memory.h>#define dbg_init 0x1#define dbg_alloc 0x2#define dbg_findpg 0x4#define dbg_write 0x8#define dbg_read 0x10#define dbg_ino 0x20#define dbg_inogrow 0x40#define dbg_req 0x80#define dbg_free 0x100#define dbg_fresh 0x200/* Following should be an OR of some of the above */#if 0#define dbg_flags ( dbg_alloc|dbg_read|dbg_inogrow|dbg_req )#else#define dbg_flags ( 0u )#endif#define DEBUG(x) if (dbg_##x & dbg_flags)#include "constituents.h"#define KR_FILESTART KR_APP(0) /* start key for files */#define KR_CURFILE KR_APP(1)#define KR_OSTREAM KR_APP(2)#define KR_MYSPACE KR_APP(3)#define KR_SCRATCH KR_APP(4)/* #define FLIP_BUF */#ifdef FLIP_BUF#define BUF_SZ EROS_PAGE_SIZE#else#define BUF_SZ EROS_MESSAGE_LIMIT#endif#define BLOCK_SIZE 4096#define NSTACK (BUF_SZ/EROS_PAGE_SIZE + 1)const uint32_t __rt_stack_pages = NSTACK;#define GROW_NOZERO 2#define GROW 1#define NO_GROW 0/* Following is temporary!!! */typedef uint32_t f_size_t;#define base_addr ((uint8_t *) 0x08000000)#define INO_NINDIR 11/* Following structure is of a size that evenly divides BLOCK_SIZE, which is important to the implementation */typedef struct ino ino_s;struct ino { union { uint64_t sz; /* 3 bytes available here */ ino_s *nxt_free; } u; uint64_t uuid; /* unique ID */ uint8_t nLayer; uint32_t *indir[INO_NINDIR];} ;/* Max of 5 indirection blocks */const uint64_t sizes_by_layers[] = { 1llu * INO_NINDIR * BLOCK_SIZE, 1llu * INO_NINDIR * BLOCK_SIZE * (BLOCK_SIZE/sizeof(uint32_t *)), 1llu * INO_NINDIR * BLOCK_SIZE * (BLOCK_SIZE/sizeof(uint32_t *)) * (BLOCK_SIZE/sizeof(uint32_t *)), 1llu * INO_NINDIR * BLOCK_SIZE * (BLOCK_SIZE/sizeof(uint32_t *)) * (BLOCK_SIZE/sizeof(uint32_t *)) * (BLOCK_SIZE/sizeof(uint32_t *)), 1llu * INO_NINDIR * BLOCK_SIZE * (BLOCK_SIZE/sizeof(uint32_t *)) * (BLOCK_SIZE/sizeof(uint32_t *)) * (BLOCK_SIZE/sizeof(uint32_t *)) * (BLOCK_SIZE/sizeof(uint32_t *)),};typedef struct server_state { uint8_t *buf; ino_s *first_free_inode; uint32_t *first_free_block; ino_s root; uint8_t *top_addr; uint64_t nxt_uuid;} server_state;#define WANT_ZERO 1#define NO_ZERO 0uint8_t*AllocBlock(server_state *ss, int wantZero){ uint8_t * pg; if (ss->first_free_block) { uint32_t *nxt = (uint32_t *) *(ss->first_free_block); pg = (uint8_t *) ss->first_free_block; ss->first_free_block = nxt; if (wantZero == WANT_ZERO) bzero(pg, BLOCK_SIZE); } else { pg = ss->top_addr; ss->top_addr += BLOCK_SIZE; /* Newly allocated pages come to us pre-zeroed by VCSK. */ DEBUG(fresh) kprintf(KR_OSTREAM, "Allocating fresh page\n"); } DEBUG(alloc) kdprintf(KR_OSTREAM, "AllocBlock returns 0x%x\n", pg); return pg;}voidinit(server_state *ss){ uint32_t result; node_copy(KR_CONSTIT, KC_OSTREAM, KR_OSTREAM); process_copy(KR_SELF, ProcAddrSpace, KR_SCRATCH); /* Buy a new root node: */ result = spcbank_buy_nodes(KR_BANK, 1, KR_MYSPACE, KR_VOID, KR_VOID); if (result != RC_OK) DEBUG(init) kdprintf(KR_OSTREAM, "DIR: spcbank nodes exhausted\n", result); DEBUG(init) kdprintf(KR_OSTREAM, "Bought new space\n"); /* make that node LSS=TOP_LSS */ node_make_node_key(KR_MYSPACE, EROS_ADDRESS_BLSS, KR_MYSPACE); node_swap(KR_MYSPACE, 0, KR_SCRATCH, KR_VOID); process_swap(KR_SELF, ProcAddrSpace, KR_MYSPACE, KR_VOID); node_copy(KR_CONSTIT, KC_ZSF, KR_SCRATCH); result = constructor_request(KR_SCRATCH, KR_BANK, KR_SCHED, KR_VOID, KR_SCRATCH); /* plug in newly allocated ZSF */ DEBUG(init) kdprintf(KR_OSTREAM, "FS: plugging zsf into new spc root\n", result); node_swap(KR_MYSPACE, 1, KR_SCRATCH, KR_VOID); bzero(ss, sizeof(*ss)); ss->top_addr = base_addr; ss->first_free_inode = 0; ss->first_free_block = 0; ss->root.nLayer = 0; ss->root.uuid = 0; ss->nxt_uuid = 1; { uint32_t sz = BLOCK_SIZE; ss->buf = AllocBlock(ss, WANT_ZERO); while (sz < BUF_SZ) { AllocBlock(ss, WANT_ZERO); sz += BLOCK_SIZE; } } DEBUG(init) kdprintf(KR_OSTREAM, "Root inode is initialized\n");}/* find_file_page(): Given a *byte* position named by /at/, returns * the address of the INDIRECTION TABLE ENTRY for the page. Thus: * * *(find_file_page(...)) = new_page_ptr * * or * new_page_ptr = *(find_file_page(...)) * * This function does lazy file expansion! */uint32_t **find_file_page(server_state *ss, ino_s *ino, f_size_t at, int wantGrow){ uint64_t allocSz = (ino->u.sz + (BLOCK_SIZE - 1)) & (BLOCK_SIZE-1); uint64_t atPg = (at / BLOCK_SIZE); uint32_t ndx; uint32_t **blockTable = ino->indir; DEBUG(findpg) kdprintf(KR_OSTREAM, "find: ino: 0x%X sz 0x%X at: 0x%x, grow? %c\n", ino->uuid, ino->u.sz, at, (wantGrow == GROW) ? 'y' : 'n'); /* Grow the file upwards as necessary. */ while (allocSz > sizes_by_layers[ino->nLayer]) { int i; uint32_t **newIndir; DEBUG(findpg) kdprintf(KR_OSTREAM, "find: ino: 0x%X allocSz 0x%X nLayer %d (max 0x%x) => grow\n", ino->uuid, allocSz, ino->nLayer, sizes_by_layers[ino->nLayer]); newIndir = (uint32_t **) AllocBlock(ss, WANT_ZERO); for (i = 0; i < INO_NINDIR; i++) { newIndir[i] = ino->indir[i]; ino->indir[i] = 0; } ino->indir[0] = (uint32_t*) newIndir; ino->nLayer++; } DEBUG(findpg) kdprintf(KR_OSTREAM, "find: ino: 0x%X nLayer: %d\n", ino->uuid, ino->nLayer); { uint32_t layer = ino->nLayer; while (layer > 0) { ndx = (atPg / (layer * (BLOCK_SIZE/sizeof(uint32_t *)))); ndx %= (BLOCK_SIZE / sizeof(uint32_t)); DEBUG(findpg) kdprintf(KR_OSTREAM, "find: ino: 0x%X layer %d ndx %d\n", ino->uuid, layer, ndx); blockTable = (uint32_t **)blockTable[ndx]; DEBUG(findpg) kdprintf(KR_OSTREAM, "find: ino: 0x%X layer %d ndx %d ==> 0x%x\n", ino->uuid, layer, ndx, blockTable); if (blockTable == 0) { if (wantGrow == NO_GROW) return 0; blockTable[ndx] = (uint32_t *) AllocBlock(ss, WANT_ZERO); blockTable = (uint32_t **)blockTable[ndx]; DEBUG(findpg) kdprintf(KR_OSTREAM, "find: ino: 0x%X layer %d ndx %d: grow layer: 0x%x\n", ino->uuid, layer, ndx, blockTable); } layer--; } ndx = atPg % (BLOCK_SIZE / sizeof(uint32_t)); DEBUG(findpg) kdprintf(KR_OSTREAM, "find: ino: 0x%X layer %d ndx %d: blockTbl 0x%x bt[ndx] 0x%x\n", ino->uuid, layer, ndx, blockTable, blockTable[ndx]); if (blockTable[ndx] == 0 && wantGrow != NO_GROW) { DEBUG(findpg) kdprintf(KR_OSTREAM, "find: ino: 0x%X layer %d ndx %d: grow leaf: 0x%x\n", ino->uuid, layer, ndx, blockTable[ndx]); if (wantGrow == GROW) blockTable[ndx] = (uint32_t *) AllocBlock(ss, WANT_ZERO); else blockTable[ndx] = (uint32_t *) AllocBlock(ss, NO_ZERO); } } DEBUG(findpg) kdprintf(KR_OSTREAM, "find: ino: 0x%X return 0x%x contains 0x%x\n", ino->uuid, &blockTable[ndx], blockTable[ndx]); return &blockTable[ndx];}/* Write /len/ bytes of data from /buf/ into /file/, starting at position /at/. Extends the file as necessary. */uint32_twrite_to_file(server_state *ss, ino_s *ino, f_size_t at, uint32_t len, uint8_t *buf){ DEBUG(write) kdprintf(KR_OSTREAM, "write: ino: 0x%X writing %d at 0x%x\n", ino->uuid, len, at); /* The passed /buf/ is contiguous, but there is no guarantee that the file itself is. */ while (len) { uint32_t offset = at & (BLOCK_SIZE - 1); uint32_t nBytes = BLOCK_SIZE - offset; DEBUG(write) kdprintf(KR_OSTREAM, "write: ino: 0x%X bwrite %d at 0x%x\n", ino->uuid, nBytes, at); if (nBytes > len) nBytes = len; { uint32_t grow = (offset == 0 && nBytes == BLOCK_SIZE) ? GROW_NOZERO : GROW; uint32_t **ppPage = find_file_page(ss, ino, at, grow); uint8_t *pPage = (uint8_t *) *ppPage;#ifdef FLIP_BUF if (offset == 0 && nBytes == BLOCK_SIZE) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -