clang-format

This commit is contained in:
2024-09-10 13:03:02 -04:00
parent 53c617d779
commit d66450e427
381 changed files with 28864 additions and 34170 deletions

View File

@@ -42,7 +42,7 @@
* Constants
*/
#define SEMFS_ROOTDIR 0xffffffffU /* semnum for root dir */
#define SEMFS_ROOTDIR 0xffffffffU /* semnum for root dir */
/*
* A user-facing semaphore.
@@ -52,11 +52,11 @@
* XXX: or would we? review once all this is done.
*/
struct semfs_sem {
struct lock *sems_lock; /* Lock to protect count */
struct cv *sems_cv; /* CV to wait */
unsigned sems_count; /* Semaphore count */
bool sems_hasvnode; /* The vnode exists */
bool sems_linked; /* In the directory */
struct lock *sems_lock; /* Lock to protect count */
struct cv *sems_cv; /* CV to wait */
unsigned sems_count; /* Semaphore count */
bool sems_hasvnode; /* The vnode exists */
bool sems_linked; /* In the directory */
};
DECLARRAY(semfs_sem, SEMFS_INLINE);
@@ -64,8 +64,8 @@ DECLARRAY(semfs_sem, SEMFS_INLINE);
* Directory entry; name and reference to a semaphore.
*/
struct semfs_direntry {
char *semd_name; /* Name */
unsigned semd_semnum; /* Which semaphore */
char *semd_name; /* Name */
unsigned semd_semnum; /* Which semaphore */
};
DECLARRAY(semfs_direntry, SEMFS_INLINE);
@@ -77,9 +77,9 @@ DECLARRAY(semfs_direntry, SEMFS_INLINE);
* practice. XXX: review after finishing)
*/
struct semfs_vnode {
struct vnode semv_absvn; /* Abstract vnode */
struct semfs *semv_semfs; /* Back-pointer to fs */
unsigned semv_semnum; /* Which semaphore */
struct vnode semv_absvn; /* Abstract vnode */
struct semfs *semv_semfs; /* Back-pointer to fs */
unsigned semv_semnum; /* Which semaphore */
};
/*
@@ -87,14 +87,14 @@ struct semfs_vnode {
* is only one of these.
*/
struct semfs {
struct fs semfs_absfs; /* Abstract fs object */
struct fs semfs_absfs; /* Abstract fs object */
struct lock *semfs_tablelock; /* Lock for following */
struct vnodearray *semfs_vnodes; /* Currently extant vnodes */
struct semfs_semarray *semfs_sems; /* Semaphores */
struct lock *semfs_tablelock; /* Lock for following */
struct vnodearray *semfs_vnodes; /* Currently extant vnodes */
struct semfs_semarray *semfs_sems; /* Semaphores */
struct lock *semfs_dirlock; /* Lock for following */
struct semfs_direntryarray *semfs_dents; /* The root directory */
struct lock *semfs_dirlock; /* Lock for following */
struct semfs_direntryarray *semfs_dents; /* The root directory */
};
/*
@@ -104,7 +104,6 @@ struct semfs {
DEFARRAY(semfs_sem, SEMFS_INLINE);
DEFARRAY(semfs_direntry, SEMFS_INLINE);
/*
* Functions.
*/
@@ -119,5 +118,4 @@ void semfs_direntry_destroy(struct semfs_direntry *);
/* in semfs_vnops.c */
int semfs_getvnode(struct semfs *, unsigned, struct vnode **ret);
#endif /* SEMFS_H */

View File

@@ -42,185 +42,163 @@
/*
* Sync doesn't need to do anything.
*/
static
int
semfs_sync(struct fs *fs)
{
(void)fs;
return 0;
static int semfs_sync(struct fs *fs) {
(void)fs;
return 0;
}
/*
* We have only one volume name and it's hardwired.
*/
static
const char *
semfs_getvolname(struct fs *fs)
{
(void)fs;
return "sem";
static const char *semfs_getvolname(struct fs *fs) {
(void)fs;
return "sem";
}
/*
* Get the root directory vnode.
*/
static
int
semfs_getroot(struct fs *fs, struct vnode **ret)
{
struct semfs *semfs = fs->fs_data;
struct vnode *vn;
int result;
static int semfs_getroot(struct fs *fs, struct vnode **ret) {
struct semfs *semfs = fs->fs_data;
struct vnode *vn;
int result;
result = semfs_getvnode(semfs, SEMFS_ROOTDIR, &vn);
if (result) {
kprintf("semfs: couldn't load root vnode: %s\n",
strerror(result));
return result;
}
*ret = vn;
return 0;
result = semfs_getvnode(semfs, SEMFS_ROOTDIR, &vn);
if (result) {
kprintf("semfs: couldn't load root vnode: %s\n", strerror(result));
return result;
}
*ret = vn;
return 0;
}
////////////////////////////////////////////////////////////
// mount and unmount logic
/*
* Destructor for struct semfs.
*/
static
void
semfs_destroy(struct semfs *semfs)
{
struct semfs_sem *sem;
struct semfs_direntry *dent;
unsigned i, num;
static void semfs_destroy(struct semfs *semfs) {
struct semfs_sem *sem;
struct semfs_direntry *dent;
unsigned i, num;
num = semfs_semarray_num(semfs->semfs_sems);
for (i=0; i<num; i++) {
sem = semfs_semarray_get(semfs->semfs_sems, i);
semfs_sem_destroy(sem);
}
semfs_semarray_setsize(semfs->semfs_sems, 0);
num = semfs_semarray_num(semfs->semfs_sems);
for (i = 0; i < num; i++) {
sem = semfs_semarray_get(semfs->semfs_sems, i);
semfs_sem_destroy(sem);
}
semfs_semarray_setsize(semfs->semfs_sems, 0);
num = semfs_direntryarray_num(semfs->semfs_dents);
for (i=0; i<num; i++) {
dent = semfs_direntryarray_get(semfs->semfs_dents, i);
semfs_direntry_destroy(dent);
}
semfs_direntryarray_setsize(semfs->semfs_dents, 0);
num = semfs_direntryarray_num(semfs->semfs_dents);
for (i = 0; i < num; i++) {
dent = semfs_direntryarray_get(semfs->semfs_dents, i);
semfs_direntry_destroy(dent);
}
semfs_direntryarray_setsize(semfs->semfs_dents, 0);
semfs_direntryarray_destroy(semfs->semfs_dents);
lock_destroy(semfs->semfs_dirlock);
semfs_semarray_destroy(semfs->semfs_sems);
vnodearray_destroy(semfs->semfs_vnodes);
lock_destroy(semfs->semfs_tablelock);
kfree(semfs);
semfs_direntryarray_destroy(semfs->semfs_dents);
lock_destroy(semfs->semfs_dirlock);
semfs_semarray_destroy(semfs->semfs_sems);
vnodearray_destroy(semfs->semfs_vnodes);
lock_destroy(semfs->semfs_tablelock);
kfree(semfs);
}
/*
* Unmount routine. XXX: Since semfs is attached at boot and can't be
* remounted, maybe unmounting it shouldn't be allowed.
*/
static
int
semfs_unmount(struct fs *fs)
{
struct semfs *semfs = fs->fs_data;
static int semfs_unmount(struct fs *fs) {
struct semfs *semfs = fs->fs_data;
lock_acquire(semfs->semfs_tablelock);
if (vnodearray_num(semfs->semfs_vnodes) > 0) {
lock_release(semfs->semfs_tablelock);
return EBUSY;
}
lock_acquire(semfs->semfs_tablelock);
if (vnodearray_num(semfs->semfs_vnodes) > 0) {
lock_release(semfs->semfs_tablelock);
return EBUSY;
}
lock_release(semfs->semfs_tablelock);
semfs_destroy(semfs);
lock_release(semfs->semfs_tablelock);
semfs_destroy(semfs);
return 0;
return 0;
}
/*
* Operations table.
*/
static const struct fs_ops semfs_fsops = {
.fsop_sync = semfs_sync,
.fsop_getvolname = semfs_getvolname,
.fsop_getroot = semfs_getroot,
.fsop_unmount = semfs_unmount,
.fsop_sync = semfs_sync,
.fsop_getvolname = semfs_getvolname,
.fsop_getroot = semfs_getroot,
.fsop_unmount = semfs_unmount,
};
/*
* Constructor for struct semfs.
*/
static
struct semfs *
semfs_create(void)
{
struct semfs *semfs;
static struct semfs *semfs_create(void) {
struct semfs *semfs;
semfs = kmalloc(sizeof(*semfs));
if (semfs == NULL) {
goto fail_total;
}
semfs = kmalloc(sizeof(*semfs));
if (semfs == NULL) {
goto fail_total;
}
semfs->semfs_tablelock = lock_create("semfs_table");
if (semfs->semfs_tablelock == NULL) {
goto fail_semfs;
}
semfs->semfs_vnodes = vnodearray_create();
if (semfs->semfs_vnodes == NULL) {
goto fail_tablelock;
}
semfs->semfs_sems = semfs_semarray_create();
if (semfs->semfs_sems == NULL) {
goto fail_vnodes;
}
semfs->semfs_tablelock = lock_create("semfs_table");
if (semfs->semfs_tablelock == NULL) {
goto fail_semfs;
}
semfs->semfs_vnodes = vnodearray_create();
if (semfs->semfs_vnodes == NULL) {
goto fail_tablelock;
}
semfs->semfs_sems = semfs_semarray_create();
if (semfs->semfs_sems == NULL) {
goto fail_vnodes;
}
semfs->semfs_dirlock = lock_create("semfs_dir");
if (semfs->semfs_dirlock == NULL) {
goto fail_sems;
}
semfs->semfs_dents = semfs_direntryarray_create();
if (semfs->semfs_dents == NULL) {
goto fail_dirlock;
}
semfs->semfs_dirlock = lock_create("semfs_dir");
if (semfs->semfs_dirlock == NULL) {
goto fail_sems;
}
semfs->semfs_dents = semfs_direntryarray_create();
if (semfs->semfs_dents == NULL) {
goto fail_dirlock;
}
semfs->semfs_absfs.fs_data = semfs;
semfs->semfs_absfs.fs_ops = &semfs_fsops;
return semfs;
semfs->semfs_absfs.fs_data = semfs;
semfs->semfs_absfs.fs_ops = &semfs_fsops;
return semfs;
fail_dirlock:
lock_destroy(semfs->semfs_dirlock);
fail_sems:
semfs_semarray_destroy(semfs->semfs_sems);
fail_vnodes:
vnodearray_destroy(semfs->semfs_vnodes);
fail_tablelock:
lock_destroy(semfs->semfs_tablelock);
fail_semfs:
kfree(semfs);
fail_total:
return NULL;
fail_dirlock:
lock_destroy(semfs->semfs_dirlock);
fail_sems:
semfs_semarray_destroy(semfs->semfs_sems);
fail_vnodes:
vnodearray_destroy(semfs->semfs_vnodes);
fail_tablelock:
lock_destroy(semfs->semfs_tablelock);
fail_semfs:
kfree(semfs);
fail_total:
return NULL;
}
/*
* Create the semfs. There is only one semfs and it's attached as
* "sem:" during bootup.
*/
void
semfs_bootstrap(void)
{
struct semfs *semfs;
int result;
void semfs_bootstrap(void) {
struct semfs *semfs;
int result;
semfs = semfs_create();
if (semfs == NULL) {
panic("Out of memory creating semfs\n");
}
result = vfs_addfs("sem", &semfs->semfs_absfs);
if (result) {
panic("Attaching semfs: %s\n", strerror(result));
}
semfs = semfs_create();
if (semfs == NULL) {
panic("Out of memory creating semfs\n");
}
result = vfs_addfs("sem", &semfs->semfs_absfs);
if (result) {
panic("Attaching semfs: %s\n", strerror(result));
}
}

View File

@@ -40,74 +40,69 @@
/*
* Constructor for semfs_sem.
*/
struct semfs_sem *
semfs_sem_create(const char *name)
{
struct semfs_sem *sem;
char lockname[32];
char cvname[32];
struct semfs_sem *semfs_sem_create(const char *name) {
struct semfs_sem *sem;
char lockname[32];
char cvname[32];
snprintf(lockname, sizeof(lockname), "sem:l.%s", name);
snprintf(cvname, sizeof(cvname), "sem:%s", name);
snprintf(lockname, sizeof(lockname), "sem:l.%s", name);
snprintf(cvname, sizeof(cvname), "sem:%s", name);
sem = kmalloc(sizeof(*sem));
if (sem == NULL) {
goto fail_return;
}
sem->sems_lock = lock_create(lockname);
if (sem->sems_lock == NULL) {
goto fail_sem;
}
sem->sems_cv = cv_create(cvname);
if (sem->sems_cv == NULL) {
goto fail_lock;
}
sem->sems_count = 0;
sem->sems_hasvnode = false;
sem->sems_linked = false;
return sem;
sem = kmalloc(sizeof(*sem));
if (sem == NULL) {
goto fail_return;
}
sem->sems_lock = lock_create(lockname);
if (sem->sems_lock == NULL) {
goto fail_sem;
}
sem->sems_cv = cv_create(cvname);
if (sem->sems_cv == NULL) {
goto fail_lock;
}
sem->sems_count = 0;
sem->sems_hasvnode = false;
sem->sems_linked = false;
return sem;
fail_lock:
lock_destroy(sem->sems_lock);
fail_sem:
kfree(sem);
fail_return:
return NULL;
fail_lock:
lock_destroy(sem->sems_lock);
fail_sem:
kfree(sem);
fail_return:
return NULL;
}
/*
* Destructor for semfs_sem.
*/
void
semfs_sem_destroy(struct semfs_sem *sem)
{
cv_destroy(sem->sems_cv);
lock_destroy(sem->sems_lock);
kfree(sem);
void semfs_sem_destroy(struct semfs_sem *sem) {
cv_destroy(sem->sems_cv);
lock_destroy(sem->sems_lock);
kfree(sem);
}
/*
* Helper to insert a semfs_sem into the semaphore table.
*/
int
semfs_sem_insert(struct semfs *semfs, struct semfs_sem *sem, unsigned *ret)
{
unsigned i, num;
int semfs_sem_insert(struct semfs *semfs, struct semfs_sem *sem,
unsigned *ret) {
unsigned i, num;
KASSERT(lock_do_i_hold(semfs->semfs_tablelock));
num = semfs_semarray_num(semfs->semfs_sems);
if (num == SEMFS_ROOTDIR) {
/* Too many */
return ENOSPC;
}
for (i=0; i<num; i++) {
if (semfs_semarray_get(semfs->semfs_sems, i) == NULL) {
semfs_semarray_set(semfs->semfs_sems, i, sem);
*ret = i;
return 0;
}
}
return semfs_semarray_add(semfs->semfs_sems, sem, ret);
KASSERT(lock_do_i_hold(semfs->semfs_tablelock));
num = semfs_semarray_num(semfs->semfs_sems);
if (num == SEMFS_ROOTDIR) {
/* Too many */
return ENOSPC;
}
for (i = 0; i < num; i++) {
if (semfs_semarray_get(semfs->semfs_sems, i) == NULL) {
semfs_semarray_set(semfs->semfs_sems, i, sem);
*ret = i;
return 0;
}
}
return semfs_semarray_add(semfs->semfs_sems, sem, ret);
}
////////////////////////////////////////////////////////////
@@ -116,30 +111,27 @@ semfs_sem_insert(struct semfs *semfs, struct semfs_sem *sem, unsigned *ret)
/*
* Constructor for semfs_direntry.
*/
struct semfs_direntry *
semfs_direntry_create(const char *name, unsigned semnum)
{
struct semfs_direntry *dent;
struct semfs_direntry *semfs_direntry_create(const char *name,
unsigned semnum) {
struct semfs_direntry *dent;
dent = kmalloc(sizeof(*dent));
if (dent == NULL) {
return NULL;
}
dent->semd_name = kstrdup(name);
if (dent->semd_name == NULL) {
kfree(dent);
return NULL;
}
dent->semd_semnum = semnum;
return dent;
dent = kmalloc(sizeof(*dent));
if (dent == NULL) {
return NULL;
}
dent->semd_name = kstrdup(name);
if (dent->semd_name == NULL) {
kfree(dent);
return NULL;
}
dent->semd_semnum = semnum;
return dent;
}
/*
* Destructor for semfs_direntry.
*/
void
semfs_direntry_destroy(struct semfs_direntry *dent)
{
kfree(dent->semd_name);
kfree(dent);
void semfs_direntry_destroy(struct semfs_direntry *dent) {
kfree(dent->semd_name);
kfree(dent);
}

File diff suppressed because it is too large Load Diff

View File

@@ -41,63 +41,53 @@
/*
* Zero out a disk block.
*/
static
int
sfs_clearblock(struct sfs_fs *sfs, daddr_t block)
{
/* static -> automatically initialized to zero */
static char zeros[SFS_BLOCKSIZE];
static int sfs_clearblock(struct sfs_fs *sfs, daddr_t block) {
/* static -> automatically initialized to zero */
static char zeros[SFS_BLOCKSIZE];
return sfs_writeblock(sfs, block, zeros, SFS_BLOCKSIZE);
return sfs_writeblock(sfs, block, zeros, SFS_BLOCKSIZE);
}
/*
* Allocate a block.
*/
int
sfs_balloc(struct sfs_fs *sfs, daddr_t *diskblock)
{
int result;
int sfs_balloc(struct sfs_fs *sfs, daddr_t *diskblock) {
int result;
result = bitmap_alloc(sfs->sfs_freemap, diskblock);
if (result) {
return result;
}
sfs->sfs_freemapdirty = true;
result = bitmap_alloc(sfs->sfs_freemap, diskblock);
if (result) {
return result;
}
sfs->sfs_freemapdirty = true;
if (*diskblock >= sfs->sfs_sb.sb_nblocks) {
panic("sfs: %s: balloc: invalid block %u\n",
sfs->sfs_sb.sb_volname, *diskblock);
}
if (*diskblock >= sfs->sfs_sb.sb_nblocks) {
panic("sfs: %s: balloc: invalid block %u\n", sfs->sfs_sb.sb_volname,
*diskblock);
}
/* Clear block before returning it */
result = sfs_clearblock(sfs, *diskblock);
if (result) {
bitmap_unmark(sfs->sfs_freemap, *diskblock);
}
return result;
/* Clear block before returning it */
result = sfs_clearblock(sfs, *diskblock);
if (result) {
bitmap_unmark(sfs->sfs_freemap, *diskblock);
}
return result;
}
/*
* Free a block.
*/
void
sfs_bfree(struct sfs_fs *sfs, daddr_t diskblock)
{
bitmap_unmark(sfs->sfs_freemap, diskblock);
sfs->sfs_freemapdirty = true;
void sfs_bfree(struct sfs_fs *sfs, daddr_t diskblock) {
bitmap_unmark(sfs->sfs_freemap, diskblock);
sfs->sfs_freemapdirty = true;
}
/*
* Check if a block is in use.
*/
int
sfs_bused(struct sfs_fs *sfs, daddr_t diskblock)
{
if (diskblock >= sfs->sfs_sb.sb_nblocks) {
panic("sfs: %s: sfs_bused called on out of range block %u\n",
sfs->sfs_sb.sb_volname, diskblock);
}
return bitmap_isset(sfs->sfs_freemap, diskblock);
int sfs_bused(struct sfs_fs *sfs, daddr_t diskblock) {
if (diskblock >= sfs->sfs_sb.sb_nblocks) {
panic("sfs: %s: sfs_bused called on out of range block %u\n",
sfs->sfs_sb.sb_volname, diskblock);
}
return bitmap_isset(sfs->sfs_freemap, diskblock);
}

View File

@@ -45,259 +45,250 @@
* file. If DOALLOC is set, and no such block exists, one will be
* allocated.
*/
int
sfs_bmap(struct sfs_vnode *sv, uint32_t fileblock, bool doalloc,
daddr_t *diskblock)
{
/*
* I/O buffer for handling indirect blocks.
*
* Note: in real life (and when you've done the fs assignment)
* you would get space from the disk buffer cache for this,
* not use a static area.
*/
static uint32_t idbuf[SFS_DBPERIDB];
int sfs_bmap(struct sfs_vnode *sv, uint32_t fileblock, bool doalloc,
daddr_t *diskblock) {
/*
* I/O buffer for handling indirect blocks.
*
* Note: in real life (and when you've done the fs assignment)
* you would get space from the disk buffer cache for this,
* not use a static area.
*/
static uint32_t idbuf[SFS_DBPERIDB];
struct sfs_fs *sfs = sv->sv_absvn.vn_fs->fs_data;
daddr_t block;
daddr_t idblock;
uint32_t idnum, idoff;
int result;
struct sfs_fs *sfs = sv->sv_absvn.vn_fs->fs_data;
daddr_t block;
daddr_t idblock;
uint32_t idnum, idoff;
int result;
KASSERT(sizeof(idbuf)==SFS_BLOCKSIZE);
KASSERT(sizeof(idbuf) == SFS_BLOCKSIZE);
/* Since we're using a static buffer, we'd better be locked. */
KASSERT(vfs_biglock_do_i_hold());
/* Since we're using a static buffer, we'd better be locked. */
KASSERT(vfs_biglock_do_i_hold());
/*
* If the block we want is one of the direct blocks...
*/
if (fileblock < SFS_NDIRECT) {
/*
* Get the block number
*/
block = sv->sv_i.sfi_direct[fileblock];
/*
* If the block we want is one of the direct blocks...
*/
if (fileblock < SFS_NDIRECT) {
/*
* Get the block number
*/
block = sv->sv_i.sfi_direct[fileblock];
/*
* Do we need to allocate?
*/
if (block==0 && doalloc) {
result = sfs_balloc(sfs, &block);
if (result) {
return result;
}
/*
* Do we need to allocate?
*/
if (block == 0 && doalloc) {
result = sfs_balloc(sfs, &block);
if (result) {
return result;
}
/* Remember what we allocated; mark inode dirty */
sv->sv_i.sfi_direct[fileblock] = block;
sv->sv_dirty = true;
}
/* Remember what we allocated; mark inode dirty */
sv->sv_i.sfi_direct[fileblock] = block;
sv->sv_dirty = true;
}
/*
* Hand back the block
*/
if (block != 0 && !sfs_bused(sfs, block)) {
panic("sfs: %s: Data block %u (block %u of file %u) "
"marked free\n", sfs->sfs_sb.sb_volname,
block, fileblock, sv->sv_ino);
}
*diskblock = block;
return 0;
}
/*
* Hand back the block
*/
if (block != 0 && !sfs_bused(sfs, block)) {
panic("sfs: %s: Data block %u (block %u of file %u) "
"marked free\n",
sfs->sfs_sb.sb_volname, block, fileblock, sv->sv_ino);
}
*diskblock = block;
return 0;
}
/*
* It's not a direct block; it must be in the indirect block.
* Subtract off the number of direct blocks, so FILEBLOCK is
* now the offset into the indirect block space.
*/
/*
* It's not a direct block; it must be in the indirect block.
* Subtract off the number of direct blocks, so FILEBLOCK is
* now the offset into the indirect block space.
*/
fileblock -= SFS_NDIRECT;
fileblock -= SFS_NDIRECT;
/* Get the indirect block number and offset w/i that indirect block */
idnum = fileblock / SFS_DBPERIDB;
idoff = fileblock % SFS_DBPERIDB;
/* Get the indirect block number and offset w/i that indirect block */
idnum = fileblock / SFS_DBPERIDB;
idoff = fileblock % SFS_DBPERIDB;
/*
* We only have one indirect block. If the offset we were asked for
* is too large, we can't handle it, so fail.
*/
if (idnum >= SFS_NINDIRECT) {
return EFBIG;
}
/*
* We only have one indirect block. If the offset we were asked for
* is too large, we can't handle it, so fail.
*/
if (idnum >= SFS_NINDIRECT) {
return EFBIG;
}
/* Get the disk block number of the indirect block. */
idblock = sv->sv_i.sfi_indirect;
/* Get the disk block number of the indirect block. */
idblock = sv->sv_i.sfi_indirect;
if (idblock==0 && !doalloc) {
/*
* There's no indirect block allocated. We weren't
* asked to allocate anything, so pretend the indirect
* block was filled with all zeros.
*/
*diskblock = 0;
return 0;
}
else if (idblock==0) {
/*
* There's no indirect block allocated, but we need to
* allocate a block whose number needs to be stored in
* the indirect block. Thus, we need to allocate an
* indirect block.
*/
result = sfs_balloc(sfs, &idblock);
if (result) {
return result;
}
if (idblock == 0 && !doalloc) {
/*
* There's no indirect block allocated. We weren't
* asked to allocate anything, so pretend the indirect
* block was filled with all zeros.
*/
*diskblock = 0;
return 0;
} else if (idblock == 0) {
/*
* There's no indirect block allocated, but we need to
* allocate a block whose number needs to be stored in
* the indirect block. Thus, we need to allocate an
* indirect block.
*/
result = sfs_balloc(sfs, &idblock);
if (result) {
return result;
}
/* Remember the block we just allocated */
sv->sv_i.sfi_indirect = idblock;
/* Remember the block we just allocated */
sv->sv_i.sfi_indirect = idblock;
/* Mark the inode dirty */
sv->sv_dirty = true;
/* Mark the inode dirty */
sv->sv_dirty = true;
/* Clear the indirect block buffer */
bzero(idbuf, sizeof(idbuf));
}
else {
/*
* We already have an indirect block allocated; load it.
*/
result = sfs_readblock(sfs, idblock, idbuf, sizeof(idbuf));
if (result) {
return result;
}
}
/* Clear the indirect block buffer */
bzero(idbuf, sizeof(idbuf));
} else {
/*
* We already have an indirect block allocated; load it.
*/
result = sfs_readblock(sfs, idblock, idbuf, sizeof(idbuf));
if (result) {
return result;
}
}
/* Get the block out of the indirect block buffer */
block = idbuf[idoff];
/* Get the block out of the indirect block buffer */
block = idbuf[idoff];
/* If there's no block there, allocate one */
if (block==0 && doalloc) {
result = sfs_balloc(sfs, &block);
if (result) {
return result;
}
/* If there's no block there, allocate one */
if (block == 0 && doalloc) {
result = sfs_balloc(sfs, &block);
if (result) {
return result;
}
/* Remember the block we allocated */
idbuf[idoff] = block;
/* Remember the block we allocated */
idbuf[idoff] = block;
/* The indirect block is now dirty; write it back */
result = sfs_writeblock(sfs, idblock, idbuf, sizeof(idbuf));
if (result) {
return result;
}
}
/* The indirect block is now dirty; write it back */
result = sfs_writeblock(sfs, idblock, idbuf, sizeof(idbuf));
if (result) {
return result;
}
}
/* Hand back the result and return. */
if (block != 0 && !sfs_bused(sfs, block)) {
panic("sfs: %s: Data block %u (block %u of file %u) "
"marked free\n", sfs->sfs_sb.sb_volname,
block, fileblock, sv->sv_ino);
}
*diskblock = block;
return 0;
/* Hand back the result and return. */
if (block != 0 && !sfs_bused(sfs, block)) {
panic("sfs: %s: Data block %u (block %u of file %u) "
"marked free\n",
sfs->sfs_sb.sb_volname, block, fileblock, sv->sv_ino);
}
*diskblock = block;
return 0;
}
/*
* Called for ftruncate() and from sfs_reclaim.
*/
int
sfs_itrunc(struct sfs_vnode *sv, off_t len)
{
/*
* I/O buffer for handling the indirect block.
*
* Note: in real life (and when you've done the fs assignment)
* you would get space from the disk buffer cache for this,
* not use a static area.
*/
static uint32_t idbuf[SFS_DBPERIDB];
int sfs_itrunc(struct sfs_vnode *sv, off_t len) {
/*
* I/O buffer for handling the indirect block.
*
* Note: in real life (and when you've done the fs assignment)
* you would get space from the disk buffer cache for this,
* not use a static area.
*/
static uint32_t idbuf[SFS_DBPERIDB];
struct sfs_fs *sfs = sv->sv_absvn.vn_fs->fs_data;
struct sfs_fs *sfs = sv->sv_absvn.vn_fs->fs_data;
/* Length in blocks (divide rounding up) */
uint32_t blocklen = DIVROUNDUP(len, SFS_BLOCKSIZE);
/* Length in blocks (divide rounding up) */
uint32_t blocklen = DIVROUNDUP(len, SFS_BLOCKSIZE);
uint32_t i, j;
daddr_t block, idblock;
uint32_t baseblock, highblock;
int result;
int hasnonzero, iddirty;
uint32_t i, j;
daddr_t block, idblock;
uint32_t baseblock, highblock;
int result;
int hasnonzero, iddirty;
KASSERT(sizeof(idbuf)==SFS_BLOCKSIZE);
KASSERT(sizeof(idbuf) == SFS_BLOCKSIZE);
vfs_biglock_acquire();
vfs_biglock_acquire();
/*
* Go through the direct blocks. Discard any that are
* past the limit we're truncating to.
*/
for (i=0; i<SFS_NDIRECT; i++) {
block = sv->sv_i.sfi_direct[i];
if (i >= blocklen && block != 0) {
sfs_bfree(sfs, block);
sv->sv_i.sfi_direct[i] = 0;
sv->sv_dirty = true;
}
}
/*
* Go through the direct blocks. Discard any that are
* past the limit we're truncating to.
*/
for (i = 0; i < SFS_NDIRECT; i++) {
block = sv->sv_i.sfi_direct[i];
if (i >= blocklen && block != 0) {
sfs_bfree(sfs, block);
sv->sv_i.sfi_direct[i] = 0;
sv->sv_dirty = true;
}
}
/* Indirect block number */
idblock = sv->sv_i.sfi_indirect;
/* Indirect block number */
idblock = sv->sv_i.sfi_indirect;
/* The lowest block in the indirect block */
baseblock = SFS_NDIRECT;
/* The lowest block in the indirect block */
baseblock = SFS_NDIRECT;
/* The highest block in the indirect block */
highblock = baseblock + SFS_DBPERIDB - 1;
/* The highest block in the indirect block */
highblock = baseblock + SFS_DBPERIDB - 1;
if (blocklen < highblock && idblock != 0) {
/* We're past the proposed EOF; may need to free stuff */
if (blocklen < highblock && idblock != 0) {
/* We're past the proposed EOF; may need to free stuff */
/* Read the indirect block */
result = sfs_readblock(sfs, idblock, idbuf, sizeof(idbuf));
if (result) {
vfs_biglock_release();
return result;
}
/* Read the indirect block */
result = sfs_readblock(sfs, idblock, idbuf, sizeof(idbuf));
if (result) {
vfs_biglock_release();
return result;
}
hasnonzero = 0;
iddirty = 0;
for (j=0; j<SFS_DBPERIDB; j++) {
/* Discard any blocks that are past the new EOF */
if (blocklen < baseblock+j && idbuf[j] != 0) {
sfs_bfree(sfs, idbuf[j]);
idbuf[j] = 0;
iddirty = 1;
}
/* Remember if we see any nonzero blocks in here */
if (idbuf[j]!=0) {
hasnonzero=1;
}
}
hasnonzero = 0;
iddirty = 0;
for (j = 0; j < SFS_DBPERIDB; j++) {
/* Discard any blocks that are past the new EOF */
if (blocklen < baseblock + j && idbuf[j] != 0) {
sfs_bfree(sfs, idbuf[j]);
idbuf[j] = 0;
iddirty = 1;
}
/* Remember if we see any nonzero blocks in here */
if (idbuf[j] != 0) {
hasnonzero = 1;
}
}
if (!hasnonzero) {
/* The whole indirect block is empty now; free it */
sfs_bfree(sfs, idblock);
sv->sv_i.sfi_indirect = 0;
sv->sv_dirty = true;
}
else if (iddirty) {
/* The indirect block is dirty; write it back */
result = sfs_writeblock(sfs, idblock, idbuf,
sizeof(idbuf));
if (result) {
vfs_biglock_release();
return result;
}
}
}
if (!hasnonzero) {
/* The whole indirect block is empty now; free it */
sfs_bfree(sfs, idblock);
sv->sv_i.sfi_indirect = 0;
sv->sv_dirty = true;
} else if (iddirty) {
/* The indirect block is dirty; write it back */
result = sfs_writeblock(sfs, idblock, idbuf, sizeof(idbuf));
if (result) {
vfs_biglock_release();
return result;
}
}
}
/* Set the file size */
sv->sv_i.sfi_size = len;
/* Set the file size */
sv->sv_i.sfi_size = len;
/* Mark the inode dirty */
sv->sv_dirty = true;
/* Mark the inode dirty */
sv->sv_dirty = true;
vfs_biglock_release();
return 0;
vfs_biglock_release();
return 0;
}

View File

@@ -43,33 +43,29 @@
* Read the directory entry out of slot SLOT of a directory vnode.
* The "slot" is the index of the directory entry, starting at 0.
*/
static
int
sfs_readdir(struct sfs_vnode *sv, int slot, struct sfs_direntry *sd)
{
off_t actualpos;
static int sfs_readdir(struct sfs_vnode *sv, int slot,
struct sfs_direntry *sd) {
off_t actualpos;
/* Compute the actual position in the directory to read. */
actualpos = slot * sizeof(struct sfs_direntry);
/* Compute the actual position in the directory to read. */
actualpos = slot * sizeof(struct sfs_direntry);
return sfs_metaio(sv, actualpos, sd, sizeof(*sd), UIO_READ);
return sfs_metaio(sv, actualpos, sd, sizeof(*sd), UIO_READ);
}
/*
* Write (overwrite) the directory entry in slot SLOT of a directory
* vnode.
*/
static
int
sfs_writedir(struct sfs_vnode *sv, int slot, struct sfs_direntry *sd)
{
off_t actualpos;
static int sfs_writedir(struct sfs_vnode *sv, int slot,
struct sfs_direntry *sd) {
off_t actualpos;
/* Compute the actual position in the directory. */
KASSERT(slot>=0);
actualpos = slot * sizeof(struct sfs_direntry);
/* Compute the actual position in the directory. */
KASSERT(slot >= 0);
actualpos = slot * sizeof(struct sfs_direntry);
return sfs_metaio(sv, actualpos, sd, sizeof(*sd), UIO_WRITE);
return sfs_metaio(sv, actualpos, sd, sizeof(*sd), UIO_WRITE);
}
/*
@@ -77,22 +73,19 @@ sfs_writedir(struct sfs_vnode *sv, int slot, struct sfs_direntry *sd)
* This actually computes the number of existing slots, and does not
* account for empty slots.
*/
static
int
sfs_dir_nentries(struct sfs_vnode *sv)
{
struct sfs_fs *sfs = sv->sv_absvn.vn_fs->fs_data;
off_t size;
static int sfs_dir_nentries(struct sfs_vnode *sv) {
struct sfs_fs *sfs = sv->sv_absvn.vn_fs->fs_data;
off_t size;
KASSERT(sv->sv_i.sfi_type == SFS_TYPE_DIR);
KASSERT(sv->sv_i.sfi_type == SFS_TYPE_DIR);
size = sv->sv_i.sfi_size;
if (size % sizeof(struct sfs_direntry) != 0) {
panic("sfs: %s: directory %u: Invalid size %llu\n",
sfs->sfs_sb.sb_volname, sv->sv_ino, size);
}
size = sv->sv_i.sfi_size;
if (size % sizeof(struct sfs_direntry) != 0) {
panic("sfs: %s: directory %u: Invalid size %llu\n", sfs->sfs_sb.sb_volname,
sv->sv_ino, size);
}
return size / sizeof(struct sfs_direntry);
return size / sizeof(struct sfs_direntry);
}
/*
@@ -100,140 +93,130 @@ sfs_dir_nentries(struct sfs_vnode *sv)
* return its inode number, its slot, and/or the slot number of an
* empty directory slot if one is found.
*/
int
sfs_dir_findname(struct sfs_vnode *sv, const char *name,
uint32_t *ino, int *slot, int *emptyslot)
{
struct sfs_direntry tsd;
int found, nentries, i, result;
int sfs_dir_findname(struct sfs_vnode *sv, const char *name, uint32_t *ino,
int *slot, int *emptyslot) {
struct sfs_direntry tsd;
int found, nentries, i, result;
nentries = sfs_dir_nentries(sv);
nentries = sfs_dir_nentries(sv);
/* For each slot... */
found = 0;
for (i=0; i<nentries; i++) {
/* For each slot... */
found = 0;
for (i = 0; i < nentries; i++) {
/* Read the entry from that slot */
result = sfs_readdir(sv, i, &tsd);
if (result) {
return result;
}
if (tsd.sfd_ino == SFS_NOINO) {
/* Free slot - report it back if one was requested */
if (emptyslot != NULL) {
*emptyslot = i;
}
}
else {
/* Ensure null termination, just in case */
tsd.sfd_name[sizeof(tsd.sfd_name)-1] = 0;
if (!strcmp(tsd.sfd_name, name)) {
/* Read the entry from that slot */
result = sfs_readdir(sv, i, &tsd);
if (result) {
return result;
}
if (tsd.sfd_ino == SFS_NOINO) {
/* Free slot - report it back if one was requested */
if (emptyslot != NULL) {
*emptyslot = i;
}
} else {
/* Ensure null termination, just in case */
tsd.sfd_name[sizeof(tsd.sfd_name) - 1] = 0;
if (!strcmp(tsd.sfd_name, name)) {
/* Each name may legally appear only once... */
KASSERT(found==0);
/* Each name may legally appear only once... */
KASSERT(found == 0);
found = 1;
if (slot != NULL) {
*slot = i;
}
if (ino != NULL) {
*ino = tsd.sfd_ino;
}
}
}
}
found = 1;
if (slot != NULL) {
*slot = i;
}
if (ino != NULL) {
*ino = tsd.sfd_ino;
}
}
}
}
return found ? 0 : ENOENT;
return found ? 0 : ENOENT;
}
/*
* Create a link in a directory to the specified inode by number, with
* the specified name, and optionally hand back the slot.
*/
int
sfs_dir_link(struct sfs_vnode *sv, const char *name, uint32_t ino, int *slot)
{
int emptyslot = -1;
int result;
struct sfs_direntry sd;
int sfs_dir_link(struct sfs_vnode *sv, const char *name, uint32_t ino,
int *slot) {
int emptyslot = -1;
int result;
struct sfs_direntry sd;
/* Look up the name. We want to make sure it *doesn't* exist. */
result = sfs_dir_findname(sv, name, NULL, NULL, &emptyslot);
if (result!=0 && result!=ENOENT) {
return result;
}
if (result==0) {
return EEXIST;
}
/* Look up the name. We want to make sure it *doesn't* exist. */
result = sfs_dir_findname(sv, name, NULL, NULL, &emptyslot);
if (result != 0 && result != ENOENT) {
return result;
}
if (result == 0) {
return EEXIST;
}
if (strlen(name)+1 > sizeof(sd.sfd_name)) {
return ENAMETOOLONG;
}
if (strlen(name) + 1 > sizeof(sd.sfd_name)) {
return ENAMETOOLONG;
}
/* If we didn't get an empty slot, add the entry at the end. */
if (emptyslot < 0) {
emptyslot = sfs_dir_nentries(sv);
}
/* If we didn't get an empty slot, add the entry at the end. */
if (emptyslot < 0) {
emptyslot = sfs_dir_nentries(sv);
}
/* Set up the entry. */
bzero(&sd, sizeof(sd));
sd.sfd_ino = ino;
strcpy(sd.sfd_name, name);
/* Set up the entry. */
bzero(&sd, sizeof(sd));
sd.sfd_ino = ino;
strcpy(sd.sfd_name, name);
/* Hand back the slot, if so requested. */
if (slot) {
*slot = emptyslot;
}
/* Hand back the slot, if so requested. */
if (slot) {
*slot = emptyslot;
}
/* Write the entry. */
return sfs_writedir(sv, emptyslot, &sd);
/* Write the entry. */
return sfs_writedir(sv, emptyslot, &sd);
}
/*
* Unlink a name in a directory, by slot number.
*/
int
sfs_dir_unlink(struct sfs_vnode *sv, int slot)
{
struct sfs_direntry sd;
int sfs_dir_unlink(struct sfs_vnode *sv, int slot) {
struct sfs_direntry sd;
/* Initialize a suitable directory entry... */
bzero(&sd, sizeof(sd));
sd.sfd_ino = SFS_NOINO;
/* Initialize a suitable directory entry... */
bzero(&sd, sizeof(sd));
sd.sfd_ino = SFS_NOINO;
/* ... and write it */
return sfs_writedir(sv, slot, &sd);
/* ... and write it */
return sfs_writedir(sv, slot, &sd);
}
/*
* Look for a name in a directory and hand back a vnode for the
* file, if there is one.
*/
int
sfs_lookonce(struct sfs_vnode *sv, const char *name,
struct sfs_vnode **ret,
int *slot)
{
struct sfs_fs *sfs = sv->sv_absvn.vn_fs->fs_data;
uint32_t ino;
int result;
int sfs_lookonce(struct sfs_vnode *sv, const char *name, struct sfs_vnode **ret,
int *slot) {
struct sfs_fs *sfs = sv->sv_absvn.vn_fs->fs_data;
uint32_t ino;
int result;
result = sfs_dir_findname(sv, name, &ino, slot, NULL);
if (result) {
return result;
}
result = sfs_dir_findname(sv, name, &ino, slot, NULL);
if (result) {
return result;
}
result = sfs_loadvnode(sfs, ino, SFS_TYPE_INVAL, ret);
if (result) {
return result;
}
result = sfs_loadvnode(sfs, ino, SFS_TYPE_INVAL, ret);
if (result) {
return result;
}
if ((*ret)->sv_i.sfi_linkcount == 0) {
panic("sfs: %s: name %s (inode %u) in dir %u has "
"linkcount 0\n", sfs->sfs_sb.sb_volname,
name, (*ret)->sv_ino, sv->sv_ino);
}
if ((*ret)->sv_i.sfi_linkcount == 0) {
panic("sfs: %s: name %s (inode %u) in dir %u has "
"linkcount 0\n",
sfs->sfs_sb.sb_volname, name, (*ret)->sv_ino, sv->sv_ino);
}
return 0;
return 0;
}

View File

@@ -44,11 +44,10 @@
#include <sfs.h>
#include "sfsprivate.h"
/* Shortcuts for the size macros in kern/sfs.h */
#define SFS_FS_NBLOCKS(sfs) ((sfs)->sfs_sb.sb_nblocks)
#define SFS_FS_FREEMAPBITS(sfs) SFS_FREEMAPBITS(SFS_FS_NBLOCKS(sfs))
#define SFS_FS_FREEMAPBLOCKS(sfs) SFS_FREEMAPBLOCKS(SFS_FS_NBLOCKS(sfs))
#define SFS_FS_NBLOCKS(sfs) ((sfs)->sfs_sb.sb_nblocks)
#define SFS_FS_FREEMAPBITS(sfs) SFS_FREEMAPBITS(SFS_FS_NBLOCKS(sfs))
#define SFS_FS_FREEMAPBLOCKS(sfs) SFS_FREEMAPBLOCKS(SFS_FS_NBLOCKS(sfs))
/*
* Routine for doing I/O (reads or writes) on the free block bitmap.
@@ -67,170 +66,152 @@
* The sectors used by the superblock and the bitmap itself are
* likewise marked in use by mksfs.
*/
static
int
sfs_freemapio(struct sfs_fs *sfs, enum uio_rw rw)
{
uint32_t j, freemapblocks;
char *freemapdata;
int result;
static int sfs_freemapio(struct sfs_fs *sfs, enum uio_rw rw) {
uint32_t j, freemapblocks;
char *freemapdata;
int result;
/* Number of blocks in the free block bitmap. */
freemapblocks = SFS_FS_FREEMAPBLOCKS(sfs);
/* Number of blocks in the free block bitmap. */
freemapblocks = SFS_FS_FREEMAPBLOCKS(sfs);
/* Pointer to our freemap data in memory. */
freemapdata = bitmap_getdata(sfs->sfs_freemap);
/* Pointer to our freemap data in memory. */
freemapdata = bitmap_getdata(sfs->sfs_freemap);
/* For each block in the free block bitmap... */
for (j=0; j<freemapblocks; j++) {
/* For each block in the free block bitmap... */
for (j = 0; j < freemapblocks; j++) {
/* Get a pointer to its data */
void *ptr = freemapdata + j*SFS_BLOCKSIZE;
/* Get a pointer to its data */
void *ptr = freemapdata + j * SFS_BLOCKSIZE;
/* and read or write it. The freemap starts at sector 2. */
if (rw == UIO_READ) {
result = sfs_readblock(sfs, SFS_FREEMAP_START+j, ptr,
SFS_BLOCKSIZE);
}
else {
result = sfs_writeblock(sfs, SFS_FREEMAP_START+j, ptr,
SFS_BLOCKSIZE);
}
/* and read or write it. The freemap starts at sector 2. */
if (rw == UIO_READ) {
result = sfs_readblock(sfs, SFS_FREEMAP_START + j, ptr, SFS_BLOCKSIZE);
} else {
result = sfs_writeblock(sfs, SFS_FREEMAP_START + j, ptr, SFS_BLOCKSIZE);
}
/* If we failed, stop. */
if (result) {
return result;
}
}
return 0;
/* If we failed, stop. */
if (result) {
return result;
}
}
return 0;
}
/*
* Sync routine for the vnode table.
*/
static
int
sfs_sync_vnodes(struct sfs_fs *sfs)
{
unsigned i, num;
static int sfs_sync_vnodes(struct sfs_fs *sfs) {
unsigned i, num;
/* Go over the array of loaded vnodes, syncing as we go. */
num = vnodearray_num(sfs->sfs_vnodes);
for (i=0; i<num; i++) {
struct vnode *v = vnodearray_get(sfs->sfs_vnodes, i);
VOP_FSYNC(v);
}
return 0;
/* Go over the array of loaded vnodes, syncing as we go. */
num = vnodearray_num(sfs->sfs_vnodes);
for (i = 0; i < num; i++) {
struct vnode *v = vnodearray_get(sfs->sfs_vnodes, i);
VOP_FSYNC(v);
}
return 0;
}
/*
* Sync routine for the freemap.
*/
static
int
sfs_sync_freemap(struct sfs_fs *sfs)
{
int result;
static int sfs_sync_freemap(struct sfs_fs *sfs) {
int result;
if (sfs->sfs_freemapdirty) {
result = sfs_freemapio(sfs, UIO_WRITE);
if (result) {
return result;
}
sfs->sfs_freemapdirty = false;
}
if (sfs->sfs_freemapdirty) {
result = sfs_freemapio(sfs, UIO_WRITE);
if (result) {
return result;
}
sfs->sfs_freemapdirty = false;
}
return 0;
return 0;
}
/*
* Sync routine for the superblock.
*/
static
int
sfs_sync_superblock(struct sfs_fs *sfs)
{
int result;
static int sfs_sync_superblock(struct sfs_fs *sfs) {
int result;
if (sfs->sfs_superdirty) {
result = sfs_writeblock(sfs, SFS_SUPER_BLOCK, &sfs->sfs_sb,
sizeof(sfs->sfs_sb));
if (result) {
return result;
}
sfs->sfs_superdirty = false;
}
return 0;
if (sfs->sfs_superdirty) {
result =
sfs_writeblock(sfs, SFS_SUPER_BLOCK, &sfs->sfs_sb, sizeof(sfs->sfs_sb));
if (result) {
return result;
}
sfs->sfs_superdirty = false;
}
return 0;
}
/*
* Sync routine. This is what gets invoked if you do FS_SYNC on the
* sfs filesystem structure.
*/
static
int
sfs_sync(struct fs *fs)
{
struct sfs_fs *sfs;
int result;
static int sfs_sync(struct fs *fs) {
struct sfs_fs *sfs;
int result;
vfs_biglock_acquire();
vfs_biglock_acquire();
/*
* Get the sfs_fs from the generic abstract fs.
*
* Note that the abstract struct fs, which is all the VFS
* layer knows about, is actually a member of struct sfs_fs.
* The pointer in the struct fs points back to the top of the
* struct sfs_fs - essentially the same object. This can be a
* little confusing at first.
*
* The following diagram may help:
*
* struct sfs_fs <-------------\
* : |
* : sfs_absfs (struct fs) | <------\
* : : | |
* : : various members | |
* : : | |
* : : fs_data ----------/ |
* : : ...|...
* : . VFS .
* : . layer .
* : other members .......
* :
* :
*
* This construct is repeated with vnodes and devices and other
* similar things all over the place in OS/161, so taking the
* time to straighten it out in your mind is worthwhile.
*/
/*
* Get the sfs_fs from the generic abstract fs.
*
* Note that the abstract struct fs, which is all the VFS
* layer knows about, is actually a member of struct sfs_fs.
* The pointer in the struct fs points back to the top of the
* struct sfs_fs - essentially the same object. This can be a
* little confusing at first.
*
* The following diagram may help:
*
* struct sfs_fs <-------------\
* : |
* : sfs_absfs (struct fs) | <------\
* : : | |
* : : various members | |
* : : | |
* : : fs_data ----------/ |
* : : ...|...
* : . VFS .
* : . layer .
* : other members .......
* :
* :
*
* This construct is repeated with vnodes and devices and other
* similar things all over the place in OS/161, so taking the
* time to straighten it out in your mind is worthwhile.
*/
sfs = fs->fs_data;
sfs = fs->fs_data;
/* If any vnodes need to be written, write them. */
result = sfs_sync_vnodes(sfs);
if (result) {
vfs_biglock_release();
return result;
}
/* If any vnodes need to be written, write them. */
result = sfs_sync_vnodes(sfs);
if (result) {
vfs_biglock_release();
return result;
}
/* If the free block map needs to be written, write it. */
result = sfs_sync_freemap(sfs);
if (result) {
vfs_biglock_release();
return result;
}
/* If the free block map needs to be written, write it. */
result = sfs_sync_freemap(sfs);
if (result) {
vfs_biglock_release();
return result;
}
/* If the superblock needs to be written, write it. */
result = sfs_sync_superblock(sfs);
if (result) {
vfs_biglock_release();
return result;
}
/* If the superblock needs to be written, write it. */
result = sfs_sync_superblock(sfs);
if (result) {
vfs_biglock_release();
return result;
}
vfs_biglock_release();
return 0;
vfs_biglock_release();
return 0;
}
/*
@@ -238,33 +219,27 @@ sfs_sync(struct fs *fs)
* to by their volume name followed by a colon as well as the name
* of the device they're mounted on.
*/
static
const char *
sfs_getvolname(struct fs *fs)
{
struct sfs_fs *sfs = fs->fs_data;
const char *ret;
static const char *sfs_getvolname(struct fs *fs) {
struct sfs_fs *sfs = fs->fs_data;
const char *ret;
vfs_biglock_acquire();
ret = sfs->sfs_sb.sb_volname;
vfs_biglock_release();
vfs_biglock_acquire();
ret = sfs->sfs_sb.sb_volname;
vfs_biglock_release();
return ret;
return ret;
}
/*
* Destructor for struct sfs_fs.
*/
static
void
sfs_fs_destroy(struct sfs_fs *sfs)
{
if (sfs->sfs_freemap != NULL) {
bitmap_destroy(sfs->sfs_freemap);
}
vnodearray_destroy(sfs->sfs_vnodes);
KASSERT(sfs->sfs_device == NULL);
kfree(sfs);
static void sfs_fs_destroy(struct sfs_fs *sfs) {
if (sfs->sfs_freemap != NULL) {
bitmap_destroy(sfs->sfs_freemap);
}
vnodearray_destroy(sfs->sfs_vnodes);
KASSERT(sfs->sfs_device == NULL);
kfree(sfs);
}
/*
@@ -272,43 +247,40 @@ sfs_fs_destroy(struct sfs_fs *sfs)
*
* VFS calls FS_SYNC on the filesystem prior to unmounting it.
*/
static
int
sfs_unmount(struct fs *fs)
{
struct sfs_fs *sfs = fs->fs_data;
static int sfs_unmount(struct fs *fs) {
struct sfs_fs *sfs = fs->fs_data;
vfs_biglock_acquire();
vfs_biglock_acquire();
/* Do we have any files open? If so, can't unmount. */
if (vnodearray_num(sfs->sfs_vnodes) > 0) {
vfs_biglock_release();
return EBUSY;
}
/* Do we have any files open? If so, can't unmount. */
if (vnodearray_num(sfs->sfs_vnodes) > 0) {
vfs_biglock_release();
return EBUSY;
}
/* We should have just had sfs_sync called. */
KASSERT(sfs->sfs_superdirty == false);
KASSERT(sfs->sfs_freemapdirty == false);
/* We should have just had sfs_sync called. */
KASSERT(sfs->sfs_superdirty == false);
KASSERT(sfs->sfs_freemapdirty == false);
/* The vfs layer takes care of the device for us */
sfs->sfs_device = NULL;
/* The vfs layer takes care of the device for us */
sfs->sfs_device = NULL;
/* Destroy the fs object; once we start nuking stuff we can't fail. */
sfs_fs_destroy(sfs);
/* Destroy the fs object; once we start nuking stuff we can't fail. */
sfs_fs_destroy(sfs);
/* nothing else to do */
vfs_biglock_release();
return 0;
/* nothing else to do */
vfs_biglock_release();
return 0;
}
/*
* File system operations table.
*/
static const struct fs_ops sfs_fsops = {
.fsop_sync = sfs_sync,
.fsop_getvolname = sfs_getvolname,
.fsop_getroot = sfs_getroot,
.fsop_unmount = sfs_unmount,
.fsop_sync = sfs_sync,
.fsop_getvolname = sfs_getvolname,
.fsop_getroot = sfs_getroot,
.fsop_unmount = sfs_unmount,
};
/*
@@ -316,56 +288,53 @@ static const struct fs_ops sfs_fsops = {
* but skips stuff that requires reading the volume, like allocating
* the freemap.
*/
static
struct sfs_fs *
sfs_fs_create(void)
{
struct sfs_fs *sfs;
static struct sfs_fs *sfs_fs_create(void) {
struct sfs_fs *sfs;
/*
* Make sure our on-disk structures aren't messed up
*/
COMPILE_ASSERT(sizeof(struct sfs_superblock)==SFS_BLOCKSIZE);
COMPILE_ASSERT(sizeof(struct sfs_dinode)==SFS_BLOCKSIZE);
COMPILE_ASSERT(SFS_BLOCKSIZE % sizeof(struct sfs_direntry) == 0);
/*
* Make sure our on-disk structures aren't messed up
*/
COMPILE_ASSERT(sizeof(struct sfs_superblock) == SFS_BLOCKSIZE);
COMPILE_ASSERT(sizeof(struct sfs_dinode) == SFS_BLOCKSIZE);
COMPILE_ASSERT(SFS_BLOCKSIZE % sizeof(struct sfs_direntry) == 0);
/* Allocate object */
sfs = kmalloc(sizeof(struct sfs_fs));
if (sfs==NULL) {
goto fail;
}
/* Allocate object */
sfs = kmalloc(sizeof(struct sfs_fs));
if (sfs == NULL) {
goto fail;
}
/*
* Fill in fields
*/
/*
* Fill in fields
*/
/* abstract vfs-level fs */
sfs->sfs_absfs.fs_data = sfs;
sfs->sfs_absfs.fs_ops = &sfs_fsops;
/* abstract vfs-level fs */
sfs->sfs_absfs.fs_data = sfs;
sfs->sfs_absfs.fs_ops = &sfs_fsops;
/* superblock */
/* (ignore sfs_super, we'll read in over it shortly) */
sfs->sfs_superdirty = false;
/* superblock */
/* (ignore sfs_super, we'll read in over it shortly) */
sfs->sfs_superdirty = false;
/* device we mount on */
sfs->sfs_device = NULL;
/* device we mount on */
sfs->sfs_device = NULL;
/* vnode table */
sfs->sfs_vnodes = vnodearray_create();
if (sfs->sfs_vnodes == NULL) {
goto cleanup_object;
}
/* vnode table */
sfs->sfs_vnodes = vnodearray_create();
if (sfs->sfs_vnodes == NULL) {
goto cleanup_object;
}
/* freemap */
sfs->sfs_freemap = NULL;
sfs->sfs_freemapdirty = false;
/* freemap */
sfs->sfs_freemap = NULL;
sfs->sfs_freemapdirty = false;
return sfs;
return sfs;
cleanup_object:
kfree(sfs);
kfree(sfs);
fail:
return NULL;
return NULL;
}
/*
@@ -381,101 +350,95 @@ fail:
* filesystems with the same name mounted at once, or two filesystems
* mounted on the same device at once.
*/
static
int
sfs_domount(void *options, struct device *dev, struct fs **ret)
{
int result;
struct sfs_fs *sfs;
static int sfs_domount(void *options, struct device *dev, struct fs **ret) {
int result;
struct sfs_fs *sfs;
vfs_biglock_acquire();
vfs_biglock_acquire();
/* We don't pass any options through mount */
(void)options;
/* We don't pass any options through mount */
(void)options;
/*
* We can't mount on devices with the wrong sector size.
*
* (Note: for all intents and purposes here, "sector" and
* "block" are interchangeable terms. Technically a filesystem
* block may be composed of several hardware sectors, but we
* don't do that in sfs.)
*/
if (dev->d_blocksize != SFS_BLOCKSIZE) {
vfs_biglock_release();
kprintf("sfs: Cannot mount on device with blocksize %zu\n",
dev->d_blocksize);
return ENXIO;
}
/*
* We can't mount on devices with the wrong sector size.
*
* (Note: for all intents and purposes here, "sector" and
* "block" are interchangeable terms. Technically a filesystem
* block may be composed of several hardware sectors, but we
* don't do that in sfs.)
*/
if (dev->d_blocksize != SFS_BLOCKSIZE) {
vfs_biglock_release();
kprintf("sfs: Cannot mount on device with blocksize %zu\n",
dev->d_blocksize);
return ENXIO;
}
sfs = sfs_fs_create();
if (sfs == NULL) {
vfs_biglock_release();
return ENOMEM;
}
sfs = sfs_fs_create();
if (sfs == NULL) {
vfs_biglock_release();
return ENOMEM;
}
/* Set the device so we can use sfs_readblock() */
sfs->sfs_device = dev;
/* Set the device so we can use sfs_readblock() */
sfs->sfs_device = dev;
/* Load superblock */
result = sfs_readblock(sfs, SFS_SUPER_BLOCK, &sfs->sfs_sb,
sizeof(sfs->sfs_sb));
if (result) {
sfs->sfs_device = NULL;
sfs_fs_destroy(sfs);
vfs_biglock_release();
return result;
}
/* Load superblock */
result =
sfs_readblock(sfs, SFS_SUPER_BLOCK, &sfs->sfs_sb, sizeof(sfs->sfs_sb));
if (result) {
sfs->sfs_device = NULL;
sfs_fs_destroy(sfs);
vfs_biglock_release();
return result;
}
/* Make some simple sanity checks */
/* Make some simple sanity checks */
if (sfs->sfs_sb.sb_magic != SFS_MAGIC) {
kprintf("sfs: Wrong magic number in superblock "
"(0x%x, should be 0x%x)\n",
sfs->sfs_sb.sb_magic,
SFS_MAGIC);
sfs->sfs_device = NULL;
sfs_fs_destroy(sfs);
vfs_biglock_release();
return EINVAL;
}
if (sfs->sfs_sb.sb_magic != SFS_MAGIC) {
kprintf("sfs: Wrong magic number in superblock "
"(0x%x, should be 0x%x)\n",
sfs->sfs_sb.sb_magic, SFS_MAGIC);
sfs->sfs_device = NULL;
sfs_fs_destroy(sfs);
vfs_biglock_release();
return EINVAL;
}
if (sfs->sfs_sb.sb_nblocks > dev->d_blocks) {
kprintf("sfs: warning - fs has %u blocks, device has %u\n",
sfs->sfs_sb.sb_nblocks, dev->d_blocks);
}
if (sfs->sfs_sb.sb_nblocks > dev->d_blocks) {
kprintf("sfs: warning - fs has %u blocks, device has %u\n",
sfs->sfs_sb.sb_nblocks, dev->d_blocks);
}
/* Ensure null termination of the volume name */
sfs->sfs_sb.sb_volname[sizeof(sfs->sfs_sb.sb_volname)-1] = 0;
/* Ensure null termination of the volume name */
sfs->sfs_sb.sb_volname[sizeof(sfs->sfs_sb.sb_volname) - 1] = 0;
/* Load free block bitmap */
sfs->sfs_freemap = bitmap_create(SFS_FS_FREEMAPBITS(sfs));
if (sfs->sfs_freemap == NULL) {
sfs->sfs_device = NULL;
sfs_fs_destroy(sfs);
vfs_biglock_release();
return ENOMEM;
}
result = sfs_freemapio(sfs, UIO_READ);
if (result) {
sfs->sfs_device = NULL;
sfs_fs_destroy(sfs);
vfs_biglock_release();
return result;
}
/* Load free block bitmap */
sfs->sfs_freemap = bitmap_create(SFS_FS_FREEMAPBITS(sfs));
if (sfs->sfs_freemap == NULL) {
sfs->sfs_device = NULL;
sfs_fs_destroy(sfs);
vfs_biglock_release();
return ENOMEM;
}
result = sfs_freemapio(sfs, UIO_READ);
if (result) {
sfs->sfs_device = NULL;
sfs_fs_destroy(sfs);
vfs_biglock_release();
return result;
}
/* Hand back the abstract fs */
*ret = &sfs->sfs_absfs;
/* Hand back the abstract fs */
*ret = &sfs->sfs_absfs;
vfs_biglock_release();
return 0;
vfs_biglock_release();
return 0;
}
/*
* Actual function called from high-level code to mount an sfs.
*/
int
sfs_mount(const char *device)
{
return vfs_mount(device, NULL, sfs_domount);
int sfs_mount(const char *device) {
return vfs_mount(device, NULL, sfs_domount);
}

View File

@@ -39,25 +39,21 @@
#include <sfs.h>
#include "sfsprivate.h"
/*
* Write an on-disk inode structure back out to disk.
*/
int
sfs_sync_inode(struct sfs_vnode *sv)
{
struct sfs_fs *sfs = sv->sv_absvn.vn_fs->fs_data;
int result;
int sfs_sync_inode(struct sfs_vnode *sv) {
struct sfs_fs *sfs = sv->sv_absvn.vn_fs->fs_data;
int result;
if (sv->sv_dirty) {
result = sfs_writeblock(sfs, sv->sv_ino, &sv->sv_i,
sizeof(sv->sv_i));
if (result) {
return result;
}
sv->sv_dirty = false;
}
return 0;
if (sv->sv_dirty) {
result = sfs_writeblock(sfs, sv->sv_ino, &sv->sv_i, sizeof(sv->sv_i));
if (result) {
return result;
}
sv->sv_dirty = false;
}
return 0;
}
/*
@@ -65,256 +61,249 @@ sfs_sync_inode(struct sfs_vnode *sv)
*
* This function should try to avoid returning errors other than EBUSY.
*/
int
sfs_reclaim(struct vnode *v)
{
struct sfs_vnode *sv = v->vn_data;
struct sfs_fs *sfs = v->vn_fs->fs_data;
unsigned ix, i, num;
int result;
int sfs_reclaim(struct vnode *v) {
struct sfs_vnode *sv = v->vn_data;
struct sfs_fs *sfs = v->vn_fs->fs_data;
unsigned ix, i, num;
int result;
vfs_biglock_acquire();
vfs_biglock_acquire();
/*
* Make sure someone else hasn't picked up the vnode since the
* decision was made to reclaim it. (You must also synchronize
* this with sfs_loadvnode.)
*/
spinlock_acquire(&v->vn_countlock);
if (v->vn_refcount != 1) {
/*
* Make sure someone else hasn't picked up the vnode since the
* decision was made to reclaim it. (You must also synchronize
* this with sfs_loadvnode.)
*/
spinlock_acquire(&v->vn_countlock);
if (v->vn_refcount != 1) {
/* consume the reference VOP_DECREF gave us */
KASSERT(v->vn_refcount>1);
v->vn_refcount--;
/* consume the reference VOP_DECREF gave us */
KASSERT(v->vn_refcount > 1);
v->vn_refcount--;
spinlock_release(&v->vn_countlock);
vfs_biglock_release();
return EBUSY;
}
spinlock_release(&v->vn_countlock);
spinlock_release(&v->vn_countlock);
vfs_biglock_release();
return EBUSY;
}
spinlock_release(&v->vn_countlock);
/* If there are no on-disk references to the file either, erase it. */
if (sv->sv_i.sfi_linkcount == 0) {
result = sfs_itrunc(sv, 0);
if (result) {
vfs_biglock_release();
return result;
}
}
/* If there are no on-disk references to the file either, erase it. */
if (sv->sv_i.sfi_linkcount == 0) {
result = sfs_itrunc(sv, 0);
if (result) {
vfs_biglock_release();
return result;
}
}
/* Sync the inode to disk */
result = sfs_sync_inode(sv);
if (result) {
vfs_biglock_release();
return result;
}
/* Sync the inode to disk */
result = sfs_sync_inode(sv);
if (result) {
vfs_biglock_release();
return result;
}
/* If there are no on-disk references, discard the inode */
if (sv->sv_i.sfi_linkcount==0) {
sfs_bfree(sfs, sv->sv_ino);
}
/* If there are no on-disk references, discard the inode */
if (sv->sv_i.sfi_linkcount == 0) {
sfs_bfree(sfs, sv->sv_ino);
}
/* Remove the vnode structure from the table in the struct sfs_fs. */
num = vnodearray_num(sfs->sfs_vnodes);
ix = num;
for (i=0; i<num; i++) {
struct vnode *v2 = vnodearray_get(sfs->sfs_vnodes, i);
struct sfs_vnode *sv2 = v2->vn_data;
if (sv2 == sv) {
ix = i;
break;
}
}
if (ix == num) {
panic("sfs: %s: reclaim vnode %u not in vnode pool\n",
sfs->sfs_sb.sb_volname, sv->sv_ino);
}
vnodearray_remove(sfs->sfs_vnodes, ix);
/* Remove the vnode structure from the table in the struct sfs_fs. */
num = vnodearray_num(sfs->sfs_vnodes);
ix = num;
for (i = 0; i < num; i++) {
struct vnode *v2 = vnodearray_get(sfs->sfs_vnodes, i);
struct sfs_vnode *sv2 = v2->vn_data;
if (sv2 == sv) {
ix = i;
break;
}
}
if (ix == num) {
panic("sfs: %s: reclaim vnode %u not in vnode pool\n",
sfs->sfs_sb.sb_volname, sv->sv_ino);
}
vnodearray_remove(sfs->sfs_vnodes, ix);
vnode_cleanup(&sv->sv_absvn);
vnode_cleanup(&sv->sv_absvn);
vfs_biglock_release();
vfs_biglock_release();
/* Release the storage for the vnode structure itself. */
kfree(sv);
/* Release the storage for the vnode structure itself. */
kfree(sv);
/* Done */
return 0;
/* Done */
return 0;
}
/*
* Function to load a inode into memory as a vnode, or dig up one
* that's already resident.
*/
int
sfs_loadvnode(struct sfs_fs *sfs, uint32_t ino, int forcetype,
struct sfs_vnode **ret)
{
struct vnode *v;
struct sfs_vnode *sv;
const struct vnode_ops *ops;
unsigned i, num;
int result;
int sfs_loadvnode(struct sfs_fs *sfs, uint32_t ino, int forcetype,
struct sfs_vnode **ret) {
struct vnode *v;
struct sfs_vnode *sv;
const struct vnode_ops *ops;
unsigned i, num;
int result;
/* Look in the vnodes table */
num = vnodearray_num(sfs->sfs_vnodes);
/* Look in the vnodes table */
num = vnodearray_num(sfs->sfs_vnodes);
/* Linear search. Is this too slow? You decide. */
for (i=0; i<num; i++) {
v = vnodearray_get(sfs->sfs_vnodes, i);
sv = v->vn_data;
/* Linear search. Is this too slow? You decide. */
for (i = 0; i < num; i++) {
v = vnodearray_get(sfs->sfs_vnodes, i);
sv = v->vn_data;
/* Every inode in memory must be in an allocated block */
if (!sfs_bused(sfs, sv->sv_ino)) {
panic("sfs: %s: Found inode %u in unallocated block\n",
sfs->sfs_sb.sb_volname, sv->sv_ino);
}
/* Every inode in memory must be in an allocated block */
if (!sfs_bused(sfs, sv->sv_ino)) {
panic("sfs: %s: Found inode %u in unallocated block\n",
sfs->sfs_sb.sb_volname, sv->sv_ino);
}
if (sv->sv_ino==ino) {
/* Found */
if (sv->sv_ino == ino) {
/* Found */
/* forcetype is only allowed when creating objects */
KASSERT(forcetype==SFS_TYPE_INVAL);
/* forcetype is only allowed when creating objects */
KASSERT(forcetype == SFS_TYPE_INVAL);
VOP_INCREF(&sv->sv_absvn);
*ret = sv;
return 0;
}
}
VOP_INCREF(&sv->sv_absvn);
*ret = sv;
return 0;
}
}
/* Didn't have it loaded; load it */
/* Didn't have it loaded; load it */
sv = kmalloc(sizeof(struct sfs_vnode));
if (sv==NULL) {
return ENOMEM;
}
sv = kmalloc(sizeof(struct sfs_vnode));
if (sv == NULL) {
return ENOMEM;
}
/* Must be in an allocated block */
if (!sfs_bused(sfs, ino)) {
panic("sfs: %s: Tried to load inode %u from "
"unallocated block\n", sfs->sfs_sb.sb_volname, ino);
}
/* Must be in an allocated block */
if (!sfs_bused(sfs, ino)) {
panic("sfs: %s: Tried to load inode %u from "
"unallocated block\n",
sfs->sfs_sb.sb_volname, ino);
}
/* Read the block the inode is in */
result = sfs_readblock(sfs, ino, &sv->sv_i, sizeof(sv->sv_i));
if (result) {
kfree(sv);
return result;
}
/* Read the block the inode is in */
result = sfs_readblock(sfs, ino, &sv->sv_i, sizeof(sv->sv_i));
if (result) {
kfree(sv);
return result;
}
/* Not dirty yet */
sv->sv_dirty = false;
/* Not dirty yet */
sv->sv_dirty = false;
/*
* FORCETYPE is set if we're creating a new file, because the
* block on disk will have been zeroed out by sfs_balloc and
* thus the type recorded there will be SFS_TYPE_INVAL.
*/
if (forcetype != SFS_TYPE_INVAL) {
KASSERT(sv->sv_i.sfi_type == SFS_TYPE_INVAL);
sv->sv_i.sfi_type = forcetype;
sv->sv_dirty = true;
}
/*
* FORCETYPE is set if we're creating a new file, because the
* block on disk will have been zeroed out by sfs_balloc and
* thus the type recorded there will be SFS_TYPE_INVAL.
*/
if (forcetype != SFS_TYPE_INVAL) {
KASSERT(sv->sv_i.sfi_type == SFS_TYPE_INVAL);
sv->sv_i.sfi_type = forcetype;
sv->sv_dirty = true;
}
/*
* Choose the function table based on the object type.
*/
switch (sv->sv_i.sfi_type) {
case SFS_TYPE_FILE:
ops = &sfs_fileops;
break;
case SFS_TYPE_DIR:
ops = &sfs_dirops;
break;
default:
panic("sfs: %s: loadvnode: Invalid inode type "
"(inode %u, type %u)\n", sfs->sfs_sb.sb_volname,
ino, sv->sv_i.sfi_type);
}
/*
* Choose the function table based on the object type.
*/
switch (sv->sv_i.sfi_type) {
case SFS_TYPE_FILE:
ops = &sfs_fileops;
break;
case SFS_TYPE_DIR:
ops = &sfs_dirops;
break;
default:
panic("sfs: %s: loadvnode: Invalid inode type "
"(inode %u, type %u)\n",
sfs->sfs_sb.sb_volname, ino, sv->sv_i.sfi_type);
}
/* Call the common vnode initializer */
result = vnode_init(&sv->sv_absvn, ops, &sfs->sfs_absfs, sv);
if (result) {
kfree(sv);
return result;
}
/* Call the common vnode initializer */
result = vnode_init(&sv->sv_absvn, ops, &sfs->sfs_absfs, sv);
if (result) {
kfree(sv);
return result;
}
/* Set the other fields in our vnode structure */
sv->sv_ino = ino;
/* Set the other fields in our vnode structure */
sv->sv_ino = ino;
/* Add it to our table */
result = vnodearray_add(sfs->sfs_vnodes, &sv->sv_absvn, NULL);
if (result) {
vnode_cleanup(&sv->sv_absvn);
kfree(sv);
return result;
}
/* Add it to our table */
result = vnodearray_add(sfs->sfs_vnodes, &sv->sv_absvn, NULL);
if (result) {
vnode_cleanup(&sv->sv_absvn);
kfree(sv);
return result;
}
/* Hand it back */
*ret = sv;
return 0;
/* Hand it back */
*ret = sv;
return 0;
}
/*
* Create a new filesystem object and hand back its vnode.
*/
int
sfs_makeobj(struct sfs_fs *sfs, int type, struct sfs_vnode **ret)
{
uint32_t ino;
int result;
int sfs_makeobj(struct sfs_fs *sfs, int type, struct sfs_vnode **ret) {
uint32_t ino;
int result;
/*
* First, get an inode. (Each inode is a block, and the inode
* number is the block number, so just get a block.)
*/
/*
* First, get an inode. (Each inode is a block, and the inode
* number is the block number, so just get a block.)
*/
result = sfs_balloc(sfs, &ino);
if (result) {
return result;
}
result = sfs_balloc(sfs, &ino);
if (result) {
return result;
}
/*
* Now load a vnode for it.
*/
/*
* Now load a vnode for it.
*/
result = sfs_loadvnode(sfs, ino, type, ret);
if (result) {
sfs_bfree(sfs, ino);
}
return result;
result = sfs_loadvnode(sfs, ino, type, ret);
if (result) {
sfs_bfree(sfs, ino);
}
return result;
}
/*
* Get vnode for the root of the filesystem.
* The root vnode is always found in block 1 (SFS_ROOTDIR_INO).
*/
int
sfs_getroot(struct fs *fs, struct vnode **ret)
{
struct sfs_fs *sfs = fs->fs_data;
struct sfs_vnode *sv;
int result;
int sfs_getroot(struct fs *fs, struct vnode **ret) {
struct sfs_fs *sfs = fs->fs_data;
struct sfs_vnode *sv;
int result;
vfs_biglock_acquire();
vfs_biglock_acquire();
result = sfs_loadvnode(sfs, SFS_ROOTDIR_INO, SFS_TYPE_INVAL, &sv);
if (result) {
kprintf("sfs: %s: getroot: Cannot load root vnode\n",
sfs->sfs_sb.sb_volname);
vfs_biglock_release();
return result;
}
result = sfs_loadvnode(sfs, SFS_ROOTDIR_INO, SFS_TYPE_INVAL, &sv);
if (result) {
kprintf("sfs: %s: getroot: Cannot load root vnode\n",
sfs->sfs_sb.sb_volname);
vfs_biglock_release();
return result;
}
if (sv->sv_i.sfi_type != SFS_TYPE_DIR) {
kprintf("sfs: %s: getroot: not directory (type %u)\n",
sfs->sfs_sb.sb_volname, sv->sv_i.sfi_type);
vfs_biglock_release();
return EINVAL;
}
if (sv->sv_i.sfi_type != SFS_TYPE_DIR) {
kprintf("sfs: %s: getroot: not directory (type %u)\n",
sfs->sfs_sb.sb_volname, sv->sv_i.sfi_type);
vfs_biglock_release();
return EINVAL;
}
vfs_biglock_release();
vfs_biglock_release();
*ret = &sv->sv_absvn;
return 0;
*ret = &sv->sv_absvn;
return 0;
}

View File

@@ -55,80 +55,67 @@
/*
* Read or write a block, retrying I/O errors.
*/
static
int
sfs_rwblock(struct sfs_fs *sfs, struct uio *uio)
{
int result;
int tries=0;
static int sfs_rwblock(struct sfs_fs *sfs, struct uio *uio) {
int result;
int tries = 0;
KASSERT(vfs_biglock_do_i_hold());
KASSERT(vfs_biglock_do_i_hold());
DEBUG(DB_SFS, "sfs: %s %llu\n",
uio->uio_rw == UIO_READ ? "read" : "write",
uio->uio_offset / SFS_BLOCKSIZE);
DEBUG(DB_SFS, "sfs: %s %llu\n", uio->uio_rw == UIO_READ ? "read" : "write",
uio->uio_offset / SFS_BLOCKSIZE);
retry:
result = DEVOP_IO(sfs->sfs_device, uio);
if (result == EINVAL) {
/*
* This means the sector we requested was out of range,
* or the seek address we gave wasn't sector-aligned,
* or a couple of other things that are our fault.
*/
panic("sfs: %s: DEVOP_IO returned EINVAL\n",
sfs->sfs_sb.sb_volname);
}
if (result == EIO) {
if (tries == 0) {
tries++;
kprintf("sfs: %s: block %llu I/O error, retrying\n",
sfs->sfs_sb.sb_volname,
uio->uio_offset / SFS_BLOCKSIZE);
goto retry;
}
else if (tries < 10) {
tries++;
goto retry;
}
else {
kprintf("sfs: %s: block %llu I/O error, giving up "
"after %d retries\n",
sfs->sfs_sb.sb_volname,
uio->uio_offset / SFS_BLOCKSIZE, tries);
}
}
return result;
retry:
result = DEVOP_IO(sfs->sfs_device, uio);
if (result == EINVAL) {
/*
* This means the sector we requested was out of range,
* or the seek address we gave wasn't sector-aligned,
* or a couple of other things that are our fault.
*/
panic("sfs: %s: DEVOP_IO returned EINVAL\n", sfs->sfs_sb.sb_volname);
}
if (result == EIO) {
if (tries == 0) {
tries++;
kprintf("sfs: %s: block %llu I/O error, retrying\n",
sfs->sfs_sb.sb_volname, uio->uio_offset / SFS_BLOCKSIZE);
goto retry;
} else if (tries < 10) {
tries++;
goto retry;
} else {
kprintf("sfs: %s: block %llu I/O error, giving up "
"after %d retries\n",
sfs->sfs_sb.sb_volname, uio->uio_offset / SFS_BLOCKSIZE, tries);
}
}
return result;
}
/*
* Read a block.
*/
int
sfs_readblock(struct sfs_fs *sfs, daddr_t block, void *data, size_t len)
{
struct iovec iov;
struct uio ku;
int sfs_readblock(struct sfs_fs *sfs, daddr_t block, void *data, size_t len) {
struct iovec iov;
struct uio ku;
KASSERT(len == SFS_BLOCKSIZE);
KASSERT(len == SFS_BLOCKSIZE);
SFSUIO(&iov, &ku, data, block, UIO_READ);
return sfs_rwblock(sfs, &ku);
SFSUIO(&iov, &ku, data, block, UIO_READ);
return sfs_rwblock(sfs, &ku);
}
/*
* Write a block.
*/
int
sfs_writeblock(struct sfs_fs *sfs, daddr_t block, void *data, size_t len)
{
struct iovec iov;
struct uio ku;
int sfs_writeblock(struct sfs_fs *sfs, daddr_t block, void *data, size_t len) {
struct iovec iov;
struct uio ku;
KASSERT(len == SFS_BLOCKSIZE);
KASSERT(len == SFS_BLOCKSIZE);
SFSUIO(&iov, &ku, data, block, UIO_WRITE);
return sfs_rwblock(sfs, &ku);
SFSUIO(&iov, &ku, data, block, UIO_WRITE);
return sfs_rwblock(sfs, &ku);
}
////////////////////////////////////////////////////////////
@@ -145,247 +132,237 @@ sfs_writeblock(struct sfs_fs *sfs, daddr_t block, void *data, size_t len)
* the sector; LEN is the number of bytes to actually read or write.
* UIO is the area to do the I/O into.
*/
static
int
sfs_partialio(struct sfs_vnode *sv, struct uio *uio,
uint32_t skipstart, uint32_t len)
{
/*
* I/O buffer for handling partial sectors.
*
* Note: in real life (and when you've done the fs assignment)
* you would get space from the disk buffer cache for this,
* not use a static area.
*/
static char iobuf[SFS_BLOCKSIZE];
static int sfs_partialio(struct sfs_vnode *sv, struct uio *uio,
uint32_t skipstart, uint32_t len) {
/*
* I/O buffer for handling partial sectors.
*
* Note: in real life (and when you've done the fs assignment)
* you would get space from the disk buffer cache for this,
* not use a static area.
*/
static char iobuf[SFS_BLOCKSIZE];
struct sfs_fs *sfs = sv->sv_absvn.vn_fs->fs_data;
daddr_t diskblock;
uint32_t fileblock;
int result;
struct sfs_fs *sfs = sv->sv_absvn.vn_fs->fs_data;
daddr_t diskblock;
uint32_t fileblock;
int result;
/* Allocate missing blocks if and only if we're writing */
bool doalloc = (uio->uio_rw==UIO_WRITE);
/* Allocate missing blocks if and only if we're writing */
bool doalloc = (uio->uio_rw == UIO_WRITE);
KASSERT(skipstart + len <= SFS_BLOCKSIZE);
KASSERT(skipstart + len <= SFS_BLOCKSIZE);
/* We're using a global static buffer; it had better be locked */
KASSERT(vfs_biglock_do_i_hold());
/* We're using a global static buffer; it had better be locked */
KASSERT(vfs_biglock_do_i_hold());
/* Compute the block offset of this block in the file */
fileblock = uio->uio_offset / SFS_BLOCKSIZE;
/* Compute the block offset of this block in the file */
fileblock = uio->uio_offset / SFS_BLOCKSIZE;
/* Get the disk block number */
result = sfs_bmap(sv, fileblock, doalloc, &diskblock);
if (result) {
return result;
}
/* Get the disk block number */
result = sfs_bmap(sv, fileblock, doalloc, &diskblock);
if (result) {
return result;
}
if (diskblock == 0) {
/*
* There was no block mapped at this point in the file.
* Zero the buffer.
*/
KASSERT(uio->uio_rw == UIO_READ);
bzero(iobuf, sizeof(iobuf));
}
else {
/*
* Read the block.
*/
result = sfs_readblock(sfs, diskblock, iobuf, sizeof(iobuf));
if (result) {
return result;
}
}
if (diskblock == 0) {
/*
* There was no block mapped at this point in the file.
* Zero the buffer.
*/
KASSERT(uio->uio_rw == UIO_READ);
bzero(iobuf, sizeof(iobuf));
} else {
/*
* Read the block.
*/
result = sfs_readblock(sfs, diskblock, iobuf, sizeof(iobuf));
if (result) {
return result;
}
}
/*
* Now perform the requested operation into/out of the buffer.
*/
result = uiomove(iobuf+skipstart, len, uio);
if (result) {
return result;
}
/*
* Now perform the requested operation into/out of the buffer.
*/
result = uiomove(iobuf + skipstart, len, uio);
if (result) {
return result;
}
/*
* If it was a write, write back the modified block.
*/
if (uio->uio_rw == UIO_WRITE) {
result = sfs_writeblock(sfs, diskblock, iobuf, sizeof(iobuf));
if (result) {
return result;
}
}
/*
* If it was a write, write back the modified block.
*/
if (uio->uio_rw == UIO_WRITE) {
result = sfs_writeblock(sfs, diskblock, iobuf, sizeof(iobuf));
if (result) {
return result;
}
}
return 0;
return 0;
}
/*
* Do I/O (either read or write) of a single whole block.
*/
static
int
sfs_blockio(struct sfs_vnode *sv, struct uio *uio)
{
struct sfs_fs *sfs = sv->sv_absvn.vn_fs->fs_data;
daddr_t diskblock;
uint32_t fileblock;
int result;
bool doalloc = (uio->uio_rw==UIO_WRITE);
off_t saveoff;
off_t diskoff;
off_t saveres;
off_t diskres;
static int sfs_blockio(struct sfs_vnode *sv, struct uio *uio) {
struct sfs_fs *sfs = sv->sv_absvn.vn_fs->fs_data;
daddr_t diskblock;
uint32_t fileblock;
int result;
bool doalloc = (uio->uio_rw == UIO_WRITE);
off_t saveoff;
off_t diskoff;
off_t saveres;
off_t diskres;
/* Get the block number within the file */
fileblock = uio->uio_offset / SFS_BLOCKSIZE;
/* Get the block number within the file */
fileblock = uio->uio_offset / SFS_BLOCKSIZE;
/* Look up the disk block number */
result = sfs_bmap(sv, fileblock, doalloc, &diskblock);
if (result) {
return result;
}
/* Look up the disk block number */
result = sfs_bmap(sv, fileblock, doalloc, &diskblock);
if (result) {
return result;
}
if (diskblock == 0) {
/*
* No block - fill with zeros.
*
* We must be reading, or sfs_bmap would have
* allocated a block for us.
*/
KASSERT(uio->uio_rw == UIO_READ);
return uiomovezeros(SFS_BLOCKSIZE, uio);
}
if (diskblock == 0) {
/*
* No block - fill with zeros.
*
* We must be reading, or sfs_bmap would have
* allocated a block for us.
*/
KASSERT(uio->uio_rw == UIO_READ);
return uiomovezeros(SFS_BLOCKSIZE, uio);
}
/*
* Do the I/O directly to the uio region. Save the uio_offset,
* and substitute one that makes sense to the device.
*/
saveoff = uio->uio_offset;
diskoff = diskblock * SFS_BLOCKSIZE;
uio->uio_offset = diskoff;
/*
* Do the I/O directly to the uio region. Save the uio_offset,
* and substitute one that makes sense to the device.
*/
saveoff = uio->uio_offset;
diskoff = diskblock * SFS_BLOCKSIZE;
uio->uio_offset = diskoff;
/*
* Temporarily set the residue to be one block size.
*/
KASSERT(uio->uio_resid >= SFS_BLOCKSIZE);
saveres = uio->uio_resid;
diskres = SFS_BLOCKSIZE;
uio->uio_resid = diskres;
/*
* Temporarily set the residue to be one block size.
*/
KASSERT(uio->uio_resid >= SFS_BLOCKSIZE);
saveres = uio->uio_resid;
diskres = SFS_BLOCKSIZE;
uio->uio_resid = diskres;
result = sfs_rwblock(sfs, uio);
result = sfs_rwblock(sfs, uio);
/*
* Now, restore the original uio_offset and uio_resid and update
* them by the amount of I/O done.
*/
uio->uio_offset = (uio->uio_offset - diskoff) + saveoff;
uio->uio_resid = (uio->uio_resid - diskres) + saveres;
/*
* Now, restore the original uio_offset and uio_resid and update
* them by the amount of I/O done.
*/
uio->uio_offset = (uio->uio_offset - diskoff) + saveoff;
uio->uio_resid = (uio->uio_resid - diskres) + saveres;
return result;
return result;
}
/*
* Do I/O of a whole region of data, whether or not it's block-aligned.
*/
int
sfs_io(struct sfs_vnode *sv, struct uio *uio)
{
uint32_t blkoff;
uint32_t nblocks, i;
int result = 0;
uint32_t origresid, extraresid = 0;
int sfs_io(struct sfs_vnode *sv, struct uio *uio) {
uint32_t blkoff;
uint32_t nblocks, i;
int result = 0;
uint32_t origresid, extraresid = 0;
origresid = uio->uio_resid;
origresid = uio->uio_resid;
/*
* If reading, check for EOF. If we can read a partial area,
* remember how much extra there was in EXTRARESID so we can
* add it back to uio_resid at the end.
*/
if (uio->uio_rw == UIO_READ) {
off_t size = sv->sv_i.sfi_size;
off_t endpos = uio->uio_offset + uio->uio_resid;
/*
* If reading, check for EOF. If we can read a partial area,
* remember how much extra there was in EXTRARESID so we can
* add it back to uio_resid at the end.
*/
if (uio->uio_rw == UIO_READ) {
off_t size = sv->sv_i.sfi_size;
off_t endpos = uio->uio_offset + uio->uio_resid;
if (uio->uio_offset >= size) {
/* At or past EOF - just return */
return 0;
}
if (uio->uio_offset >= size) {
/* At or past EOF - just return */
return 0;
}
if (endpos > size) {
extraresid = endpos - size;
KASSERT(uio->uio_resid > extraresid);
uio->uio_resid -= extraresid;
}
}
if (endpos > size) {
extraresid = endpos - size;
KASSERT(uio->uio_resid > extraresid);
uio->uio_resid -= extraresid;
}
}
/*
* First, do any leading partial block.
*/
blkoff = uio->uio_offset % SFS_BLOCKSIZE;
if (blkoff != 0) {
/* Number of bytes at beginning of block to skip */
uint32_t skip = blkoff;
/*
* First, do any leading partial block.
*/
blkoff = uio->uio_offset % SFS_BLOCKSIZE;
if (blkoff != 0) {
/* Number of bytes at beginning of block to skip */
uint32_t skip = blkoff;
/* Number of bytes to read/write after that point */
uint32_t len = SFS_BLOCKSIZE - blkoff;
/* Number of bytes to read/write after that point */
uint32_t len = SFS_BLOCKSIZE - blkoff;
/* ...which might be less than the rest of the block */
if (len > uio->uio_resid) {
len = uio->uio_resid;
}
/* ...which might be less than the rest of the block */
if (len > uio->uio_resid) {
len = uio->uio_resid;
}
/* Call sfs_partialio() to do it. */
result = sfs_partialio(sv, uio, skip, len);
if (result) {
goto out;
}
}
/* Call sfs_partialio() to do it. */
result = sfs_partialio(sv, uio, skip, len);
if (result) {
goto out;
}
}
/* If we're done, quit. */
if (uio->uio_resid==0) {
goto out;
}
/* If we're done, quit. */
if (uio->uio_resid == 0) {
goto out;
}
/*
* Now we should be block-aligned. Do the remaining whole blocks.
*/
KASSERT(uio->uio_offset % SFS_BLOCKSIZE == 0);
nblocks = uio->uio_resid / SFS_BLOCKSIZE;
for (i=0; i<nblocks; i++) {
result = sfs_blockio(sv, uio);
if (result) {
goto out;
}
}
/*
* Now we should be block-aligned. Do the remaining whole blocks.
*/
KASSERT(uio->uio_offset % SFS_BLOCKSIZE == 0);
nblocks = uio->uio_resid / SFS_BLOCKSIZE;
for (i = 0; i < nblocks; i++) {
result = sfs_blockio(sv, uio);
if (result) {
goto out;
}
}
/*
* Now do any remaining partial block at the end.
*/
KASSERT(uio->uio_resid < SFS_BLOCKSIZE);
/*
* Now do any remaining partial block at the end.
*/
KASSERT(uio->uio_resid < SFS_BLOCKSIZE);
if (uio->uio_resid > 0) {
result = sfs_partialio(sv, uio, 0, uio->uio_resid);
if (result) {
goto out;
}
}
if (uio->uio_resid > 0) {
result = sfs_partialio(sv, uio, 0, uio->uio_resid);
if (result) {
goto out;
}
}
out:
out:
/* If writing and we did anything, adjust file length */
if (uio->uio_resid != origresid &&
uio->uio_rw == UIO_WRITE &&
uio->uio_offset > (off_t)sv->sv_i.sfi_size) {
sv->sv_i.sfi_size = uio->uio_offset;
sv->sv_dirty = true;
}
/* If writing and we did anything, adjust file length */
if (uio->uio_resid != origresid && uio->uio_rw == UIO_WRITE &&
uio->uio_offset > (off_t)sv->sv_i.sfi_size) {
sv->sv_i.sfi_size = uio->uio_offset;
sv->sv_dirty = true;
}
/* Add in any extra amount we couldn't read because of EOF */
uio->uio_resid += extraresid;
/* Add in any extra amount we couldn't read because of EOF */
uio->uio_resid += extraresid;
/* Done */
return result;
/* Done */
return result;
}
////////////////////////////////////////////////////////////
@@ -402,79 +379,75 @@ sfs_io(struct sfs_vnode *sv, struct uio *uio)
* more advanced things to handle metadata and user data I/O
* differently.
*/
int
sfs_metaio(struct sfs_vnode *sv, off_t actualpos, void *data, size_t len,
enum uio_rw rw)
{
struct sfs_fs *sfs = sv->sv_absvn.vn_fs->fs_data;
off_t endpos;
uint32_t vnblock;
uint32_t blockoffset;
daddr_t diskblock;
bool doalloc;
int result;
int sfs_metaio(struct sfs_vnode *sv, off_t actualpos, void *data, size_t len,
enum uio_rw rw) {
struct sfs_fs *sfs = sv->sv_absvn.vn_fs->fs_data;
off_t endpos;
uint32_t vnblock;
uint32_t blockoffset;
daddr_t diskblock;
bool doalloc;
int result;
/*
* I/O buffer for metadata ops.
*
* Note: in real life (and when you've done the fs assignment) you
* would get space from the disk buffer cache for this, not use a
* static area.
*/
static char metaiobuf[SFS_BLOCKSIZE];
/*
* I/O buffer for metadata ops.
*
* Note: in real life (and when you've done the fs assignment) you
* would get space from the disk buffer cache for this, not use a
* static area.
*/
static char metaiobuf[SFS_BLOCKSIZE];
/* We're using a global static buffer; it had better be locked */
KASSERT(vfs_biglock_do_i_hold());
/* We're using a global static buffer; it had better be locked */
KASSERT(vfs_biglock_do_i_hold());
/* Figure out which block of the vnode (directory, whatever) this is */
vnblock = actualpos / SFS_BLOCKSIZE;
blockoffset = actualpos % SFS_BLOCKSIZE;
/* Figure out which block of the vnode (directory, whatever) this is */
vnblock = actualpos / SFS_BLOCKSIZE;
blockoffset = actualpos % SFS_BLOCKSIZE;
/* Get the disk block number */
doalloc = (rw == UIO_WRITE);
result = sfs_bmap(sv, vnblock, doalloc, &diskblock);
if (result) {
return result;
}
/* Get the disk block number */
doalloc = (rw == UIO_WRITE);
result = sfs_bmap(sv, vnblock, doalloc, &diskblock);
if (result) {
return result;
}
if (diskblock == 0) {
/* Should only get block 0 back if doalloc is false */
KASSERT(rw == UIO_READ);
if (diskblock == 0) {
/* Should only get block 0 back if doalloc is false */
KASSERT(rw == UIO_READ);
/* Sparse file, read as zeros. */
bzero(data, len);
return 0;
}
/* Sparse file, read as zeros. */
bzero(data, len);
return 0;
}
/* Read the block */
result = sfs_readblock(sfs, diskblock, metaiobuf, sizeof(metaiobuf));
if (result) {
return result;
}
/* Read the block */
result = sfs_readblock(sfs, diskblock, metaiobuf, sizeof(metaiobuf));
if (result) {
return result;
}
if (rw == UIO_READ) {
/* Copy out the selected region */
memcpy(data, metaiobuf + blockoffset, len);
}
else {
/* Update the selected region */
memcpy(metaiobuf + blockoffset, data, len);
if (rw == UIO_READ) {
/* Copy out the selected region */
memcpy(data, metaiobuf + blockoffset, len);
} else {
/* Update the selected region */
memcpy(metaiobuf + blockoffset, data, len);
/* Write the block back */
result = sfs_writeblock(sfs, diskblock,
metaiobuf, sizeof(metaiobuf));
if (result) {
return result;
}
/* Write the block back */
result = sfs_writeblock(sfs, diskblock, metaiobuf, sizeof(metaiobuf));
if (result) {
return result;
}
/* Update the vnode size if needed */
endpos = actualpos + len;
if (endpos > (off_t)sv->sv_i.sfi_size) {
sv->sv_i.sfi_size = endpos;
sv->sv_dirty = true;
}
}
/* Update the vnode size if needed */
endpos = actualpos + len;
if (endpos > (off_t)sv->sv_i.sfi_size) {
sv->sv_i.sfi_size = endpos;
sv->sv_dirty = true;
}
}
/* Done */
return 0;
/* Done */
return 0;
}

View File

@@ -48,210 +48,177 @@
/*
* This is called on *each* open().
*/
static
int
sfs_eachopen(struct vnode *v, int openflags)
{
/*
* At this level we do not need to handle O_CREAT, O_EXCL,
* O_TRUNC, or O_APPEND.
*
* Any of O_RDONLY, O_WRONLY, and O_RDWR are valid, so we don't need
* to check that either.
*/
static int sfs_eachopen(struct vnode *v, int openflags) {
/*
* At this level we do not need to handle O_CREAT, O_EXCL,
* O_TRUNC, or O_APPEND.
*
* Any of O_RDONLY, O_WRONLY, and O_RDWR are valid, so we don't need
* to check that either.
*/
(void)v;
(void)openflags;
(void)v;
(void)openflags;
return 0;
return 0;
}
/*
* This is called on *each* open() of a directory.
* Directories may only be open for read.
*/
static
int
sfs_eachopendir(struct vnode *v, int openflags)
{
switch (openflags & O_ACCMODE) {
case O_RDONLY:
break;
case O_WRONLY:
case O_RDWR:
default:
return EISDIR;
}
if (openflags & O_APPEND) {
return EISDIR;
}
static int sfs_eachopendir(struct vnode *v, int openflags) {
switch (openflags & O_ACCMODE) {
case O_RDONLY:
break;
case O_WRONLY:
case O_RDWR:
default:
return EISDIR;
}
if (openflags & O_APPEND) {
return EISDIR;
}
(void)v;
return 0;
(void)v;
return 0;
}
/*
* Called for read(). sfs_io() does the work.
*/
static
int
sfs_read(struct vnode *v, struct uio *uio)
{
struct sfs_vnode *sv = v->vn_data;
int result;
static int sfs_read(struct vnode *v, struct uio *uio) {
struct sfs_vnode *sv = v->vn_data;
int result;
KASSERT(uio->uio_rw==UIO_READ);
KASSERT(uio->uio_rw == UIO_READ);
vfs_biglock_acquire();
result = sfs_io(sv, uio);
vfs_biglock_release();
vfs_biglock_acquire();
result = sfs_io(sv, uio);
vfs_biglock_release();
return result;
return result;
}
/*
* Called for write(). sfs_io() does the work.
*/
static
int
sfs_write(struct vnode *v, struct uio *uio)
{
struct sfs_vnode *sv = v->vn_data;
int result;
static int sfs_write(struct vnode *v, struct uio *uio) {
struct sfs_vnode *sv = v->vn_data;
int result;
KASSERT(uio->uio_rw==UIO_WRITE);
KASSERT(uio->uio_rw == UIO_WRITE);
vfs_biglock_acquire();
result = sfs_io(sv, uio);
vfs_biglock_release();
vfs_biglock_acquire();
result = sfs_io(sv, uio);
vfs_biglock_release();
return result;
return result;
}
/*
* Called for ioctl()
*/
static
int
sfs_ioctl(struct vnode *v, int op, userptr_t data)
{
/*
* No ioctls.
*/
static int sfs_ioctl(struct vnode *v, int op, userptr_t data) {
/*
* No ioctls.
*/
(void)v;
(void)op;
(void)data;
(void)v;
(void)op;
(void)data;
return EINVAL;
return EINVAL;
}
/*
* Called for stat/fstat/lstat.
*/
static
int
sfs_stat(struct vnode *v, struct stat *statbuf)
{
struct sfs_vnode *sv = v->vn_data;
int result;
static int sfs_stat(struct vnode *v, struct stat *statbuf) {
struct sfs_vnode *sv = v->vn_data;
int result;
/* Fill in the stat structure */
bzero(statbuf, sizeof(struct stat));
/* Fill in the stat structure */
bzero(statbuf, sizeof(struct stat));
result = VOP_GETTYPE(v, &statbuf->st_mode);
if (result) {
return result;
}
result = VOP_GETTYPE(v, &statbuf->st_mode);
if (result) {
return result;
}
statbuf->st_size = sv->sv_i.sfi_size;
statbuf->st_nlink = sv->sv_i.sfi_linkcount;
statbuf->st_size = sv->sv_i.sfi_size;
statbuf->st_nlink = sv->sv_i.sfi_linkcount;
/* We don't support this yet */
statbuf->st_blocks = 0;
/* We don't support this yet */
statbuf->st_blocks = 0;
/* Fill in other fields as desired/possible... */
/* Fill in other fields as desired/possible... */
return 0;
return 0;
}
/*
* Return the type of the file (types as per kern/stat.h)
*/
static
int
sfs_gettype(struct vnode *v, uint32_t *ret)
{
struct sfs_vnode *sv = v->vn_data;
struct sfs_fs *sfs = v->vn_fs->fs_data;
static int sfs_gettype(struct vnode *v, uint32_t *ret) {
struct sfs_vnode *sv = v->vn_data;
struct sfs_fs *sfs = v->vn_fs->fs_data;
vfs_biglock_acquire();
vfs_biglock_acquire();
switch (sv->sv_i.sfi_type) {
case SFS_TYPE_FILE:
*ret = S_IFREG;
vfs_biglock_release();
return 0;
case SFS_TYPE_DIR:
*ret = S_IFDIR;
vfs_biglock_release();
return 0;
}
panic("sfs: %s: gettype: Invalid inode type (inode %u, type %u)\n",
sfs->sfs_sb.sb_volname, sv->sv_ino, sv->sv_i.sfi_type);
return EINVAL;
switch (sv->sv_i.sfi_type) {
case SFS_TYPE_FILE:
*ret = S_IFREG;
vfs_biglock_release();
return 0;
case SFS_TYPE_DIR:
*ret = S_IFDIR;
vfs_biglock_release();
return 0;
}
panic("sfs: %s: gettype: Invalid inode type (inode %u, type %u)\n",
sfs->sfs_sb.sb_volname, sv->sv_ino, sv->sv_i.sfi_type);
return EINVAL;
}
/*
* Check if seeking is allowed. The answer is "yes".
*/
static
bool
sfs_isseekable(struct vnode *v)
{
(void)v;
return true;
static bool sfs_isseekable(struct vnode *v) {
(void)v;
return true;
}
/*
* Called for fsync(), and also on filesystem unmount, global sync(),
* and some other cases.
*/
static
int
sfs_fsync(struct vnode *v)
{
struct sfs_vnode *sv = v->vn_data;
int result;
static int sfs_fsync(struct vnode *v) {
struct sfs_vnode *sv = v->vn_data;
int result;
vfs_biglock_acquire();
result = sfs_sync_inode(sv);
vfs_biglock_release();
vfs_biglock_acquire();
result = sfs_sync_inode(sv);
vfs_biglock_release();
return result;
return result;
}
/*
* Called for mmap().
*/
static
int
sfs_mmap(struct vnode *v /* add stuff as needed */)
{
(void)v;
return ENOSYS;
static int sfs_mmap(struct vnode *v /* add stuff as needed */) {
(void)v;
return ENOSYS;
}
/*
* Truncate a file.
*/
static
int
sfs_truncate(struct vnode *v, off_t len)
{
struct sfs_vnode *sv = v->vn_data;
static int sfs_truncate(struct vnode *v, off_t len) {
struct sfs_vnode *sv = v->vn_data;
return sfs_itrunc(sv, len);
return sfs_itrunc(sv, len);
}
/*
@@ -260,90 +227,84 @@ sfs_truncate(struct vnode *v, off_t len)
* and hand back the empty string. (The VFS layer takes care of the
* device name, leading slash, etc.)
*/
static
int
sfs_namefile(struct vnode *vv, struct uio *uio)
{
struct sfs_vnode *sv = vv->vn_data;
KASSERT(sv->sv_ino == SFS_ROOTDIR_INO);
static int sfs_namefile(struct vnode *vv, struct uio *uio) {
struct sfs_vnode *sv = vv->vn_data;
KASSERT(sv->sv_ino == SFS_ROOTDIR_INO);
/* send back the empty string - just return */
/* send back the empty string - just return */
(void)uio;
(void)uio;
return 0;
return 0;
}
/*
* Create a file. If EXCL is set, insist that the filename not already
* exist; otherwise, if it already exists, just open it.
*/
static
int
sfs_creat(struct vnode *v, const char *name, bool excl, mode_t mode,
struct vnode **ret)
{
struct sfs_fs *sfs = v->vn_fs->fs_data;
struct sfs_vnode *sv = v->vn_data;
struct sfs_vnode *newguy;
uint32_t ino;
int result;
static int sfs_creat(struct vnode *v, const char *name, bool excl, mode_t mode,
struct vnode **ret) {
struct sfs_fs *sfs = v->vn_fs->fs_data;
struct sfs_vnode *sv = v->vn_data;
struct sfs_vnode *newguy;
uint32_t ino;
int result;
vfs_biglock_acquire();
vfs_biglock_acquire();
/* Look up the name */
result = sfs_dir_findname(sv, name, &ino, NULL, NULL);
if (result!=0 && result!=ENOENT) {
vfs_biglock_release();
return result;
}
/* Look up the name */
result = sfs_dir_findname(sv, name, &ino, NULL, NULL);
if (result != 0 && result != ENOENT) {
vfs_biglock_release();
return result;
}
/* If it exists and we didn't want it to, fail */
if (result==0 && excl) {
vfs_biglock_release();
return EEXIST;
}
/* If it exists and we didn't want it to, fail */
if (result == 0 && excl) {
vfs_biglock_release();
return EEXIST;
}
if (result==0) {
/* We got something; load its vnode and return */
result = sfs_loadvnode(sfs, ino, SFS_TYPE_INVAL, &newguy);
if (result) {
vfs_biglock_release();
return result;
}
*ret = &newguy->sv_absvn;
vfs_biglock_release();
return 0;
}
if (result == 0) {
/* We got something; load its vnode and return */
result = sfs_loadvnode(sfs, ino, SFS_TYPE_INVAL, &newguy);
if (result) {
vfs_biglock_release();
return result;
}
*ret = &newguy->sv_absvn;
vfs_biglock_release();
return 0;
}
/* Didn't exist - create it */
result = sfs_makeobj(sfs, SFS_TYPE_FILE, &newguy);
if (result) {
vfs_biglock_release();
return result;
}
/* Didn't exist - create it */
result = sfs_makeobj(sfs, SFS_TYPE_FILE, &newguy);
if (result) {
vfs_biglock_release();
return result;
}
/* We don't currently support file permissions; ignore MODE */
(void)mode;
/* We don't currently support file permissions; ignore MODE */
(void)mode;
/* Link it into the directory */
result = sfs_dir_link(sv, name, newguy->sv_ino, NULL);
if (result) {
VOP_DECREF(&newguy->sv_absvn);
vfs_biglock_release();
return result;
}
/* Link it into the directory */
result = sfs_dir_link(sv, name, newguy->sv_ino, NULL);
if (result) {
VOP_DECREF(&newguy->sv_absvn);
vfs_biglock_release();
return result;
}
/* Update the linkcount of the new file */
newguy->sv_i.sfi_linkcount++;
/* Update the linkcount of the new file */
newguy->sv_i.sfi_linkcount++;
/* and consequently mark it dirty. */
newguy->sv_dirty = true;
/* and consequently mark it dirty. */
newguy->sv_dirty = true;
*ret = &newguy->sv_absvn;
*ret = &newguy->sv_absvn;
vfs_biglock_release();
return 0;
vfs_biglock_release();
return 0;
}
/*
@@ -351,74 +312,68 @@ sfs_creat(struct vnode *v, const char *name, bool excl, mode_t mode,
* The VFS layer should prevent this being called unless both
* vnodes are ours.
*/
static
int
sfs_link(struct vnode *dir, const char *name, struct vnode *file)
{
struct sfs_vnode *sv = dir->vn_data;
struct sfs_vnode *f = file->vn_data;
int result;
static int sfs_link(struct vnode *dir, const char *name, struct vnode *file) {
struct sfs_vnode *sv = dir->vn_data;
struct sfs_vnode *f = file->vn_data;
int result;
KASSERT(file->vn_fs == dir->vn_fs);
KASSERT(file->vn_fs == dir->vn_fs);
vfs_biglock_acquire();
vfs_biglock_acquire();
/* Hard links to directories aren't allowed. */
if (f->sv_i.sfi_type == SFS_TYPE_DIR) {
vfs_biglock_release();
return EINVAL;
}
/* Hard links to directories aren't allowed. */
if (f->sv_i.sfi_type == SFS_TYPE_DIR) {
vfs_biglock_release();
return EINVAL;
}
/* Create the link */
result = sfs_dir_link(sv, name, f->sv_ino, NULL);
if (result) {
vfs_biglock_release();
return result;
}
/* Create the link */
result = sfs_dir_link(sv, name, f->sv_ino, NULL);
if (result) {
vfs_biglock_release();
return result;
}
/* and update the link count, marking the inode dirty */
f->sv_i.sfi_linkcount++;
f->sv_dirty = true;
/* and update the link count, marking the inode dirty */
f->sv_i.sfi_linkcount++;
f->sv_dirty = true;
vfs_biglock_release();
return 0;
vfs_biglock_release();
return 0;
}
/*
* Delete a file.
*/
static
int
sfs_remove(struct vnode *dir, const char *name)
{
struct sfs_vnode *sv = dir->vn_data;
struct sfs_vnode *victim;
int slot;
int result;
static int sfs_remove(struct vnode *dir, const char *name) {
struct sfs_vnode *sv = dir->vn_data;
struct sfs_vnode *victim;
int slot;
int result;
vfs_biglock_acquire();
vfs_biglock_acquire();
/* Look for the file and fetch a vnode for it. */
result = sfs_lookonce(sv, name, &victim, &slot);
if (result) {
vfs_biglock_release();
return result;
}
/* Look for the file and fetch a vnode for it. */
result = sfs_lookonce(sv, name, &victim, &slot);
if (result) {
vfs_biglock_release();
return result;
}
/* Erase its directory entry. */
result = sfs_dir_unlink(sv, slot);
if (result==0) {
/* If we succeeded, decrement the link count. */
KASSERT(victim->sv_i.sfi_linkcount > 0);
victim->sv_i.sfi_linkcount--;
victim->sv_dirty = true;
}
/* Erase its directory entry. */
result = sfs_dir_unlink(sv, slot);
if (result == 0) {
/* If we succeeded, decrement the link count. */
KASSERT(victim->sv_i.sfi_linkcount > 0);
victim->sv_i.sfi_linkcount--;
victim->sv_dirty = true;
}
/* Discard the reference that sfs_lookonce got us */
VOP_DECREF(&victim->sv_absvn);
/* Discard the reference that sfs_lookonce got us */
VOP_DECREF(&victim->sv_absvn);
vfs_biglock_release();
return result;
vfs_biglock_release();
return result;
}
/*
@@ -427,88 +382,83 @@ sfs_remove(struct vnode *dir, const char *name)
* Since we don't support subdirectories, assumes that the two
* directories passed are the same.
*/
static
int
sfs_rename(struct vnode *d1, const char *n1,
struct vnode *d2, const char *n2)
{
struct sfs_vnode *sv = d1->vn_data;
struct sfs_fs *sfs = sv->sv_absvn.vn_fs->fs_data;
struct sfs_vnode *g1;
int slot1, slot2;
int result, result2;
static int sfs_rename(struct vnode *d1, const char *n1, struct vnode *d2,
const char *n2) {
struct sfs_vnode *sv = d1->vn_data;
struct sfs_fs *sfs = sv->sv_absvn.vn_fs->fs_data;
struct sfs_vnode *g1;
int slot1, slot2;
int result, result2;
vfs_biglock_acquire();
vfs_biglock_acquire();
KASSERT(d1==d2);
KASSERT(sv->sv_ino == SFS_ROOTDIR_INO);
KASSERT(d1 == d2);
KASSERT(sv->sv_ino == SFS_ROOTDIR_INO);
/* Look up the old name of the file and get its inode and slot number*/
result = sfs_lookonce(sv, n1, &g1, &slot1);
if (result) {
vfs_biglock_release();
return result;
}
/* Look up the old name of the file and get its inode and slot number*/
result = sfs_lookonce(sv, n1, &g1, &slot1);
if (result) {
vfs_biglock_release();
return result;
}
/* We don't support subdirectories */
KASSERT(g1->sv_i.sfi_type == SFS_TYPE_FILE);
/* We don't support subdirectories */
KASSERT(g1->sv_i.sfi_type == SFS_TYPE_FILE);
/*
* Link it under the new name.
*
* We could theoretically just overwrite the original
* directory entry, except that we need to check to make sure
* the new name doesn't already exist; might as well use the
* existing link routine.
*/
result = sfs_dir_link(sv, n2, g1->sv_ino, &slot2);
if (result) {
goto puke;
}
/*
* Link it under the new name.
*
* We could theoretically just overwrite the original
* directory entry, except that we need to check to make sure
* the new name doesn't already exist; might as well use the
* existing link routine.
*/
result = sfs_dir_link(sv, n2, g1->sv_ino, &slot2);
if (result) {
goto puke;
}
/* Increment the link count, and mark inode dirty */
g1->sv_i.sfi_linkcount++;
g1->sv_dirty = true;
/* Increment the link count, and mark inode dirty */
g1->sv_i.sfi_linkcount++;
g1->sv_dirty = true;
/* Unlink the old slot */
result = sfs_dir_unlink(sv, slot1);
if (result) {
goto puke_harder;
}
/* Unlink the old slot */
result = sfs_dir_unlink(sv, slot1);
if (result) {
goto puke_harder;
}
/*
* Decrement the link count again, and mark the inode dirty again,
* in case it's been synced behind our back.
*/
KASSERT(g1->sv_i.sfi_linkcount>0);
g1->sv_i.sfi_linkcount--;
g1->sv_dirty = true;
/*
* Decrement the link count again, and mark the inode dirty again,
* in case it's been synced behind our back.
*/
KASSERT(g1->sv_i.sfi_linkcount > 0);
g1->sv_i.sfi_linkcount--;
g1->sv_dirty = true;
/* Let go of the reference to g1 */
VOP_DECREF(&g1->sv_absvn);
/* Let go of the reference to g1 */
VOP_DECREF(&g1->sv_absvn);
vfs_biglock_release();
return 0;
vfs_biglock_release();
return 0;
puke_harder:
/*
* Error recovery: try to undo what we already did
*/
result2 = sfs_dir_unlink(sv, slot2);
if (result2) {
kprintf("sfs: %s: rename: %s\n",
sfs->sfs_sb.sb_volname, strerror(result));
kprintf("sfs: %s: rename: while cleaning up: %s\n",
sfs->sfs_sb.sb_volname, strerror(result2));
panic("sfs: %s: rename: Cannot recover\n",
sfs->sfs_sb.sb_volname);
}
g1->sv_i.sfi_linkcount--;
puke:
/* Let go of the reference to g1 */
VOP_DECREF(&g1->sv_absvn);
vfs_biglock_release();
return result;
puke_harder:
/*
* Error recovery: try to undo what we already did
*/
result2 = sfs_dir_unlink(sv, slot2);
if (result2) {
kprintf("sfs: %s: rename: %s\n", sfs->sfs_sb.sb_volname, strerror(result));
kprintf("sfs: %s: rename: while cleaning up: %s\n", sfs->sfs_sb.sb_volname,
strerror(result2));
panic("sfs: %s: rename: Cannot recover\n", sfs->sfs_sb.sb_volname);
}
g1->sv_i.sfi_linkcount--;
puke:
/* Let go of the reference to g1 */
VOP_DECREF(&g1->sv_absvn);
vfs_biglock_release();
return result;
}
/*
@@ -518,31 +468,28 @@ sfs_rename(struct vnode *d1, const char *n1,
* Since we don't support subdirectories, this is very easy -
* return the root dir and copy the path.
*/
static
int
sfs_lookparent(struct vnode *v, char *path, struct vnode **ret,
char *buf, size_t buflen)
{
struct sfs_vnode *sv = v->vn_data;
static int sfs_lookparent(struct vnode *v, char *path, struct vnode **ret,
char *buf, size_t buflen) {
struct sfs_vnode *sv = v->vn_data;
vfs_biglock_acquire();
vfs_biglock_acquire();
if (sv->sv_i.sfi_type != SFS_TYPE_DIR) {
vfs_biglock_release();
return ENOTDIR;
}
if (sv->sv_i.sfi_type != SFS_TYPE_DIR) {
vfs_biglock_release();
return ENOTDIR;
}
if (strlen(path)+1 > buflen) {
vfs_biglock_release();
return ENAMETOOLONG;
}
strcpy(buf, path);
if (strlen(path) + 1 > buflen) {
vfs_biglock_release();
return ENAMETOOLONG;
}
strcpy(buf, path);
VOP_INCREF(&sv->sv_absvn);
*ret = &sv->sv_absvn;
VOP_INCREF(&sv->sv_absvn);
*ret = &sv->sv_absvn;
vfs_biglock_release();
return 0;
vfs_biglock_release();
return 0;
}
/*
@@ -551,31 +498,28 @@ sfs_lookparent(struct vnode *v, char *path, struct vnode **ret,
* Since we don't support subdirectories, it's easy - just look up the
* name.
*/
static
int
sfs_lookup(struct vnode *v, char *path, struct vnode **ret)
{
struct sfs_vnode *sv = v->vn_data;
struct sfs_vnode *final;
int result;
static int sfs_lookup(struct vnode *v, char *path, struct vnode **ret) {
struct sfs_vnode *sv = v->vn_data;
struct sfs_vnode *final;
int result;
vfs_biglock_acquire();
vfs_biglock_acquire();
if (sv->sv_i.sfi_type != SFS_TYPE_DIR) {
vfs_biglock_release();
return ENOTDIR;
}
if (sv->sv_i.sfi_type != SFS_TYPE_DIR) {
vfs_biglock_release();
return ENOTDIR;
}
result = sfs_lookonce(sv, path, &final, NULL);
if (result) {
vfs_biglock_release();
return result;
}
result = sfs_lookonce(sv, path, &final, NULL);
if (result) {
vfs_biglock_release();
return result;
}
*ret = &final->sv_absvn;
*ret = &final->sv_absvn;
vfs_biglock_release();
return 0;
vfs_biglock_release();
return 0;
}
////////////////////////////////////////////////////////////
@@ -585,66 +529,66 @@ sfs_lookup(struct vnode *v, char *path, struct vnode **ret)
* Function table for sfs files.
*/
const struct vnode_ops sfs_fileops = {
.vop_magic = VOP_MAGIC, /* mark this a valid vnode ops table */
.vop_magic = VOP_MAGIC, /* mark this a valid vnode ops table */
.vop_eachopen = sfs_eachopen,
.vop_reclaim = sfs_reclaim,
.vop_eachopen = sfs_eachopen,
.vop_reclaim = sfs_reclaim,
.vop_read = sfs_read,
.vop_readlink = vopfail_uio_notdir,
.vop_getdirentry = vopfail_uio_notdir,
.vop_write = sfs_write,
.vop_ioctl = sfs_ioctl,
.vop_stat = sfs_stat,
.vop_gettype = sfs_gettype,
.vop_isseekable = sfs_isseekable,
.vop_fsync = sfs_fsync,
.vop_mmap = sfs_mmap,
.vop_truncate = sfs_truncate,
.vop_namefile = vopfail_uio_notdir,
.vop_read = sfs_read,
.vop_readlink = vopfail_uio_notdir,
.vop_getdirentry = vopfail_uio_notdir,
.vop_write = sfs_write,
.vop_ioctl = sfs_ioctl,
.vop_stat = sfs_stat,
.vop_gettype = sfs_gettype,
.vop_isseekable = sfs_isseekable,
.vop_fsync = sfs_fsync,
.vop_mmap = sfs_mmap,
.vop_truncate = sfs_truncate,
.vop_namefile = vopfail_uio_notdir,
.vop_creat = vopfail_creat_notdir,
.vop_symlink = vopfail_symlink_notdir,
.vop_mkdir = vopfail_mkdir_notdir,
.vop_link = vopfail_link_notdir,
.vop_remove = vopfail_string_notdir,
.vop_rmdir = vopfail_string_notdir,
.vop_rename = vopfail_rename_notdir,
.vop_creat = vopfail_creat_notdir,
.vop_symlink = vopfail_symlink_notdir,
.vop_mkdir = vopfail_mkdir_notdir,
.vop_link = vopfail_link_notdir,
.vop_remove = vopfail_string_notdir,
.vop_rmdir = vopfail_string_notdir,
.vop_rename = vopfail_rename_notdir,
.vop_lookup = vopfail_lookup_notdir,
.vop_lookparent = vopfail_lookparent_notdir,
.vop_lookup = vopfail_lookup_notdir,
.vop_lookparent = vopfail_lookparent_notdir,
};
/*
* Function table for the sfs directory.
*/
const struct vnode_ops sfs_dirops = {
.vop_magic = VOP_MAGIC, /* mark this a valid vnode ops table */
.vop_magic = VOP_MAGIC, /* mark this a valid vnode ops table */
.vop_eachopen = sfs_eachopendir,
.vop_reclaim = sfs_reclaim,
.vop_eachopen = sfs_eachopendir,
.vop_reclaim = sfs_reclaim,
.vop_read = vopfail_uio_isdir,
.vop_readlink = vopfail_uio_inval,
.vop_getdirentry = vopfail_uio_nosys,
.vop_write = vopfail_uio_isdir,
.vop_ioctl = sfs_ioctl,
.vop_stat = sfs_stat,
.vop_gettype = sfs_gettype,
.vop_isseekable = sfs_isseekable,
.vop_fsync = sfs_fsync,
.vop_mmap = vopfail_mmap_isdir,
.vop_truncate = vopfail_truncate_isdir,
.vop_namefile = sfs_namefile,
.vop_read = vopfail_uio_isdir,
.vop_readlink = vopfail_uio_inval,
.vop_getdirentry = vopfail_uio_nosys,
.vop_write = vopfail_uio_isdir,
.vop_ioctl = sfs_ioctl,
.vop_stat = sfs_stat,
.vop_gettype = sfs_gettype,
.vop_isseekable = sfs_isseekable,
.vop_fsync = sfs_fsync,
.vop_mmap = vopfail_mmap_isdir,
.vop_truncate = vopfail_truncate_isdir,
.vop_namefile = sfs_namefile,
.vop_creat = sfs_creat,
.vop_symlink = vopfail_symlink_nosys,
.vop_mkdir = vopfail_mkdir_nosys,
.vop_link = sfs_link,
.vop_remove = sfs_remove,
.vop_rmdir = vopfail_string_nosys,
.vop_rename = sfs_rename,
.vop_creat = sfs_creat,
.vop_symlink = vopfail_symlink_nosys,
.vop_mkdir = vopfail_mkdir_nosys,
.vop_link = sfs_link,
.vop_remove = sfs_remove,
.vop_rmdir = vopfail_string_nosys,
.vop_rename = sfs_rename,
.vop_lookup = sfs_lookup,
.vop_lookparent = sfs_lookparent,
.vop_lookup = sfs_lookup,
.vop_lookparent = sfs_lookparent,
};

View File

@@ -32,15 +32,13 @@
#include <uio.h> /* for uio_rw */
/* ops tables (in sfs_vnops.c) */
extern const struct vnode_ops sfs_fileops;
extern const struct vnode_ops sfs_dirops;
/* Macro for initializing a uio structure */
#define SFSUIO(iov, uio, ptr, block, rw) \
uio_kinit(iov, uio, ptr, SFS_BLOCKSIZE, ((off_t)(block))*SFS_BLOCKSIZE, rw)
#define SFSUIO(iov, uio, ptr, block, rw) \
uio_kinit(iov, uio, ptr, SFS_BLOCKSIZE, ((off_t)(block)) * SFS_BLOCKSIZE, rw)
/* Functions in sfs_balloc.c */
int sfs_balloc(struct sfs_fs *sfs, daddr_t *diskblock);
@@ -49,24 +47,23 @@ int sfs_bused(struct sfs_fs *sfs, daddr_t diskblock);
/* Functions in sfs_bmap.c */
int sfs_bmap(struct sfs_vnode *sv, uint32_t fileblock, bool doalloc,
daddr_t *diskblock);
daddr_t *diskblock);
int sfs_itrunc(struct sfs_vnode *sv, off_t len);
/* Functions in sfs_dir.c */
int sfs_dir_findname(struct sfs_vnode *sv, const char *name,
uint32_t *ino, int *slot, int *emptyslot);
int sfs_dir_findname(struct sfs_vnode *sv, const char *name, uint32_t *ino,
int *slot, int *emptyslot);
int sfs_dir_link(struct sfs_vnode *sv, const char *name, uint32_t ino,
int *slot);
int *slot);
int sfs_dir_unlink(struct sfs_vnode *sv, int slot);
int sfs_lookonce(struct sfs_vnode *sv, const char *name,
struct sfs_vnode **ret,
int *slot);
int sfs_lookonce(struct sfs_vnode *sv, const char *name, struct sfs_vnode **ret,
int *slot);
/* Functions in sfs_inode.c */
int sfs_sync_inode(struct sfs_vnode *sv);
int sfs_reclaim(struct vnode *v);
int sfs_loadvnode(struct sfs_fs *sfs, uint32_t ino, int forcetype,
struct sfs_vnode **ret);
struct sfs_vnode **ret);
int sfs_makeobj(struct sfs_fs *sfs, int type, struct sfs_vnode **ret);
int sfs_getroot(struct fs *fs, struct vnode **ret);
@@ -75,7 +72,6 @@ int sfs_readblock(struct sfs_fs *sfs, daddr_t block, void *data, size_t len);
int sfs_writeblock(struct sfs_fs *sfs, daddr_t block, void *data, size_t len);
int sfs_io(struct sfs_vnode *sv, struct uio *uio);
int sfs_metaio(struct sfs_vnode *sv, off_t pos, void *data, size_t len,
enum uio_rw rw);
enum uio_rw rw);
#endif /* _SFSPRIVATE_H_ */