clang-format
This commit is contained in:
@@ -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 */
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
Reference in New Issue
Block a user