# HG changeset patch # User menikon # Date 1581163519 -32400 # Node ID 40726bcd527241a252d5abdcba81246214820567 # Parent dca5e4f9fceb07da5e9b75a2687e6c8b5637d404 add src diff -r dca5e4f9fceb -r 40726bcd5272 final_main/appendix.tex --- a/final_main/appendix.tex Sat Feb 08 19:00:35 2020 +0900 +++ b/final_main/appendix.tex Sat Feb 08 21:05:19 2020 +0900 @@ -0,0 +1,6 @@ +\chapter*{付録} + +\lstinputlisting[label=fs.ds, caption=FileSystem の Interface]{src/fs.dg} +\lstinputlisting[label=fs_impl.h, caption=]{src/fs_impl.h} +\lstinputlisting[label=fs_impl.cbc, caption=FileSystem の 実装]{src/fs_impl.cbc} +\lstinputlisting[label=fs_impl_private.cbc, caption=FileSystem の 実装]{src/fs_impl_private.cbc} \ No newline at end of file diff -r dca5e4f9fceb -r 40726bcd5272 final_main/chapter2.tex --- a/final_main/chapter2.tex Sat Feb 08 19:00:35 2020 +0900 +++ b/final_main/chapter2.tex Sat Feb 08 21:05:19 2020 +0900 @@ -15,6 +15,7 @@ 本研究ではこのプログラミング言語を用いて xv6 の Filesystemを書き換える. \section{CodeGear} CodeGear は CbCにおける基本的な処理単位である. 以下のソースコード\ref{cbcexample}は CodeGear の継続の例である. +\newpage \lstinputlisting[label=cbcexample, caption=CodeGearの継続の例]{src/cbc_example.cbc} CodeGear は\_\_code CodeGear名 (引数) の形で記述される. CodeGear は返り値を持たない為, 関数内で処理が終了すると呼び出し 元の関数に戻ることがなく別の CodeGear へ遷移する. @@ -30,7 +31,7 @@ また CbC における CodeGear 間の継続にはスタックが使用されず, 呼び出し元の環境などを持たない為軽量継続と呼ぶ. この CbC における CodeGear 間の継続にスタックが使用されない性質は信頼性の高い OS の開発に適している. - +\newpage \section{DataGear} DataGear は CbCにおけるデータの基本的な単位である. CodeGear は Input DataGear, Output DataGear を引数に持ち,図\ref{fig:DataGear}で示したように遷移する際に任意のInput DataGearを参照し, Output DataGearを書き出す. diff -r dca5e4f9fceb -r 40726bcd5272 final_main/chapter4.tex --- a/final_main/chapter4.tex Sat Feb 08 19:00:35 2020 +0900 +++ b/final_main/chapter4.tex Sat Feb 08 21:05:19 2020 +0900 @@ -10,14 +10,22 @@ %processについて(軽く) \section{xv6 のFileSystem構造} +\begin{figure}[ht] + \begin{center} + \includegraphics[width=50mm]{fig/FileSystemLayout.pdf} + \end{center} + \caption{xv6 の FileSystem } + \label{fig:xv6filesystem} +\end{figure} + +\newpage xv6 の FileSystem の構造を以下の図\ref{fig:filesystem}に示す. -\vspace{10mm} \begin{figure}[ht] \begin{center} \includegraphics[width=150mm]{fig/xv6filesystemlayout.pdf} \end{center} - \caption{xv6 の FileSystem Layout} + \caption{xv6 の FileSystem } \label{fig:filesystem} \end{figure} @@ -25,17 +33,10 @@ \item boot sector \item super block \item inode - \item + \item block bitmap + \item data blocks + \item log \end{itemize} \section{FilleSystem の API} %関数や構造体などを解説しそのまま利用されているところをかく - - - - -\section{block bitmap} - -\section{data blocks} - -\section{log} \ No newline at end of file diff -r dca5e4f9fceb -r 40726bcd5272 final_main/fig/DataGear.graffle Binary file final_main/fig/DataGear.graffle has changed diff -r dca5e4f9fceb -r 40726bcd5272 final_main/fig/DataGear.pdf Binary file final_main/fig/DataGear.pdf has changed diff -r dca5e4f9fceb -r 40726bcd5272 final_main/fig/FileSystemLayout.graffle Binary file final_main/fig/FileSystemLayout.graffle has changed diff -r dca5e4f9fceb -r 40726bcd5272 final_main/fig/FileSystemLayout.pdf Binary file final_main/fig/FileSystemLayout.pdf has changed diff -r dca5e4f9fceb -r 40726bcd5272 final_main/main.out --- a/final_main/main.out Sat Feb 08 19:00:35 2020 +0900 +++ b/final_main/main.out Sat Feb 08 21:05:19 2020 +0900 @@ -11,11 +11,8 @@ \BOOKMARK [1][-]{section.4.1}{4.1 xv6 とは}{chapter.4}% 11 \BOOKMARK [1][-]{section.4.2}{4.2 xv6 のFileSystem構造}{chapter.4}% 12 \BOOKMARK [1][-]{section.4.3}{4.3 FilleSystem の API}{chapter.4}% 13 -\BOOKMARK [1][-]{section.4.4}{4.4 block bitmap}{chapter.4}% 14 -\BOOKMARK [1][-]{section.4.5}{4.5 data blocks}{chapter.4}% 15 -\BOOKMARK [1][-]{section.4.6}{4.6 log}{chapter.4}% 16 -\BOOKMARK [0][-]{chapter.5}{第5章 CbCによるFileSystemの書き換え}{}% 17 -\BOOKMARK [1][-]{section.5.1}{5.1 書き換え方針}{chapter.5}% 18 -\BOOKMARK [1][-]{section.5.2}{5.2 FileSystemのInterface}{chapter.5}% 19 -\BOOKMARK [1][-]{section.5.3}{5.3 CbC による FileSystem の書き換え}{chapter.5}% 20 -\BOOKMARK [0][-]{chapter.6}{第6章 まとめと今後の課題}{}% 21 +\BOOKMARK [0][-]{chapter.5}{第5章 CbCによるFileSystemの書き換え}{}% 14 +\BOOKMARK [1][-]{section.5.1}{5.1 書き換え方針}{chapter.5}% 15 +\BOOKMARK [1][-]{section.5.2}{5.2 FileSystemのInterface}{chapter.5}% 16 +\BOOKMARK [1][-]{section.5.3}{5.3 CbC による FileSystem の書き換え}{chapter.5}% 17 +\BOOKMARK [0][-]{chapter.6}{第6章 まとめと今後の課題}{}% 18 diff -r dca5e4f9fceb -r 40726bcd5272 final_main/main.pdf Binary file final_main/main.pdf has changed diff -r dca5e4f9fceb -r 40726bcd5272 final_main/main.tex --- a/final_main/main.tex Sat Feb 08 19:00:35 2020 +0900 +++ b/final_main/main.tex Sat Feb 08 21:05:19 2020 +0900 @@ -105,6 +105,6 @@ \input{thanks.tex} % 付録 -%\input{appendix.tex} +\input{appendix.tex} \end{document} diff -r dca5e4f9fceb -r 40726bcd5272 final_main/src/fs_impl.cbc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/final_main/src/fs_impl.cbc Sat Feb 08 21:05:19 2020 +0900 @@ -0,0 +1,381 @@ +#include "types.h" +#include "defs.h" +#include "param.h" +#include "stat.h" +#include "mmu.h" +#include "proc.h" +#include "spinlock.h" +#include "buf.h" +#include "fs.h" +#include "file.h" +#interface "Err.h" +#interface "fs.dg" + +// ---- +// typedef struct fs_impl impl fs{ +// union Data* fs_impl; +// +// +// +// +// } fs_impl; +// ---- + +fs* createfs_impl(struct Context* cbc_context) { + struct fs* fs = new fs(); + struct fs_impl* fs_impl = new fs_impl(); + fs->fs = (union Data*)fs_impl; + fs_impl->fs_impl = NULL; + fs_impl->sb = NULL; + fs_impl->ret = 0; + fs_impl->dev = 0; + fs_impl->type = 0; + fs_impl->bp = NULL; + fs_impl->dip = NULL; + fs_impl->inum = 0; + fs_impl->dp = NULL; + fs_impl->name = NULL; + fs_impl->off = 0; + fs_impl->poff = NULL; + fs_impl->de = NULL; + fs_impl->tot = 0; + fs_impl->m = 0; + fs_impl->dst = NULL; + fs_impl->n = 0; + fs_impl->src = NULL; + fs_impl->allocinode = C_allocinode; + fs_impl->allocinode_loop = C_allocinode_loop; + fs_impl->allocinode_loopcheck = C_allocinode_loopcheck; + fs_impl->allocinode_noloop = C_allocinode_noloop; + fs_impl->lockinode1 = C_lockinode1; + fs_impl->lockinode2 = C_lockinode2; + fs_impl->lockinode_sleepcheck = C_lockinode_sleepcheck; + fs_impl->iput_check = C_iput_check; + fs_impl->iput_inode_nolink = C_iput_inode_nolink; + fs_impl->readi_check_diskinode = C_readi_check_diskinode; + fs_impl->readi_loopcheck = C_readi_loopcheck; + fs_impl->readi_loop = C_readi_loop; + fs_impl->readi_noloop = C_readi_noloop; + fs_impl->writei_check_diskinode = C_writei_check_diskinode; + fs_impl->writei_loopcheck = C_writei_loopcheck; + fs_impl->writei_loop = C_writei_loop; + fs_impl->writei_noloop = C_writei_noloop; + fs_impl->dirlookup_loopcheck = C_dirlookup_loopcheck; + fs_impl->dirlookup_loop = C_dirlookup_loop; + fs_impl->dirlookup_noloop = C_dirlookup_noloop; + fs_impl->dirlink_namecheck = C_dirlink_namecheck; + fs_impl->dirlink_loopcheck = C_dirlink_loopcheck; + fs_impl->dirlink_loop = C_dirlink_loop; + fs_impl->dirlink_noloop = C_dirlink_noloop; + fs->readsb = C_readsbfs_impl; + fs->iinit = C_iinitfs_impl; + fs->ialloc = C_iallocfs_impl; + fs->iupdate = C_iupdatefs_impl; + fs->idup = C_idupfs_impl; + fs->ilock = C_ilockfs_impl; + fs->iunlock = C_iunlockfs_impl; + fs->iput = C_iputfs_impl; + fs->iunlockput = C_iunlockputfs_impl; + fs->stati = C_statifs_impl; + fs->readi = C_readifs_impl; + fs->writei = C_writeifs_impl; + fs->namecmp = C_namecmpfs_impl; + fs->dirlookup = C_dirlookupfs_impl; + fs->dirlink = C_dirlinkfs_impl; + fs->namei = C_nameifs_impl; + fs->nameiparent = C_nameiparentfs_impl; + return fs; +} + +typedef struct superblock superblock; +__code readsbfs_impl(struct fs_impl* fs, uint dev, struct superblock* sb, __code next(...)) { //:skip + + struct buf* bp; + + bp = bread(dev, 1); + memmove(sb, bp->data, sizeof(*sb)); + brelse(bp); + + goto next(...); +} + +struct { + struct spinlock lock; + struct inode inode[NINODE]; +} icache; + +__code iinitfs_impl(struct fs_impl* fs, __code next(...)) { + + initlock(&icache.lock, "icache"); + + goto next(...); +} + +__code iallocfs_impl(struct fs_impl* fs, uint dev, short type, __code next(...)) { + goto allocinode(fs, dev, sb, next(...)); +} + +__code iupdatefs_impl(struct fs_impl* fs, struct inode* ip, __code next(...)) { + + struct buf *bp; + struct dinode *dip; + + bp = bread(ip->dev, IBLOCK(ip->inum)); + + dip = (struct dinode*) bp->data + ip->inum % IPB; + dip->type = ip->type; + dip->major = ip->major; + dip->minor = ip->minor; + dip->nlink = ip->nlink; + dip->size = ip->size; + + memmove(dip->addrs, ip->addrs, sizeof(ip->addrs)); + log_write(bp); + brelse(bp); + + + goto next(...); +} + +__code idupfs_impl(struct fs_impl* fs, struct inode* ip, __code next(...)) { + + acquire(&icache.lock); + ip->ref++; + release(&icache.lock); + + goto next(ip, ...); + +} + +__code ilockfs_impl(struct fs_impl* fs, struct inode* ip, __code next(...)) { + + goto lockinode1(fs, ip, bp, dip, next(...)); +} + +__code iunlockfs_impl(struct fs_impl* fs, struct inode* ip, __code next(...)) { + + if (ip == 0 || !(ip->flags & I_BUSY) || ip->ref < 1) { + char* msg = "iunlock"; + struct Err* err = createKernelError(&proc->cbc_context); + Gearef(cbc_context, Err)->msg = msg; + goto meta(cbc_context, err->panic); + } + + acquire(&icache.lock); + ip->flags &= ~I_BUSY; + wakeup(ip); + release(&icache.lock); + + goto next(...); +} + +__code iputfs_impl(struct fs_impl* fs, struct inode* ip, __code next(...)) { + if (next == C_iputfs_impl) { + next = fs->next2; + } + goto iput_check(fs, ip, next(...)); + +} + +__code iunlockputfs_impl(struct fs_impl* fs, struct inode* ip, __code next(...)) { + fs->next2 = next; + goto iunlockfs_impl(ip, fs->iput, ...); +} + +typedef struct stat stat; +__code statifs_impl(struct fs_impl* fs , struct inode* ip, struct stat* st, __code next(...)) { //:skip + st->dev = ip->dev; + st->ino = ip->inum; + st->type = ip->type; + st->nlink = ip->nlink; + st->size = ip->size; + goto next(...); +} + +__code readifs_impl(struct fs_impl* fs, struct inode* ip, char* dst, uint off, uint tot, uint n, __code next(int ret, ...)) { + if (ip->type == T_DEV) { + goto readi_check_diskinode(fs, ip, dst, n, next(...)); + } + + if (off > ip->size || off + n < off) { + ret = -1; + goto next(ret, ...); + } + + if (off + n > ip->size) { + n = ip->size - off; + } + Gearef(cbc_context, fs)->tot = 0; + goto readi_loopcheck(fs, tot, m, dst, off, n, next(...)); +} + +__code writeifs_impl(struct fs_impl* fs, struct inode* ip, char* src, uint off, uint tot, uint n, __code next(int ret, ...)) { + if (ip->type == T_DEV) { + goto writei_check_diskinode(fs, ip, src, n, next(...)); + } + + if (off > ip->size || off + n < off) { + ret = -1; + goto next(ret, ...); + } + + if (off + n > MAXFILE * BSIZE) { + ret = -1; + goto next(ret, ...); + } + Gearef(cbc_context, fs)->tot = 0; + goto writei_loopcheck(fs, tot, m, src, off, n, next(...)); +} + + +__code namecmpfs_impl(struct fs_impl* fs, const char* s, const char* t, __code next(int strncmp_val, ...)) { + strncmp_val = strncmp(s, t, DIRSIZ); + goto next(strncmp_val, ...); +} + +__code dirlookupfs_impl(struct fs_impl* fs, struct inode* dp, char* name, uint off, uint* poff, dirent* de, __code next(...)) { //:skip + if (dp->type != T_DIR) { + char* msg = "dirlookup not DIR"; + struct Err* err = createKernelError(&proc->cbc_context); + Gearef(cbc_context, Err)->msg = msg; + goto meta(cbc_context, err->panic); + } + Gearef(cbc_context, fs)->off = 0; + goto dirlookup_loopcheck(fs, dp, name, off, poff, de, next(...)); +} + +__code dirlinkfs_impl(struct fs_impl* fs, struct inode* ip, struct dirent* de, struct inode* dp, char* name, uint off, uint inum, __code next(...)) { //:skip + // Check that name is not present. + if ((ip = dirlookup(dp, name, 0)) != 0) { + goto dirlink_namecheck(fs, ip, next(...)); + } + Gearef(cbc_context, fs)->off = 0; + goto dirlink_loopcheck(fs, de, dp, off, next(...)); +} + +static struct inode* iget (uint dev, uint inum) +{ + struct inode *ip, *empty; + + acquire(&icache.lock); + + // Is the inode already cached? + empty = 0; + + for (ip = &icache.inode[0]; ip < &icache.inode[NINODE]; ip++) { + if (ip->ref > 0 && ip->dev == dev && ip->inum == inum) { + ip->ref++; + release(&icache.lock); + return ip; + } + + if (empty == 0 && ip->ref == 0) { // Remember empty slot. + empty = ip; + } + } + + // Recycle an inode cache entry. + if (empty == 0) { + panic("iget: no inodes"); + } + + ip = empty; + ip->dev = dev; + ip->inum = inum; + ip->ref = 1; + ip->flags = 0; + release(&icache.lock); + + return ip; +} + +static char* skipelem (char *path, char *name) +{ + char *s; + int len; + + while (*path == '/') { + path++; + } + + if (*path == 0) { + return 0; + } + + s = path; + + while (*path != '/' && *path != 0) { + path++; + } + + len = path - s; + + if (len >= DIRSIZ) { + memmove(name, s, DIRSIZ); + } else { + memmove(name, s, len); + name[len] = 0; + } + + while (*path == '/') { + path++; + } + + return path; +} + + +static struct inode* namex (char *path, int nameiparent, char *name) +{ + struct inode *ip, *next; + + if (*path == '/') { + ip = iget(ROOTDEV, ROOTINO); + } else { + ip = idup(proc->cwd); + } + + while ((path = skipelem(path, name)) != 0) { + ilock(ip); + + if (ip->type != T_DIR) { + iunlockput(ip); + return 0; + } + + if (nameiparent && *path == '\0') { + // Stop one level early. + iunlock(ip); + return ip; + } + + if ((next = dirlookup(ip, name, 0)) == 0) { + iunlockput(ip); + return 0; + } + + iunlockput(ip); + ip = next; + } + + if (nameiparent) { + iput(ip); + return 0; + } + + return ip; +} + +__code nameifs_impl(struct fs_impl* fs, char* path, __code next(int namex_val, ...)) { + char name[DIRSIZ]; + namex_val = namex(path, 0, name); + goto next(namex_val, ...); +} + +__code nameiparentfs_impl(struct fs_impl* fs, char* path, char* name, __code next(int namex_val, ...)) { + + namex_val = namex(path, 1, name); + goto next(namex_val, ...); + +} + diff -r dca5e4f9fceb -r 40726bcd5272 final_main/src/fs_impl.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/final_main/src/fs_impl.h Sat Feb 08 21:05:19 2020 +0900 @@ -0,0 +1,47 @@ +typedef struct fs_impl impl fs{ + union Data* fs_impl; + struct superblock* sb; + int ret; + uint dev; + short type; + struct buf* bp; + struct dinode* dip; + uint inum; + struct inode* dp; + char* name; + uint off; + uint* poff; + dirent* de; + uint tot; + uint m; + char* dst; + uint n; + char* src; + + __code allocinode(Type* fs_impl, uint dev, struct superblock* sb, __code next(...)); + __code allocinode_loop(Type* fs_impl, uint inum, uint dev, short type, struct superblock* sb, struct buf* bp, struct dinode* dip, __code next(...)); + __code allocinode_loopcheck(Type* fs_impl, uint inum, uint dev, struct superblock* sb, struct buf* bp, struct dinode* dip, __code next(...)); + __code allocinode_noloop(Type* fs_impl, uint inum, uint dev, short type, struct superblock* sb, struct buf* bp, struct dinode* dip, __code next(int ret, ...)); + __code lockinode1(Type* fs_impl, struct inode *ip, struct buf *bp, struct dinode *dip, __code next(...)); + __code lockinode2(Type* fs_impl, struct inode* ip, struct buf* bp, struct dinode* dip, __code next(...)); + __code lockinode_sleepcheck(Type* fs_impl, struct inode* ip, __code next(...)); + __code iput_check(Type* fs_impl, struct inode* ip, __code next(...)); + __code iput_inode_nolink(Type* fs_impl, struct inode* ip, __code next(...)); + __code readi_check_diskinode(Type* fs_impl,struct inode* ip, char* dst, uint n, next(int ret, ...)); + __code readi_loopcheck(Type* fs_impl, uint tot, uint m, char* dst, uint off, uint n, __code next(...)); + __code readi_loop(Type* fs_impl, struct inode *ip, struct buf* bp, uint tot, uint m, char* dst, uint off, uint n, __code next(...)); + __code readi_noloop(Type* fs_impl, uint n, __code next(int ret, ...)); + __code writei_check_diskinode(Type* fs_impl,struct inode* ip, char* src, uint n, __code next(int ret, ...)); + __code writei_loopcheck(Type* fs_impl, uint tot, uint m, char* src, uint off, uint n, __code next(...)); + __code writei_loop(Type* fs_impl, struct inode* ip, struct buf* bp, uint tot, uint m, char* src, uint off, uint n, __code next(...)); + __code writei_noloop(Type* fs_impl, struct inode* ip, uint n, uint off, __code next(int ret, ...)); + __code dirlookup_loopcheck(Type* fs_impl, struct inode* dp, char* name, uint off, uint* poff, dirent* de, next(...)); + __code dirlookup_loop(Type* fs_impl, struct inode* dp, char* name, uint off, uint inum, uint* poff, dirent* de, __code next(int ret, ...)); + __code dirlookup_noloop(Type* fs_impl, __code next(int ret, ...)); + __code dirlink_namecheck(Type* fs_impl, struct inode* ip, __code next(int ret, ...)); + __code dirlink_loopcheck(Type* fs_impl, struct dirent* de, struct inode* dp, uint off, __code next(...)); + __code dirlink_loop(Type* fs_impl, struct dirent* de, struct inode* dp, uint off, uint inum, __code next(...)); + __code dirlink_noloop(Type* fs_impl, struct dirent* de, struct inode* dp, uint off, uint inum, char* name, __code next(int ret, ...)); + __code next(...); + __code next2(...); +} fs_impl; diff -r dca5e4f9fceb -r 40726bcd5272 final_main/src/fs_impl_private.cbc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/final_main/src/fs_impl_private.cbc Sat Feb 08 21:05:19 2020 +0900 @@ -0,0 +1,471 @@ +#include "types.h" +#include "defs.h" +#include "param.h" +#include "stat.h" +#include "mmu.h" +#include "proc.h" +#include "spinlock.h" +#include "buf.h" +#include "fs.h" +#include "file.h" +#interface "fs_impl.h" +#interface "Err.h" +#define min(a, b) ((a) < (b) ? (a) : (b)) + +/* +fs_impl* createfs_impl2(); +*/ + +__code allocinode(struct fs_impl* fs_impl, uint dev, struct superblock* sb, __code next(...)){ //:skip + + readsb(dev, sb); + Gearef(cbc_context, fs_impl)->inum = 1; + goto allocinode_loopcheck(fs_impl, inum, dev, sb, bp, dip, next(...)); + +} + +typedef struct buf buf; +typedef struct dinode dinode; + +__code allocinode_loopcheck(struct fs_impl* fs_impl, uint inum, uint dev, struct superblock* sb, struct buf* bp, struct dinode* dip, __code next(...)){ //:skip + if( inum < sb->ninodes){ + goto allocinode_loop(fs_impl, inum, dev, type, sb, bp, dip, next(...)); + } + char* msg = "failed allocinode..."; + struct Err* err = createKernelError(&proc->cbc_context); + Gearef(cbc_context, Err)->msg = msg; + goto meta(cbc_context, err->panic); + +} + +__code allocinode_loop(struct fs_impl* fs_impl, uint inum, uint dev, short type, struct superblock* sb, struct buf* bp, struct dinode* dip, __code next(...)){ //:skip + bp = bread(dev, IBLOCK(inum)); + dip = (struct dinode*) bp->data + inum % IPB; + if(dip->type = 0){ + goto allocinode_noloop(fs_impl, inum, dev, sb, bp, dip, next(...)); + } + + brelse(bp); + inum++; + goto allocinode_loopcheck(fs_impl, inum, dev, type, sb, bp, dip, next(...)); +} + +struct { + struct spinlock lock; + struct inode inode[NINODE]; +} icache; + +static struct inode* iget (uint dev, uint inum) +{ + struct inode *ip, *empty; + + acquire(&icache.lock); + + // Is the inode already cached? + empty = 0; + + for (ip = &icache.inode[0]; ip < &icache.inode[NINODE]; ip++) { + if (ip->ref > 0 && ip->dev == dev && ip->inum == inum) { + ip->ref++; + release(&icache.lock); + return ip; + } + + if (empty == 0 && ip->ref == 0) { // Remember empty slot. + empty = ip; + } + } + + // Recycle an inode cache entry. + if (empty == 0) { + panic("iget: no inodes"); + } + + ip = empty; + ip->dev = dev; + ip->inum = inum; + ip->ref = 1; + ip->flags = 0; + release(&icache.lock); + + return ip; +} + +__code allocinode_noloop(struct fs_impl* fs_impl, uint inum, uint dev, short type, struct superblock* sb, struct buf* bp, struct dinode* dip, __code next(int ret, ...)){ //:skip + + memset(dip, 0, sizeof(*dip)); + dip->type = type; + log_write(bp); + brelse(bp); + + ret = iget(dev, inum); + goto next(ret, ...); + +} + +__code lockinode1(struct fs_impl* fs_impl, struct inode* ip, struct buf* bp, struct dinode* dip, __code next(...)){ //:skip + + if (ip == 0 || ip->ref < 1) { + char* msg = "ilock"; + struct Err* err = createKernelError(&proc->cbc_context); + Gearef(cbc_context, Err)->msg = msg; + goto meta(cbc_context, err->panic); + } + acquire(&icache.lock); + + goto lockinode_sleepcheck(fs_impl, ip, next(...)); + +} + + +__code lockinode2(struct fs_impl* fs_impl, struct inode* ip, struct buf* bp, struct dinode* dip, __code next(...)){ //:skip + + ip->flags |= I_BUSY; + release(&icache.lock); + + if (!(ip->flags & I_VALID)) { + bp = bread(ip->dev, IBLOCK(ip->inum)); + + dip = (struct dinode*) bp->data + ip->inum % IPB; + ip->type = dip->type; + ip->major = dip->major; + ip->minor = dip->minor; + ip->nlink = dip->nlink; + ip->size = dip->size; + + memmove(ip->addrs, dip->addrs, sizeof(ip->addrs)); + brelse(bp); + ip->flags |= I_VALID; + + if (ip->type == 0) { + char* msg = "ilock: no type"; + struct Err* err = createKernelError(&proc->cbc_context); + Gearef(cbc_context, Err)->msg = msg; + goto meta(cbc_context, err->panic); + } + } + goto next(...); +} +__code lockinode_sleepcheck(struct fs_impl* fs_impl, struct inode* ip, __code next(...)){ + if(ip->flags & I_BUSY){ + sleep(ip, &icache.lock); + goto lockinode_sleepcheck(fs_impl, ip, next(...)); + } + goto lockinode2(fs_impl, ip, bp, dip, next(...)); +} + +__code iput_check(struct fs_impl* fs_impl, struct inode* ip, __code next(...)){ + acquire(&icache.lock); + if (ip->ref == 1 && (ip->flags & I_VALID) && ip->nlink == 0) { + goto iput_inode_nolink(fs_impl, ip, next(...)); + } + ip->ref--; + release(&icache.lock); + goto next(...); + +} + +static void bfree (int dev, uint b) +{ + struct buf *bp; + struct superblock sb; + int bi, m; + + readsb(dev, &sb); + bp = bread(dev, BBLOCK(b, sb.ninodes)); + bi = b % BPB; + m = 1 << (bi % 8); + + if ((bp->data[bi / 8] & m) == 0) { + panic("freeing free block"); + } + + bp->data[bi / 8] &= ~m; + log_write(bp); + brelse(bp); +} + + +static void itrunc (struct inode *ip) +{ + int i, j; + struct buf *bp; + uint *a; + + for (i = 0; i < NDIRECT; i++) { + if (ip->addrs[i]) { + bfree(ip->dev, ip->addrs[i]); + ip->addrs[i] = 0; + } + } + + if (ip->addrs[NDIRECT]) { + bp = bread(ip->dev, ip->addrs[NDIRECT]); + a = (uint*) bp->data; + + for (j = 0; j < NINDIRECT; j++) { + if (a[j]) { + bfree(ip->dev, a[j]); + } + } + + brelse(bp); + bfree(ip->dev, ip->addrs[NDIRECT]); + ip->addrs[NDIRECT] = 0; + } + + ip->size = 0; + iupdate(ip); +} + +__code iput_inode_nolink(struct fs_impl* fs_impl, struct inode* ip, __code next(...)){ + + if (ip->flags & I_BUSY) { + char* msg = "iput busy"; + struct Err* err = createKernelError(&proc->cbc_context); + Gearef(cbc_context, Err)->msg = msg; + goto meta(cbc_context, err->panic); + } + + ip->flags |= I_BUSY; + release(&icache.lock); + itrunc(ip); + ip->type = 0; + iupdate(ip); + + acquire(&icache.lock); + ip->flags = 0; + wakeup(ip); + goto next(...); +} + +__code readi_check_diskinode(struct fs_impl* fs_impl,struct inode* ip, char* dst, uint n, __code next(int ret, ...)){ + if (ip->major < 0 || ip->major >= NDEV || !devsw[ip->major].read) { + ret = -1; + goto next(ret, ...); + } + + ret = devsw[ip->major].read(ip, dst, n); + goto next(ret, ...); +} + +__code readi_loopcheck(struct fs_impl* fs_impl, uint tot, uint m, char* dst, uint off, uint n, __code next(...)){ + if(tot < n){ + goto readi_loop(fs_impl, ip, bp, tot, m, dst, off, n, next(...)); + } + goto readi_noloop(fs_impl, next(...)); +} + +static void bzero (int dev, int bno) +{ + struct buf *bp; + + bp = bread(dev, bno); + memset(bp->data, 0, BSIZE); + log_write(bp); + brelse(bp); +} + +static uint balloc (uint dev) +{ + int b, bi, m; + struct buf *bp; + struct superblock sb; + + bp = 0; + readsb(dev, &sb); + + for (b = 0; b < sb.size; b += BPB) { + bp = bread(dev, BBLOCK(b, sb.ninodes)); + + for (bi = 0; bi < BPB && b + bi < sb.size; bi++) { + m = 1 << (bi % 8); + + if ((bp->data[bi / 8] & m) == 0) { // Is block free? + bp->data[bi / 8] |= m; // Mark block in use. + log_write(bp); + brelse(bp); + bzero(dev, b + bi); + return b + bi; + } + } + + brelse(bp); + } + + panic("balloc: out of blocks"); +} + + +static uint bmap (struct inode *ip, uint bn) +{ + uint addr, *a; + struct buf *bp; + + if (bn < NDIRECT) { + if ((addr = ip->addrs[bn]) == 0) { + ip->addrs[bn] = addr = balloc(ip->dev); + } + + return addr; + } + + bn -= NDIRECT; + + if (bn < NINDIRECT) { + // Load indirect block, allocating if necessary. + if ((addr = ip->addrs[NDIRECT]) == 0) { + ip->addrs[NDIRECT] = addr = balloc(ip->dev); + } + + bp = bread(ip->dev, addr); + a = (uint*) bp->data; + + if ((addr = a[bn]) == 0) { + a[bn] = addr = balloc(ip->dev); + log_write(bp); + } + + brelse(bp); + return addr; + } + + panic("bmap: out of range"); +} + + +__code readi_loop(struct fs_impl* fs_impl, struct inode* ip, struct buf* bp, uint tot, uint m, char* dst, uint off, uint n, __code next(...)){ //:skip + bp = bread(ip->dev, bmap(ip, off / BSIZE)); + m = min(n - tot, BSIZE - off%BSIZE); + memmove(dst, bp->data + off % BSIZE, m); + brelse(bp); + tot += m; + off += m; + dst += m; + goto readi_loopcheck(fs_impl, tot, m, dst, off, n, next(...)); +} + +__code readi_noloop(struct fs_impl* fs_impl, uint n, __code next(int ret, ...)){ + ret = n; + goto next(ret, ...); +} + +__code writei_check_diskinode(struct fs_impl* fs_impl,struct inode* ip, char* src, uint n, __code next(int ret, ...)){ + if (ip->major < 0 || ip->major >= NDEV || !devsw[ip->major].write) { + ret = -1; + goto next(ret, ...); + } + + ret = devsw[ip->major].write(ip, src, n); + goto next(ret, ...); +} + +__code writei_loopcheck(struct fs_impl* fs_impl, uint tot, uint m, char* src, uint off, uint n, __code next(...)){ + if(tot < n){ + goto writei_loop(fs_impl, ip, bp, tot, m, src, off, n, next(...)); + } + goto writei_noloop(fs_impl, next(...)); +} + +__code writei_loop(struct fs_impl* fs_impl, struct inode* ip, struct buf* bp, uint tot, uint m, char* src, uint off, uint n, __code next(...)){ //:skip + bp = bread(ip->dev, bmap(ip, off / BSIZE)); + m = min(n - tot, BSIZE - off%BSIZE); + memmove(bp->data + off % BSIZE, src, m); + log_write(bp); + brelse(bp); + tot += m; + off += m; + src += m; + goto writei_loopcheck(fs_impl, tot, m, src, off, n, next(...)); +} + +__code writei_noloop(struct fs_impl* fs_impl, struct inode* ip, uint n, uint off, __code next(int ret, ...)){ + if (n > 0 && off > ip->size) { + ip->size = off; + iupdate(ip); + } + ret = n; + goto next(ret, ...); +} +typedef struct dirent dirent; +__code dirlookup_loopcheck(struct fs_impl* fs_impl, struct inode* dp, char* name, uint off, uint* poff, dirent* de, __code next(...)){ //:skip + if(off < dp->size){ + goto dirlookup_loop(fs_impl, dp, name, off, inum, poff, de, next(...)); + } + goto dirlookup_noloop(fs_impl, next(...)); +} + +__code dirlookup_loop(struct fs_impl* fs_impl, struct inode* dp, char* name, uint off, uint inum, uint* poff, dirent* de, __code next(int ret, ...)){ + if (readi(dp, (char*) &de, off, sizeof(de)) != sizeof(de)) { + char* msg = "dirlink read"; + struct Err* err = createKernelError(&proc->cbc_context); + Gearef(cbc_context, Err)->msg = msg; + goto meta(cbc_context, err->panic); + } + + if (de->inum == 0) { + off += sizeof(de); + goto dirlookup_loopcheck(fs_impl, dp, name, poff, de, next(...)); + } + + if (namecmp(name, de->name) == 0) { + // entry matches path element + if (poff) { + *poff = off; + } + + inum = de->inum; + ret = iget(dp->dev, inum); + goto next(ret, ...); + } + + off += sizeof(de); + goto dirlookup_loopcheck(fs_impl, dp, name, poff, de, next(...)); +} + +__code dirlookup_noloop(struct fs_impl* fs_impl, __code next(int ret, ...)){ + ret = 0; + goto next(ret, ...); +} + +__code dirlink_namecheck(struct fs_impl* fs_impl, struct inode* ip, __code next(int ret, ...)){ + iput(ip); + ret = -1; + goto next(ret, ...); +} + +__code dirlink_loopcheck(struct fs_impl* fs_impl, struct dirent* de, struct inode* dp, uint off, __code next(...)){ //:skip + if(off < dp->size){ + goto dirlink_loop(fs_impl, de, dp, off, inum, next(...)); + } + goto dirlink_noloop(fs_impl, de, dp, off, inum, name, next(...)); +} + +__code dirlink_loop(struct fs_impl* fs_impl, struct dirent* de, struct inode* dp, uint off, uint inum, __code next(...)){ //:skip + if (readi(dp, (char*) &de, off, sizeof(de)) != sizeof(de)) { + char* msg = "dirlink read"; + struct Err* err = createKernelError(&proc->cbc_context); + Gearef(cbc_context, Err)->msg = msg; + goto meta(cbc_context, err->panic); + } + + if (de->inum == 0) { + goto dirlink_noloop(fs_impl, de, dp, off, inum, name, next(...)); + } + + goto dirlink_loopcheck(fs_impl, de, dp, off + sizeof(de), next(...)); +} + +__code dirlink_noloop(struct fs_impl* fs_impl, struct dirent* de, struct inode* dp, uint off, uint inum, char* name, __code next(int ret, ...)){ //:skip + strncpy(de->name, name, DIRSIZ); + de->inum = inum; + + if (writei(dp, (char*) &de, off, sizeof(de)) != sizeof(de)) { + char* msg = "dirlink read"; + struct Err* err = createKernelError(&proc->cbc_context); + Gearef(cbc_context, Err)->msg = msg; + goto meta(cbc_context, err->panic); + } + ret = 0; + goto next(ret, ...); +}