?? kernel.c
字號:
/* This file contains the vnode layer used by the file system construction kit. It is the file system independent layer and managed hooking up requests from the test program (fsh and tstfs) to the actual file system routines. It provides a rather posix-like interface generally with the routines preceded by a "sys_" prefix. THIS CODE COPYRIGHT DOMINIC GIAMPAOLO. NO WARRANTY IS EXPRESSED OR IMPLIED. YOU MAY USE THIS CODE AND FREELY DISTRIBUTE IT FOR NON-COMMERCIAL USE AS LONG AS THIS NOTICE REMAINS ATTACHED. FOR COMMERCIAL USE, CONTACT DOMINIC GIAMPAOLO (dbg@be.com). Dominic Giampaolo dbg@be.com*/#include "compat.h"#include "skiplist.h"#include "lock.h"#include "fsproto.h"#include "kprotos.h"#include <sys/stat.h>#define OMODE_MASK (O_RDONLY | O_WRONLY | O_RDWR)#define SLEEP_TIME (10000.0)#define MAX_SYM_LINKS 16#define FREE_LIST 0#define USED_LIST 1#define LOCKED_LIST 2#define LIST_NUM 3#define FD_FILE 1#define FD_DIR 2#define FD_WD 4#define FD_ALL (FD_FILE | FD_DIR | FD_WD)#define DEFAULT_FD_NUM (128)#define VNNUM 256typedef unsigned long fsystem_id;typedef struct vnode vnode;typedef struct vnlist vnlist;typedef struct vnlink vnlink;typedef struct fsystem fsystem;typedef struct nspace nspace;typedef struct ofile ofile;typedef struct ioctx ioctx;typedef struct fdarray fdarray;struct vnlist { vnode *head; vnode *tail; int num;};struct vnlink { vnode *prev; vnode *next;};struct vnode { vnode_id vnid; nspace * ns; nspace * mounted; char remove; char busy; char inlist; char watched; vnlink nspace; vnlink list; int rcnt; void * data;};struct fsystem { fsystem_id fsid; bool fixed; image_id aid; char name[IDENT_NAME_LENGTH]; int rcnt; vnode_ops ops;};struct nspace { nspace_id nsid; my_dev_t dev; my_ino_t ino; fsystem *fs; vnlist vnodes; void *data; vnode * root; vnode * mount; nspace * prev; nspace * next; char shutdown;};struct ofile { short type; ushort flags; vnode * vn; void * cookie; long rcnt; long ocnt; fs_off_t pos; int omode;};struct ioctx { lock lock; int kerrno; vnode * cwd; fdarray * fds;};struct fdarray { long rcnt; lock lock; int num; ulong *alloc; ulong *coes; ofile *fds[1];};extern struct { const char * name; vnode_ops * ops;} fixed_fs[];static vnode_id invalid_vnid = 0;static vnode * rootvn;static int max_glb_file;static fdarray * global_fds;static vnlist lists[LIST_NUM];static nspace * nshead;static lock vnlock;static lock fstablock;static nspace ** nstab;static fsystem ** fstab;static int nns;static int nfs;static fsystem_id nxfsid;static nspace_id nxnsid;static SkipList skiplist;static int vnnum;static int usdvnnum;int sys_rstat(bool kernel, int fd, const char *path, struct my_stat *st, bool eatlink);static fsystem * inc_file_system(const char *name);static int dec_file_system(fsystem *fs);static int get_dir_fd(bool kernel, int fd, const char *path, char *filename, vnode **dvn);static int get_file_fd(bool kernel, int fd, const char *path, int eatsymlink, vnode **vn);static int get_file_vn(nspace_id nsid, vnode_id vnid, const char *path, int eatsymlink, vnode **vn);static int parse_path_fd(bool kerne, int fd, char **pstart, int eatsymlink, vnode **vn);static int parse_path_vn(nspace_id nsid, vnode_id vnid, char **start, int eatsymlink, vnode **vn);static int parse_path(vnode *bvn, char **pstart, char *path, int eatsymlink, vnode **vn);static char * cat_paths(char *a, char *b);static int load_vnode(nspace_id nsid, vnode_id vnid, char r, vnode **vnp);static vnode * lookup_vnode(nspace_id nsid, vnode_id vnid);static void move_vnode(vnode *vn, int list);static vnode * steal_vnode(int list);static void flush_vnode(vnode *vn, char r);static int sort_vnode(vnode *vn);static void clear_vnode(vnode *vn);static void inc_vnode(vnode *vn);static void dec_vnode(vnode *vn, char r);static int compare_vnode(vnode *vna, vnode *vnb);static nspace * nsidtons(nspace_id nsid);static int alloc_wd_fd(bool kernel, vnode *vn, bool coe, int *fdp);static int is_root(vnode *root, vnode **mount);static int is_mount_vnode(vnode *mount, vnode **root);static int is_mount_vnid(nspace_id nsid, vnode_id vnid, vnode_id *mount);static ofile * get_fd(bool kernel, int fd, int type);static int put_fd(ofile *f);static int new_fd(bool kernel, int nfd, ofile *f, int fd, bool coe);static int remove_fd(bool kernel, int fd, int type);static int get_coe(bool kernel, int fd, int type, bool *coe);static int set_coe(bool kernel, int fd, int type, bool coe);static int get_omode(bool kernel, int fd, int type, int *omode);static int invoke_close(ofile *f);static int invoke_free(ofile *f);static fdarray * new_fds(int num);static int free_fds(fdarray *fds);#define BITSZ(n) (((n) + 31) & ~31)#define SETBIT(a,i,v) *((a)+(i)/32) = (*((a)+(i)/32) & ~(1<<((i)%32))) | (v<<((i)%32))#define GETBIT(a,i) ((*((a)+(i)/32) & (1<<((i)%32))) >> ((i)%32))/* ---------------------------------------------------------------- */#include <stdio.h>static voidPANIC(char *s){ printf(s);}#ifdef DEBUGintdump_fsystem(int argc, char **argv){ struct fsystem *fs; if (argv[1] == NULL) { kprintf("%s needs an address argument\n", argv[0]); return 1; } fs = (struct fsystem *)strtoul(argv[1], NULL, 0); kprintf("fs @ 0x%x name %s rcnt %d ops @ 0x%x\n", fs, fs->name, fs->rcnt, &fs->ops);}intdump_ioctx(int argc, char **argv){ struct ioctx *ioctx; if (argv[1] == NULL) { kprintf("%s needs an address argument\n", argv[0]); return 1; } ioctx = (struct ioctx *)strtoul(argv[1], NULL, 0); kprintf("ioctx @ 0x%x, kerrno %d, cwd 0x%x, fdarray 0x%x\n", ioctx, ioctx->kerrno, ioctx->cwd, ioctx->fds);}intdump_vnode(int argc, char **argv){ struct vnode *vn; if (argv[1] == NULL) { kprintf("%s needs an address argument\n", argv[0]); return 1; } vn = (vnode *)strtoul(argv[1], NULL, 0); kprintf("vnode @ 0x%x vnid 0x%x ns 0x%x mounted 0x%x\n", vn, vn->vnid, vn->ns, vn->mounted); kprintf("remove %d busy %d inlist %d\n", vn->remove, vn->busy, vn->inlist); kprintf("nspace 0x%x list 0x%x rcnt 0x%x data 0x%x\n", &vn->nspace, &vn->list, vn->rcnt, vn->data);}intdump_fdarray(int argc, char **argv){ int i; struct fdarray *fds; if (argv[1] == NULL) { kprintf("%s needs an address argument\n", argv[0]); return 1; } fds = (struct fdarray *)strtoul(argv[1], NULL, 0); kprintf("fdarray @ 0x%x rcnt %d lock %d num %d\n", fds, fds->rcnt, fds->num); kprintf("alloc 0x%x coes 0x%x\n", fds->alloc, fds->coes); for(i=0; i < fds->num; i++) if (fds->fds[i]) kprintf("fd %3d @ 0x%x\n", i, fds->fds[i]);}intdump_ofile(int argc, char **argv){ struct ofile *ofile; if (argv[1] == NULL) { kprintf("%s needs an address argument\n", argv[0]); return 1; } ofile = (struct ofile *)strtoul(argv[1], NULL, 0); kprintf("ofile @ 0x%x type %d flags %d vn 0x%x cookie 0x%x\n", ofile, ofile->type, ofile->flags, ofile->vn, ofile->cookie); kprintf("rcnt %d ocnt %d pos 0x%x omode 0x%x\n", ofile->rcnt, ofile->ocnt, ofile->pos, ofile->omode);}intdump_nspace(int argc, char **argv){ struct nspace *ns; if (argv[1] == NULL) { kprintf("%s needs an address argument\n", argv[0]); return 1; } ns = (struct nspace *)strtoul(argv[1], NULL, 0); kprintf("ns @ 0x%x nsid %d vnlist @ 0x%x data 0x%x\n", ns, ns->nsid, &ns->vnodes, ns->data); kprintf("root 0x%x mount 0x%x prev 0x%x next 0x%x\n", ns->root, ns->mount, ns->prev, ns->next); kprintf("shutdown %d fs @ 0x%x\n", ns->shutdown, ns->fs);}voiddo_dump_io_info(thread_rec *thr){ int i; struct fdarray *fds; if (thr->ioctx == NULL || thr->ioctx->fds == NULL) { kprintf("thread: %d (%s)\n No io info?!?\n", thr->thid, thr->name); return; } kprintf("thread: %d (%s)\n", thr->thid, thr->name); fds = thr->ioctx->fds; for(i=0; i < fds->num; i++) if (fds->fds[i]) kprintf(" fd %3d vnode @ 0x%.8x (vnid 0x%.8x, data 0x%.8x)\n", i, fds->fds[i]->vn, fds->fds[i]->vn->vnid, fds->fds[i]->vn->data);}intdump_io_info(int argc, char **argv){ int i; thread_rec *thr; if (argv[1] == NULL) { kprintf("%s needs an thread name/address argument\n", argv[0]); return 1; } if (strcmp(argv[1], "-n") == 0) { int len; /* hunt for the name in argv[2] */ if (argv[2] == NULL) { kprintf("thread: the `-name' option requires an argument\n"); return 0; } len = strlen(argv[2]); for(i=0; i < nthreads; i++) { if (thread_tab[i] == NULL) continue; if (mystrstr(thread_tab[i]->name, argv[2]) != NULL) { thr = thread_tab[i]; do_dump_io_info(thr); } } } else { ulong num; num = strtoul(argv[2], NULL, 0); if (num < 0x2ffff && isbadthid(num) == 0) thr = thread_tab[thidtoslot(num)]; else thr = (thread_rec *)num; if (thr == 0) return 0; do_dump_io_info(thr); } return 1;}intfind_vn(int argc, char **argv){ nspace *ns; vnode *vn; vnode fakevn; vnode_id vnid; if (argv[1] == NULL) { kprintf("%s needs a vnid argument\n", argv[0]); return 1; } vnid = (vnode_id)strtoul(argv[1], NULL, 0); for(ns=nshead; ns; ns=ns->next) { fakevn.ns = ns; fakevn.vnid = vnid; vn = SearchSL(skiplist, &fakevn); if (vn) kprintf("vn = 0x%x (nsid = %d)\n", vn, vn->ns->nsid); } return 0;}#endif /* DEBUG *//* ---------------------------------------------------------------- */#ifdef USERint memsize = 8 * 1024 * 1024;#endifintinit_vnode_layer(void){ int err; vnode *vns; vnode_id vnid; int i; fsystem *fs; nspace *ns; void *data; size_t sz; extern vnode_ops rootfs; /* XXXdbg */ /* compute vnnum based on memsize. 256 vnodes with 8MB. compute usdvnnum based on vnnum. only 1/4 of total vnodes should remain unlocked. */ vnnum = memsize >> 15; usdvnnum = vnnum >> 2; vns = (vnode *) calloc(sizeof(vnode) * vnnum, 1); for(i=0; i<vnnum; i++) { vns[i].vnid = invalid_vnid; vns[i].ns = NULL; vns[i].mounted = NULL; vns[i].remove = FALSE; vns[i].busy = FALSE; vns[i].inlist = FREE_LIST; vns[i].nspace.next = vns[i].nspace.prev = NULL; vns[i].list.next = (i == vnnum-1 ? NULL : &vns[i+1]); vns[i].list.prev = (i == 0 ? NULL : &vns[i-1]); vns[i].rcnt = 0; vns[i].data = NULL; } lists[FREE_LIST].head = &vns[0]; lists[FREE_LIST].tail = &vns[vnnum-1]; lists[FREE_LIST].num = vnnum; lists[USED_LIST].head = NULL; lists[USED_LIST].tail = NULL; lists[USED_LIST].num = 0; lists[LOCKED_LIST].head = NULL; lists[LOCKED_LIST].tail = NULL; lists[LOCKED_LIST].num = 0; skiplist = NewSL(&compare_vnode, NULL, NO_DUPLICATES); /* set max # of file systems and mount points. with 8MB, up to 32 fs and 64 mount points. */ nns = memsize >> 17; nfs = memsize >> 18; nxfsid = 1; nxnsid = 1; nstab = (nspace **) malloc(nns * sizeof(void *)); memset(nstab, 0, nns * sizeof(void *)); fstab = (fsystem **) malloc(nfs * sizeof(void *)); memset(fstab, 0, nfs * sizeof(void *)); new_lock(&vnlock, "vnlock"); new_lock(&fstablock, "fstablock"); /* determine the max number of files the kernel can open. 8MB -> 256 */ max_glb_file = memsize >> 15; global_fds = new_fds(max_glb_file); /* install file systems */ install_file_system(&rootfs, "rootfs", TRUE, -1); /* mount the root file system */ fs = inc_file_system("rootfs"); ns = (nspace *) malloc(sizeof(nspace)); ns->fs = fs; ns->nsid = nxnsid++; nstab[ns->nsid % nns] = ns; ns->vnodes.head = ns->vnodes.tail = NULL; ns->data = NULL; ns->root = NULL; ns->mount = NULL; ns->shutdown = FALSE; ns->prev = ns->next = NULL; nshead = ns; err = (*fs->ops.mount)(ns->nsid, NULL, 0, NULL, 0, &data, &vnid); ns->data = data; ns->root = lookup_vnode(ns->nsid, vnid); rootvn = ns->root;#ifdef DEBUG add_debugger_cmd("ioctx", dump_ioctx, "dump a thread ioctx struct"); add_debugger_cmd("vnode", dump_vnode, "dump a vnode struct"); add_debugger_cmd("fdarray", dump_fdarray, "dump an fd array"); add_debugger_cmd("ofile", dump_ofile, "dump an ofile struct"); add_debugger_cmd("nspace", dump_nspace, "dump a nspace struct"); add_debugger_cmd("fsystem", dump_fsystem, "dump a fsystem struct"); add_debugger_cmd("ioinfo", dump_io_info, "dump io info for a thread"); add_debugger_cmd("findvn", find_vn, "find a vnid (in all threads)");#endif /* DEBUG */ return 0;}/* ---------------------------------------------------------------- */intsys_sync(void){ nspace *ns; op_sync *op; LOCK(vnlock); for(ns = nshead; ns; ns = ns->next) { ns->root->rcnt++; UNLOCK(vnlock); op = ns->fs->ops.sync; if (op) (*op)(ns->data); LOCK(vnlock); ns->root->rcnt--; } UNLOCK(vnlock); return 0;}static ioctx *get_cur_ioctx(void){ static int init = 0; static ioctx io; if (init == 0) { init = 1; memset(&io, 0, sizeof(io)); } return &io;}/* * sys_chdir */intsys_chdir(bool kernel, int fd, const char *path){ int err; ioctx *io; vnode *vn; op_rstat *op; struct my_stat st; err = get_file_fd(kernel, fd, path, TRUE, &vn); if (err) goto error1; op = vn->ns->fs->ops.rstat; if (!op) { err = EINVAL; goto error2; } err = (*op)(vn->ns->data, vn->data, &st); if (err) goto error2; if (!MY_S_ISDIR(st.mode)) { err = ENOTDIR; goto error2; } io = get_cur_ioctx(); LOCK(io->lock); dec_vnode(io->cwd, FALSE); io->cwd = vn; UNLOCK(io->lock); return 0; error2: dec_vnode(vn, FALSE);error1: return err;}/* * sys_access */intsys_access(bool kernel, int fd, const char *path, int mode){ int err; vnode *vn; op_access *op; err = get_file_fd(kernel, fd, path, TRUE, &vn); if (err) goto error1; op = vn->ns->fs->ops.access; if (!op) { err = EINVAL; goto error2; } err = (*op)(vn->ns->data, vn->data, mode); if (err) goto error2; dec_vnode(vn, FALSE); return 0;error2: dec_vnode(vn, FALSE);error1: return err;}/* * sys_symlink */intsys_symlink(bool kernel, const char *oldpath, int nfd, const char *newpath){ int err; char filename[FILE_NAME_LENGTH]; char *buf; vnode *dvn; op_symlink *op; err = get_dir_fd(kernel, nfd, newpath, filename, &dvn); if (err) goto error1; err = new_path(oldpath, &buf); if (err) goto error2; op = dvn->ns->fs->ops.symlink; if (!op) { err = EINVAL; goto error3; } err = (*op)(dvn->ns->data, dvn->data, filename, buf); if (err) goto error3; dec_vnode(dvn, FALSE); free_path(buf); return 0;error3: free_path(buf);error2: dec_vnode(dvn, FALSE);error1: return err;}/* * sys_readlink */ssize_tsys_readlink(bool kernel, int fd, const char *path, char *buf, size_t bufsize){ int err; vnode *vn; op_readlink *op; size_t sz; err = get_file_fd(kernel, fd, path, FALSE, &vn); if (err) goto error1; op = vn->ns->fs->ops.readlink; if (!op) { err = EINVAL; goto error2; }
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -