#include <lunaix/spike.h>
#include <lunaix/bcache.h>
-#include <stdatomic.h>
-
#include <usr/lunaix/fstypes.h>
#define VFS_NAME_MAXLEN 128
struct filesystem* fs;
struct blkbuf_cache* blks;
struct hbucket* i_cache;
+ struct hbucket* d_cache;
+
void* data;
unsigned int ref_count;
size_t blksize;
struct v_dnode* dnode;
struct llist_header* f_list;
u32_t f_pos;
- atomic_ulong ref_count;
+ unsigned long ref_count;
void* data;
struct v_file_ops* ops; // for caching
};
struct llist_header aka_list;
struct llist_header children;
struct llist_header siblings;
+
struct v_superblock* super_block;
struct v_mount* mnt;
- atomic_ulong ref_count;
+
+ unsigned long ref_count;
void* data;
vfs_sb_alloc();
void
-vfs_sb_free(struct v_superblock* sb);
+vfs_sb_unref(struct v_superblock* sb);
void
vfs_sb_ref(struct v_superblock* sb);
#define vfs_assign_sb(sb_accessor, sb) \
({ \
- if (sb_accessor) { \
- vfs_sb_free(sb_accessor); \
+ if (likely(sb_accessor)) { \
+ vfs_sb_unref(sb_accessor); \
} \
vfs_sb_ref(((sb_accessor) = (sb))); \
})
vfs_assign_sb(dnode->super_block, sb);
}
+static inline void
+vfs_d_assign_vmnt(struct v_dnode* dnode, struct v_mount* vmnt)
+{
+ if (dnode->mnt) {
+ assert_msg(dnode->mnt->mnt_point != dnode,
+ "vmnt must be detached first");
+ }
+
+ dnode->mnt = vmnt;
+
+ if (likely(vmnt))
+ vfs_d_assign_sb(dnode, vmnt->super_block);
+}
+
static inline void
vfs_vmnt_assign_sb(struct v_mount* vmnt, struct v_superblock* sb)
{
}
struct v_dnode*
-vfs_d_alloc();
+vfs_d_alloc(struct v_dnode* parent, struct hstr* name);
void
vfs_d_free(struct v_dnode* dnode);
int
vfs_get_dtype(int itype);
-void
-vfs_ref_dnode(struct v_dnode* dnode);
-
-void
-vfs_ref_file(struct v_file* file);
-
-void
-vfs_unref_dnode(struct v_dnode* dnode);
-
int
vfs_get_path(struct v_dnode* dnode, char* buf, size_t size, int depth);
int
vfs_mount_root(const char* fs_name, struct device* device);
-struct v_mount*
-vfs_create_mount(struct v_mount* parent, struct v_dnode* mnt_point);
+static inline bool
+mnt_check_busy(struct v_mount* mnt)
+{
+ return mnt->busy_counter > 1;
+}
+
+static inline void
+vfs_ref_dnode(struct v_dnode* dnode)
+{
+ dnode->ref_count++;
+
+ if (likely(dnode->mnt)) {
+ mnt_mkbusy(dnode->mnt);
+ }
+}
+
+static inline void
+vfs_unref_dnode(struct v_dnode* dnode)
+{
+ dnode->ref_count--;
+
+ if (likely(dnode->mnt)) {
+ mnt_chillax(dnode->mnt);
+ }
+}
+
+static inline void
+vfs_ref_file(struct v_file* file)
+{
+ file->ref_count++;
+}
+
+static inline void
+vfs_unref_file(struct v_file* file)
+{
+ file->ref_count--;
+}
+
+static inline bool
+vfs_check_duped_file(struct v_file* file)
+{
+ return file->ref_count > 1;
+}
int
vfs_check_writable(struct v_dnode* dnode);
struct llist_header all_mnts = { .next = &all_mnts, .prev = &all_mnts };
-struct v_mount*
-vfs_create_mount(struct v_mount* parent, struct v_dnode* mnt_point)
+static void
+__vfs_attach_vmnt(struct v_dnode* mnt_point, struct v_mount* vmnt)
+{
+ vmnt->mnt_point = mnt_point;
+ vfs_d_assign_vmnt(mnt_point, vmnt);
+ vfs_ref_dnode(mnt_point);
+}
+
+static struct v_mount*
+__vfs_create_mount(struct v_mount* parent, struct v_superblock* mnt_sb)
{
struct v_mount* mnt = vzalloc(sizeof(struct v_mount));
if (!mnt) {
mutex_init(&mnt->lock);
mnt->parent = parent;
- mnt->mnt_point = mnt_point;
- vfs_vmnt_assign_sb(mnt, mnt_point->super_block);
+ vfs_vmnt_assign_sb(mnt, mnt_sb);
if (parent) {
mnt_mkbusy(parent);
llist_append(&parent->submnts, &mnt->sibmnts);
mutex_unlock(&mnt->parent->lock);
}
-
- atomic_fetch_add(&mnt_point->ref_count, 1);
return mnt;
}
-void
-__vfs_release_vmnt(struct v_mount* mnt)
+static void
+__vfs_detach_vmnt(struct v_mount* mnt)
{
assert(llist_empty(&mnt->submnts));
+ vfs_unref_dnode(mnt->mnt_point);
+ assert(!mnt->busy_counter);
+
if (mnt->parent) {
mnt_chillax(mnt->parent);
}
+ mnt->mnt_point->mnt = NULL;
+
llist_delete(&mnt->sibmnts);
llist_delete(&mnt->list);
- atomic_fetch_sub(&mnt->mnt_point->ref_count, 1);
vfree(mnt);
}
-int
+static inline void
+__detach_node_cache_ref(struct hbucket* bucket)
+{
+ if (!bucket->head) {
+ return;
+ }
+
+ bucket->head->pprev = 0;
+}
+
+static int
__vfs_do_unmount(struct v_mount* mnt)
{
int errno = 0;
// detached the inodes from cache, and let lru policy to recycle them
for (size_t i = 0; i < VFS_HASHTABLE_SIZE; i++) {
- struct hbucket* bucket = &sb->i_cache[i];
- if (!bucket->head) {
- continue;
- }
- bucket->head->pprev = 0;
+ __detach_node_cache_ref(&sb->i_cache[i]);
+ __detach_node_cache_ref(&sb->d_cache[i]);
}
- mnt->mnt_point->mnt = mnt->parent;
+ struct v_dnode *pos, *next;
+ llist_for_each(pos, next, &mnt->mnt_point->children, siblings)
+ {
+ vfs_d_free(pos);
+ }
- vfs_sb_free(sb);
- __vfs_release_vmnt(mnt);
+ __vfs_detach_vmnt(mnt);
+ vfs_d_assign_vmnt(mnt->mnt_point, mnt->parent);
return errno;
}
}
int errno = 0;
- char* dev_name = "sys";
- char* fsname = HSTR_VAL(fs->fs_name);
+ char* dev_name;
+ char* fsname;
+ struct v_mount *parent_mnt, *vmnt;
+ struct v_superblock *sb;
- struct v_mount* parent_mnt = mnt_point->mnt;
- struct v_superblock *sb = vfs_sb_alloc(),
- *old_sb = mnt_point->super_block;
+ fsname = HSTR_VAL(fs->fs_name);
+ parent_mnt = mnt_point->mnt;
+ sb = vfs_sb_alloc();
- if (device) {
- dev_name = device->name_val;
- }
+ dev_name = device ? device->name_val : "sys";
// prepare v_superblock for fs::mount invoke
sb->dev = device;
sb->fs = fs;
sb->root = mnt_point;
- vfs_d_assign_sb(mnt_point, sb);
+
+ vmnt = __vfs_create_mount(parent_mnt, sb);
- if (!(mnt_point->mnt = vfs_create_mount(parent_mnt, mnt_point))) {
+ if (!vmnt) {
errno = ENOMEM;
goto cleanup;
}
+ __vfs_attach_vmnt(mnt_point, vmnt);
+
mnt_point->mnt->flags = options;
if (!(errno = fs->mount(sb, mnt_point))) {
kprintf("mount: dev=%s, fs=%s, mode=%d",
goto cleanup;
}
- vfs_sb_free(old_sb);
return errno;
cleanup:
ERROR("failed mount: dev=%s, fs=%s, mode=%d, err=%d",
dev_name, fsname, options, errno);
- vfs_d_assign_sb(mnt_point, old_sb);
- vfs_sb_free(sb);
- __vfs_release_vmnt(mnt_point->mnt);
+ __vfs_detach_vmnt(mnt_point->mnt);
+ vfs_d_assign_vmnt(mnt_point, parent_mnt);
mnt_point->mnt = parent_mnt;
vfs_unmount_at(struct v_dnode* mnt_point)
{
int errno = 0;
- struct v_superblock* sb = mnt_point->super_block;
+ struct v_superblock* sb;
+
+ sb = mnt_point->super_block;
if (!sb) {
return EINVAL;
}
return EINVAL;
}
- if (mnt_point->mnt->busy_counter) {
+ if (mnt_check_busy(mnt_point->mnt)) {
return EBUSY;
}
- if (!(errno = __vfs_do_unmount(mnt_point->mnt))) {
- atomic_fetch_sub(&mnt_point->ref_count, 1);
- }
-
- return errno;
+ return __vfs_do_unmount(mnt_point->mnt);
}
int
static struct cake_pile* fd_pile;
struct v_dnode* vfs_sysroot;
-static struct hbucket* dnode_cache;
struct lru_zone *dnode_lru, *inode_lru;
superblock_pile =
cake_new_pile("sb_cache", sizeof(struct v_superblock), 1, 0);
- dnode_cache = vzalloc(VFS_HASHTABLE_SIZE * sizeof(struct hbucket));
-
dnode_lru = lru_new_zone("vfs_dnode", __vfs_try_evict_dnode);
inode_lru = lru_new_zone("vfs_inode", __vfs_try_evict_inode);
// 创建一个根dnode。
vfs_sysroot = vfs_d_alloc(NULL, &vfs_empty);
vfs_sysroot->parent = vfs_sysroot;
- atomic_fetch_add(&vfs_sysroot->ref_count, 1);
+
+ vfs_ref_dnode(vfs_sysroot);
}
static inline struct hbucket*
__dcache_hash(struct v_dnode* parent, u32_t* hash)
{
- u32_t _hash = *hash;
- // 确保低位更加随机
+ struct hbucket* d_cache;
+ u32_t _hash;
+
+ d_cache = parent->super_block->d_cache;
+ _hash = *hash;
_hash = _hash ^ (_hash >> VFS_HASHBITS);
- // 与parent的指针值做加法,来减小碰撞的可能性。
_hash += (u32_t)__ptr(parent);
+
*hash = _hash;
- return &dnode_cache[_hash & VFS_HASH_MASK];
+ return &d_cache[_hash & VFS_HASH_MASK];
}
static inline int
{
assert(parent);
- atomic_fetch_add(&dnode->ref_count, 1);
+ dnode->ref_count = 1;
dnode->parent = parent;
llist_append(&parent->children, &dnode->siblings);
hlist_delete(&dnode->hash_list);
dnode->parent = NULL;
- atomic_fetch_sub(&dnode->ref_count, 1);
+ dnode->ref_count = 0;
}
void
vfile->dnode = dnode;
vfile->inode = inode;
- vfile->ref_count = ATOMIC_VAR_INIT(1);
+ vfile->ref_count = 1;
vfile->ops = inode->default_fops;
- if (check_file_node(inode) && !inode->pg_cache) {
+ if (check_regfile_node(inode) && !inode->pg_cache) {
struct pcache* pcache = vzalloc(sizeof(struct pcache));
pcache_init(pcache);
pcache->master = inode;
if (errno) {
cake_release(file_pile, vfile);
} else {
- atomic_fetch_add(&dnode->ref_count, 1);
+ vfs_ref_dnode(dnode);
inode->open_count++;
- mnt_mkbusy(dnode->mnt);
*file = vfile;
}
mutex_unlock_for(&inode->lock, pid);
- if (file->ref_count > 1) {
- atomic_fetch_sub(&file->ref_count, 1);
+ if (vfs_check_duped_file(file)) {
+ vfs_unref_file(file);
return 0;
}
goto done;
}
- atomic_fetch_sub(&file->dnode->ref_count, 1);
- mnt_chillax(file->dnode->mnt);
+ vfs_unref_dnode(file->dnode);
cake_release(file_pile, file);
/*
struct v_superblock* sb = cake_grab(superblock_pile);
memset(sb, 0, sizeof(*sb));
llist_init_head(&sb->sb_list);
+
sb->i_cache = vzalloc(VFS_HASHTABLE_SIZE * sizeof(struct hbucket));
+ sb->d_cache = vzalloc(VFS_HASHTABLE_SIZE * sizeof(struct hbucket));
+
sb->ref_count = 1;
return sb;
}
}
void
-vfs_sb_free(struct v_superblock* sb)
+vfs_sb_unref(struct v_superblock* sb)
{
assert(sb->ref_count);
sb->ref_count--;
- if (sb->ref_count) {
+ if (likely(sb->ref_count)) {
return;
}
}
vfree(sb->i_cache);
+ vfree(sb->d_cache);
+
cake_release(superblock_pile, sb);
}
llist_init_head(&dnode->aka_list);
mutex_init(&dnode->lock);
- dnode->ref_count = ATOMIC_VAR_INIT(0);
dnode->name = HHSTR(vzalloc(VFS_NAME_MAXLEN), 0, 0);
hstrcpy(&dnode->name, name);
dnode->destruct(dnode);
}
- vfs_sb_free(dnode->super_block);
+ vfs_sb_unref(dnode->super_block);
vfree((void*)dnode->name.value);
cake_release(dnode_pile, dnode);
}
inode->destruct(inode);
}
- vfs_sb_free(inode->sb);
+ vfs_sb_unref(inode->sb);
hlist_delete(&inode->hash_list);
cake_release(inode_pile, inode);
}
memcpy(copied, old, sizeof(struct v_fd));
- atomic_fetch_add(&old->file->ref_count, 1);
+ vfs_ref_file(old->file);
*new = copied;
return DO_STATUS(errno);
}
-void
-vfs_ref_file(struct v_file* file)
-{
- atomic_fetch_add(&file->ref_count, 1);
-}
-
-void
-vfs_ref_dnode(struct v_dnode* dnode)
-{
- atomic_fetch_add(&dnode->ref_count, 1);
-
- if (dnode->mnt) {
- mnt_mkbusy(dnode->mnt);
- }
-}
-
-void
-vfs_unref_dnode(struct v_dnode* dnode)
-{
- atomic_fetch_sub(&dnode->ref_count, 1);
- if (dnode->mnt) {
- mnt_chillax(dnode->mnt);
- }
-}
-
int
vfs_do_chdir(struct proc_info* proc, struct v_dnode* dnode)
{
#include <lunaix/compiler.h>
/**
- * @brief Simple string hash function
+ * @brief Simple string hash function (sdbm)
*
- * ref: https://stackoverflow.com/a/7666577
+ * ref: http://www.cse.yorku.ca/~oz/hash.html
+ *
+ * sdbm has lower standard deviation in bucket distribution
+ * than djb2 (previously used) for low bucket size (16, 32).
*
* @param str
* @return unsigned int
if (!str)
return 0;
- u32_t hash = 5381;
+ u32_t hash = 0;
int c;
while ((c = *str++))
- hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
+ hash = (hash << 6) + (hash << 16) + c - hash;
return hash >> (HASH_SIZE_BITS - truncate_to);
}
\ No newline at end of file