#include <usr/lunaix/dirent_defs.h>
+#define INODE_ACCESSED 0
+#define INODE_MODIFY 1
+
static struct cake_pile* dnode_pile;
static struct cake_pile* inode_pile;
static struct cake_pile* file_pile;
static struct cake_pile* superblock_pile;
static struct cake_pile* fd_pile;
-struct v_dnode* vfs_sysroot;
-static struct hbucket* dnode_cache;
+struct v_dnode* vfs_sysroot = NULL;
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
return NULL;
}
+static void
+__vfs_touch_inode(struct v_inode* inode, const int type)
+{
+ if (type == INODE_MODIFY) {
+ inode->mtime = clock_unixtime();
+ }
+
+ else if (type == INODE_ACCESSED) {
+ inode->atime = clock_unixtime();
+ }
+
+ lru_use_one(inode_lru, &inode->lru);
+}
+
void
vfs_dcache_add(struct v_dnode* parent, struct v_dnode* dnode)
{
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
int
vfs_open(struct v_dnode* dnode, struct v_file** file)
{
- if (!dnode->inode || !dnode->inode->ops->open) {
+ struct v_inode* inode = dnode->inode;
+
+ if (!inode || !inode->ops->open) {
return ENOTSUP;
}
- struct v_inode* inode = dnode->inode;
-
lock_inode(inode);
struct v_file* vfile = cake_grab(file_pile);
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);
}
return errno;
}
+
+static bool
+__check_unlinkable(struct v_dnode* dnode)
+{
+ int acl;
+ bool wr_self, wr_parent;
+ struct v_dnode* parent;
+
+ parent = dnode->parent;
+ acl = dnode->inode->acl;
+
+ wr_self = check_allow_write(dnode->inode);
+ wr_parent = check_allow_write(parent->inode);
+
+ if (!fsacl_test(acl, svtx)) {
+ return wr_self;
+ }
+
+ if (current_euid() == dnode->inode->uid) {
+ return true;
+ }
+
+ return wr_self && wr_parent;
+}
+
int
vfs_do_open(const char* path, int options)
{
goto unlock;
}
+ if (!check_allow_read(inode)) {
+ errno = EPERM;
+ goto unlock;
+ }
+
struct dir_context dctx = (struct dir_context) {
.cb_data = dent,
.read_complete_callback = __vfs_readdir_callback
{
int errno = 0;
struct v_fd* fd_s;
+ struct v_inode* inode;
+
if ((errno = vfs_getfd(fd, &fd_s))) {
goto done;
}
goto done;
}
- lock_inode(file->inode);
+ if (!check_allow_read(file->inode)) {
+ errno = EPERM;
+ goto done;
+ }
+
+ inode = file->inode;
+ lock_inode(inode);
- file->inode->atime = clock_unixtime();
+ __vfs_touch_inode(inode, INODE_ACCESSED);
- if (check_seqdev_node(file->inode) || (fd_s->flags & FO_DIRECT)) {
- errno = file->ops->read(file->inode, buf, count, file->f_pos);
+ if (check_seqdev_node(inode) || (fd_s->flags & FO_DIRECT)) {
+ errno = file->ops->read(inode, buf, count, file->f_pos);
} else {
- errno = pcache_read(file->inode, buf, count, file->f_pos);
+ errno = pcache_read(inode, buf, count, file->f_pos);
}
if (errno > 0) {
file->f_pos += errno;
- unlock_inode(file->inode);
+ unlock_inode(inode);
return errno;
}
- unlock_inode(file->inode);
+ unlock_inode(inode);
done:
return DO_STATUS(errno);
inode = file->inode;
lock_inode(inode);
- inode->mtime = clock_unixtime();
+ __vfs_touch_inode(inode, INODE_MODIFY);
if ((fd_s->flags & O_APPEND)) {
file->f_pos = inode->fsize;
}
goto done;
}
+ if (!check_allow_read(inode)) {
+ errno = EPERM;
+ goto done;
+ }
+
lock_inode(inode);
int overflow = 0;
return ENOTSUP;
}
+ if (!check_allow_read(inode)) {
+ return EPERM;
+ }
+
lock_inode(inode);
int errno = inode->ops->read_symlink(inode, &link);
lock_dnode(dnode);
+ if (!__check_unlinkable(dnode)) {
+ errno = EPERM;
+ goto done;
+ }
+
if ((errno = vfs_check_writable(dnode))) {
goto done;
}
return DO_STATUS(errno);
}
-int
+static int
__vfs_do_unlink(struct v_dnode* dnode)
{
int errno;
return EBUSY;
}
+ if (!__check_unlinkable(dnode)) {
+ return EPERM;
+ }
+
if ((errno = vfs_check_writable(dnode))) {
return errno;
}
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)
+static int
+vfs_do_chdir_nolock(struct proc_info* proc, struct v_dnode* dnode)
{
- atomic_fetch_add(&dnode->ref_count, 1);
-
- if (dnode->mnt) {
- mnt_mkbusy(dnode->mnt);
+ if (!check_directory_node(dnode->inode)) {
+ return ENOTDIR;
}
-}
-void
-vfs_unref_dnode(struct v_dnode* dnode)
-{
- atomic_fetch_sub(&dnode->ref_count, 1);
- if (dnode->mnt) {
- mnt_chillax(dnode->mnt);
+ if (proc->cwd) {
+ vfs_unref_dnode(proc->cwd);
}
+
+ vfs_ref_dnode(dnode);
+ proc->cwd = dnode;
+
+ return 0;
}
-int
+static int
vfs_do_chdir(struct proc_info* proc, struct v_dnode* dnode)
{
int errno = 0;
lock_dnode(dnode);
- if (!check_directory_node(dnode->inode)) {
- errno = ENOTDIR;
- goto done;
- }
-
- if (proc->cwd) {
- vfs_unref_dnode(proc->cwd);
- }
-
- vfs_ref_dnode(dnode);
- proc->cwd = dnode;
+ errno = vfs_do_chdir_nolock(proc, dnode);
unlock_dnode(dnode);
-done:
return errno;
}
return DO_STATUS(errno);
}
+
+__DEFINE_LXSYSCALL1(int, chroot, const char*, path)
+{
+ int errno;
+ struct v_dnode* dnode;
+ if ((errno = vfs_walk_proc(path, &dnode, NULL, 0))) {
+ return errno;
+ }
+
+ lock_dnode(dnode);
+
+ errno = vfs_do_chdir_nolock(__current, dnode);
+ if (errno) {
+ unlock_dnode(dnode);
+ goto done;
+ }
+
+ __current->root = dnode;
+
+ unlock_dnode(dnode);
+
+done:
+ return DO_STATUS(errno);
+}
+
__DEFINE_LXSYSCALL2(char*, getcwd, char*, buf, size_t, size)
{
int errno = 0;
struct v_inode* vino = fds->file->inode;
struct device* fdev = vino->sb->dev;
- *stat = (struct file_stat){.st_ino = vino->id,
- .st_blocks = vino->lb_usage,
- .st_size = vino->fsize,
- .mode = vino->itype,
- .st_ioblksize = PAGE_SIZE,
- .st_blksize = vino->sb->blksize};
+ stat->st_ino = vino->id;
+ stat->st_blocks = vino->lb_usage;
+ stat->st_size = vino->fsize;
+ stat->st_blksize = vino->sb->blksize;
+ stat->st_nlink = vino->link_count;
+ stat->st_uid = vino->uid;
+ stat->st_gid = vino->gid;
+
+ stat->st_ctim = vino->ctime;
+ stat->st_atim = vino->atime;
+ stat->st_mtim = vino->mtime;
+
+ stat->st_mode = (vino->itype << 16) | vino->acl;
+
+ stat->st_ioblksize = PAGE_SIZE;
if (check_device_node(vino)) {
struct device* rdev = resolve_device(vino->data);
.index = dev_uid(fdev) };
}
+done:
+ return DO_STATUS(errno);
+}
+
+__DEFINE_LXSYSCALL4(int, fchmodat, int, fd,
+ const char*, path, int, mode, int, flags)
+{
+ int errno;
+ struct v_dnode *dnode;
+ struct v_inode* inode;
+
+ errno = vfs_walkat(fd, path, flags, &dnode);
+ if (errno) {
+ goto done;
+ }
+
+ errno = vfs_check_writable(dnode);
+ if (errno) {
+ return errno;
+ }
+
+ inode = dnode->inode;
+ lock_inode(inode);
+
+ if (!current_is_root()) {
+ mode = mode & FSACL_RWXMASK;
+ }
+
+ inode->acl = mode;
+ __vfs_touch_inode(inode, INODE_MODIFY);
+
+ unlock_inode(inode);
+
+done:
+ return DO_STATUS(errno);
+}
+
+__DEFINE_LXSYSCALL5(int, fchownat, int, fd,
+ const char*, path, uid_t, uid, gid_t, gid, int, flags)
+{
+ int errno;
+ struct v_dnode *dnode;
+ struct v_inode *inode;
+
+ errno = vfs_walkat(fd, path, flags, &dnode);
+ if (errno) {
+ goto done;
+ }
+
+ errno = vfs_check_writable(dnode);
+ if (errno) {
+ return errno;
+ }
+
+ inode = dnode->inode;
+ lock_inode(inode);
+
+ inode->uid = uid;
+ inode->gid = gid;
+ __vfs_touch_inode(inode, INODE_MODIFY);
+
+ unlock_inode(inode);
+
+done:
+ return DO_STATUS(errno);
+}
+
+__DEFINE_LXSYSCALL4(int, faccessat, int, fd,
+ const char*, path, int, amode, int, flags)
+{
+ int errno, acl;
+ struct v_dnode *dnode;
+ struct v_inode *inode;
+ struct user_scope* uscope;
+
+ uid_t tuid;
+ gid_t tgid;
+
+ errno = vfs_walkat(fd, path, flags, &dnode);
+ if (errno) {
+ goto done;
+ }
+
+ if ((flags & AT_EACCESS)) {
+ tuid = current_euid();
+ tgid = current_egid();
+ }
+ else {
+ uscope = current_user_scope();
+ tuid = uscope->ruid;
+ tgid = uscope->rgid;
+ }
+
+ inode = dnode->inode;
+
+ acl = inode->acl;
+ acl &= amode;
+ acl &= check_acl_between(inode->uid, inode->gid, tuid, tgid);
+ if (!acl) {
+ errno = EACCESS;
+ }
+
done:
return DO_STATUS(errno);
}
\ No newline at end of file