Fix modification infomations. Reconstruct fs directory structure.

This commit is contained in:
TXuian
2024-02-02 18:21:04 +08:00
parent 6942ad6d1d
commit 7069f54ed9
60 changed files with 172144 additions and 65 deletions
@@ -0,0 +1,20 @@
toolchain ?= arm-none-eabi-
cc = ${toolchain}gcc
ld = ${toolchain}g++
objdump = ${toolchain}objdump
user_ldflags = -N -Ttext 0
cflags = -march=armv7-a -mtune=cortex-a9 -nostdlib -nodefaultlibs -mfloat-abi=soft -fno-pic -static -fno-builtin -fno-strict-aliasing -Wall -ggdb -Wno-unused -Werror -fno-omit-frame-pointer -fno-stack-protector -fno-pie -no-pie
c_useropts = -O0
INC_DIR = -I$(KERNEL_ROOT)/services/fs/libfs \
-I$(KERNEL_ROOT)/services/fs/fs_server/include \
-I$(KERNEL_ROOT)/services/lib/ipc \
-I$(KERNEL_ROOT)/services/boards/imx6q-sabrelite
fs_server: fs_server.o fs.o block_io.o
@mv $^ ../../boards/imx6q-sabrelite
%.o: %.c
@echo "cc $^"
@${cc} ${cflags} ${c_useropts} ${INC_DIR} -o $@ -c $^
@@ -0,0 +1,88 @@
/*
* Copyright (c) 2020 AIIT XUOS Lab
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
#include <string.h>
#include "block_io.h"
#include "libserial.h"
#include "fs.h"
#include "list.h"
static void Error(char* s)
{
printf("Error: %s\n", s);
for (;;)
;
}
// Locate the data block using block_num
uint8_t* BlockRead(int block_num)
{
uint8_t* data = (uint8_t*)MemFsRange.memfs_start + block_num * BLOCK_SIZE;
return data;
}
// Zero a block.
static void BlockClear(int block_num)
{
uint8_t* data = BlockRead(block_num);
memset(data, 0, BLOCK_SIZE);
}
// Allocate a zeroed disk block.
uint32_t BlockAlloc()
{
int bit_index, block_index, bit_mark;
struct SuperBlock sb;
ReadSuperBlock(&sb);
for (bit_index = 0; bit_index < sb.size; bit_index += BITMAP_SIZE) {
uint8_t* data = BlockRead(BLOCK_BIT_INDEX(bit_index, sb.ninodes));
for (block_index = 0; block_index < BITMAP_SIZE && bit_index + block_index < sb.size; block_index++) {
bit_mark = 1 << (block_index % 8);
if ((data[block_index / 8] & bit_mark) == 0) {
data[block_index / 8] |= bit_mark;
BlockClear(bit_index + block_index);
return bit_index + block_index;
}
}
}
Error("BlockAlloc: out of blocks");
return 0;
}
// Free a disk block.
void BlockFree(int block_num)
{
struct SuperBlock sb;
int block_index, bit_mark;
ReadSuperBlock(&sb);
uint8_t* data = BlockRead(BLOCK_BIT_INDEX(block_num, sb.ninodes));
block_index = block_num % BITMAP_SIZE;
bit_mark = 1 << (block_index % 8);
if ((data[block_index / 8] & bit_mark) == 0) {
Error("freeing free block");
}
data[block_index / 8] &= ~bit_mark;
}
@@ -0,0 +1,474 @@
// Copyright (c) 2006-2018 Frans Kaashoek, Robert Morris, Russ Cox, Massachusetts Institute of Technology
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
/**
* @file fs.c
* @brief support read and write the fs.img
* @version 1.0
* @author AIIT XUOS Lab
* @date 2024-01-25
*/
/*************************************************
File name: fs.c
Description: support read and write the fs.img
Others: take ARM_XV6 kernel/fs.c for references
https://github.com/KingofHamyang/ARM_xv6
History:
1. Date: 2024-01-25
Author: AIIT XUOS Lab
Modification:
1. support inode create and delete
3. remove inode lock and unlock
4. remove inode cache
5. rename function names(DirInodeAddEntry,DirInodeLookup, InodeAlloc, InodeFree, PathElementExtract, InodeBlockMapping, Seek, InodeSeek, InodeParentSeek, InodeRead, InodeWrite) to fit XIZI_AIoT use sceneries
*************************************************/
#include <string.h>
#include "block_io.h"
#include "fs.h"
#include "libserial.h"
static void Error(char* s)
{
printf("Error: %s\n", s);
for (;;)
;
}
#define min(a, b) ((a) < (b) ? (a) : (b))
static int DirInodeAddEntry(struct Inode* dp, char* name, uint32_t inum);
static struct Inode* DirInodeLookup(struct Inode* dp, char* name, uint32_t* poff);
static struct Inode* InodeAlloc(short type);
static int InodeFree(struct Inode* ip);
static int InodeFreeRecursive(struct Inode* dp);
static char* PathElementExtract(char* path, char* name);
static uint32_t InodeBlockMapping(struct Inode* ip, uint32_t block_num);
#define MAX_SUPPORT_FD 1024
static struct FileDescriptor fd_table[MAX_SUPPORT_FD];
struct MemFsRange MemFsRange;
/// @brief Using syscall to get fs.img real location in the memory
void MemFsInit(uintptr_t _binary_fs_img_start, uint32_t fs_img_len)
{
MemFsRange.memfs_start = _binary_fs_img_start;
MemFsRange.memfs_nr_blocks = fs_img_len / BLOCK_SIZE;
}
/// @brief Read the super block.
void ReadSuperBlock(struct SuperBlock* sb)
{
uint8_t* data = BlockRead(ROOT_INUM);
memmove(sb, data, sizeof(*sb));
}
/// @brief Get a existed Inode by inum
struct Inode* InodeGet(uint32_t inum)
{
struct Inode* ip;
uint8_t* data = BlockRead(BLOCK_INDEX(inum));
ip = (struct Inode*)data + INODE_INDEX(inum);
return ip;
}
/// @brief Alloc a new Inode using type
static struct Inode* InodeAlloc(short type)
{
int inum;
struct Inode* ip;
struct SuperBlock sb;
ReadSuperBlock(&sb);
for (inum = 1; inum < sb.ninodes; inum++) {
uint8_t* data = BlockRead(BLOCK_INDEX(inum));
ip = (struct Inode*)data + INODE_INDEX(inum);
if (ip->type == 0) {
memset(ip, 0, sizeof(*ip));
ip->inum = inum;
ip->type = type;
ip->nlink = 1;
ip->size = 0;
return ip;
}
}
Error("InodeAlloc: no inodes");
return NULL;
}
/// @brief Free the existed Inode
static int InodeFree(struct Inode* ip)
{
uint8_t* data = BlockRead(BLOCK_INDEX(ip->inum));
struct Inode* dip = (struct Inode*)data + INODE_INDEX(ip->inum);
dip->type = 0;
return 0;
}
/// @brief Delete the dir and all files or dirs under the dir.
static int InodeFreeRecursive(struct Inode* dp)
{
uint32_t off;
struct Inode* ip;
struct DirectEntry de;
for (off = 0; off < dp->size; off += sizeof(de)) {
if (InodeRead(dp, (char*)&de, off, sizeof(de)) != sizeof(de)) {
Error("inode_delete_dir failed: read directory entry failed");
}
// unlink dir
if (de.inum == 0 || strcmp(de.name, "..") == 0 || strcmp(de.name, ".") == 0) {
continue;
}
ip = InodeGet(de.inum);
if (ip->type == T_DIR) {
if (InodeFreeRecursive(ip) < 0) {
return -1;
}
} else if (ip->type == T_FILE) {
InodeFree(ip);
}
// delete the dir entry
de.inum = 0;
if (InodeWrite(dp, (char*)&de, off, sizeof(de)) != sizeof(de)) {
printf("InodeDelete failed: clear directory entry failed");
return -1;
}
}
return 0;
}
/// @brief Delete a file Inode or a dir Inode
int InodeDelete(struct Inode* dp, char* name)
{
uint32_t off;
struct Inode* ip;
struct DirectEntry de;
if ((ip = DirInodeLookup(dp, name, &off)) == 0) {
Error("Inode delete failed, file not exsit");
return -1;
}
InodeFree(ip);
if (ip->type == T_DIR) {
// recursive free alloced Inode
if (InodeFreeRecursive(ip) < 0) {
return -1;
}
}
// delete the dir entry
de.inum = 0;
if (InodeWrite(dp, (char*)&de, off, sizeof(de)) != sizeof(de)) {
printf("InodeDelete failed: clear directory entry failed");
return -1;
}
return 0;
}
/// @brief Create a new Inode under the parent Inode
struct Inode* InodeCreate(struct Inode* dp, char* name, short type, short major, short minor)
{
uint32_t off;
struct Inode* ip;
if ((ip = DirInodeLookup(dp, name, &off)) != 0) {
if (type == T_FILE && ip->type == T_FILE) {
return ip;
}
return 0;
}
if ((ip = InodeAlloc(type)) == 0) {
Error("InodeCreate: create Inode failed\n");
}
if (type == T_DIR) {
dp->nlink++;
if (DirInodeAddEntry(ip, ".", ip->inum) < 0 || DirInodeAddEntry(ip, "..", dp->inum) < 0) {
Error("InodeCreate: create dots");
}
}
if (DirInodeAddEntry(dp, name, ip->inum) < 0) {
Error("InodeCreate: DirInodeAddEntry failed");
}
return ip;
}
/// @brief Mapping the direct block addrs or indirect block addrs of the Inode using the block_num
static uint32_t InodeBlockMapping(struct Inode* ip, uint32_t block_num)
{
uint32_t addr;
// block is in range of direct mapping
if (block_num < NR_DIRECT_BLOCKS) {
if ((addr = ip->addrs[block_num]) == 0) {
ip->addrs[block_num] = addr = BlockAlloc();
}
return addr;
}
// alloc a new indirect indexing block
block_num -= NR_DIRECT_BLOCKS;
int indirect_block_id = block_num / MAX_INDIRECT_BLOCKS;
if (indirect_block_id < NR_INDIRECT_BLOCKS) {
if ((addr = ip->addrs[NR_DIRECT_BLOCKS + indirect_block_id]) == 0) {
ip->addrs[NR_DIRECT_BLOCKS + indirect_block_id] = addr = BlockAlloc();
}
block_num -= indirect_block_id * MAX_INDIRECT_BLOCKS;
} else {
Error("InodeBlockMapping: out of range");
return 0;
}
// alloc a new indirect block
uint32_t* indirect_block = (uint32_t*)BlockRead(addr);
if ((addr = indirect_block[block_num]) == 0) {
indirect_block[block_num] = addr = BlockAlloc();
}
return addr;
}
/// @brief Look up the directory Inode for searching the target Inode
static struct Inode* DirInodeLookup(struct Inode* dp, char* name, uint32_t* poff)
{
uint32_t off, inum;
struct DirectEntry de;
if (dp->type != T_DIR) {
Error("DirInodeLookup not DIR");
}
for (off = 0; off < dp->size; off += sizeof(de)) {
if (InodeRead(dp, (char*)&de, off, sizeof(de)) != sizeof(de)) {
Error("DirInodeAddEntry read");
}
if (de.inum == 0) {
continue;
}
if (strncmp((const char*)name, (const char*)de.name, DIR_NAME_SIZE) == 0) {
if (poff) {
*poff = off;
}
inum = de.inum;
return InodeGet(inum);
}
}
return 0;
}
/// @brief Add a new directory entry for dir Inode
static int DirInodeAddEntry(struct Inode* dp, char* name, uint32_t inum)
{
int off;
struct DirectEntry de;
struct Inode* ip;
// Check that direct entry is existed.
if ((ip = DirInodeLookup(dp, name, 0)) != 0) {
return -1;
}
// Look for an empty dir entry.
for (off = 0; off < dp->size; off += sizeof(de)) {
if (InodeRead(dp, (char*)&de, off, sizeof(de)) != sizeof(de)) {
Error("DirInodeAddEntry: read failed");
}
if (de.inum == 0) {
break;
}
}
// build a new direct entry.
strncpy(de.name, name, DIR_NAME_SIZE);
de.inum = inum;
if (InodeWrite(dp, (char*)&de, off, sizeof(de)) != sizeof(de)) {
Error("DirInodeAddEntry: write failed");
}
return 0;
}
static struct Inode* Seek(struct Inode* ip, char* path, int nameiparent, char* name)
{
if (ip->size == 0) {
Error("Inode is not sync\n");
}
struct Inode* next;
while ((path = PathElementExtract(path, name)) != 0) {
if (ip->type != T_DIR) {
return NULL;
}
if (nameiparent && *path == '\0') {
return ip;
}
if ((next = DirInodeLookup(ip, name, 0)) == 0) {
return NULL;
}
ip = next;
}
if (nameiparent) {
return NULL;
}
return ip;
}
/// @brief Find target Inode from source Inode
struct Inode* InodeSeek(struct Inode* source, char* path)
{
char name[DIR_NAME_SIZE] = { 0 };
return Seek(source, path, 0, name);
}
/// @brief Find target parent Inode from source Inode
struct Inode* InodeParentSeek(struct Inode* source, char* path, char* name)
{
return Seek(source, path, 1, name);
}
/// @brief Read data from the Inode to the dst buffer.
int InodeRead(struct Inode* ip, char* dst, int off, int n)
{
uint32_t tot, m;
if (off > ip->size || off + n < off) {
return -1;
}
if (off + n > ip->size) {
n = ip->size - off;
}
for (tot = 0; tot < n; tot += m, off += m, dst += m) {
uint8_t* data = BlockRead(InodeBlockMapping(ip, off / BLOCK_SIZE));
m = min(n - tot, BLOCK_SIZE - off % BLOCK_SIZE);
memmove(dst, data + off % BLOCK_SIZE, m);
}
return n;
}
/// @brief Write data from src buffer to the Inode, then increase the Inode size if neccessary.
int InodeWrite(struct Inode* ip, char* src, uint32_t off, uint32_t n)
{
uint32_t tot, m;
if (off > ip->size || off + n < off) {
return -1;
}
if (off + n > MAX_FILE_SIZE * BLOCK_SIZE) {
return -1;
}
for (tot = 0; tot < n; tot += m, off += m, src += m) {
uint8_t* data = BlockRead(InodeBlockMapping(ip, off / BLOCK_SIZE));
m = min(n - tot, BLOCK_SIZE - off % BLOCK_SIZE);
memmove(data + off % BLOCK_SIZE, src, m);
}
if (n > 0 && off > ip->size) {
ip->size = off;
}
return n;
}
// Paths process
static char* PathElementExtract(char* path, char* name)
{
// Skip leading slashes
while (*path == '/')
path++;
// Check for end of path
if (*path == 0)
return NULL;
// Extract element
char* start = path;
while (*path != '/' && *path != 0)
path++;
// Calculate length and copy to 'name'
int len = path - start;
if (len >= DIR_NAME_SIZE)
len = DIR_NAME_SIZE - 1;
strncpy(name, start, len);
name[len] = 0;
// Skip trailing slashes
while (*path == '/')
path++;
return path;
}
struct FileDescriptor* GetFileDescriptor(int fd)
{
if (fd < 0 || fd > MAX_SUPPORT_FD) {
printf("fd invlid.\n");
return NULL;
}
return &fd_table[fd];
}
void FreeFileDescriptor(int fd)
{
if (fd < 0 || fd > MAX_SUPPORT_FD) {
printf("fd invlid.\n");
return;
}
fd_table[fd].data = 0;
return;
}
int AllocFileDescriptor(void)
{
int free_idx = -1;
for (int i = 0; i < MAX_SUPPORT_FD; i++) {
// found free fd
if (free_idx == -1 && fd_table[i].data == 0) {
free_idx = i;
}
}
if (free_idx == -1) {
return -1;
}
return free_idx;
}
@@ -0,0 +1,358 @@
/*
* Copyright (c) 2020 AIIT XUOS Lab
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
#include <stdbool.h>
#include <string.h>
#include "block_io.h"
#include "fs.h"
#include "libfs_to_client.h"
#include "libserial.h"
#include "usyscall.h"
struct CwdPair {
int session_id;
struct Inode* Inode;
};
#define MAX_SUPPORT_SESSION 1024
static struct CwdPair session_cwd[MAX_SUPPORT_SESSION];
static struct CwdPair* get_session_cwd(void)
{
int free_idx = -1;
for (int i = 0; i < MAX_SUPPORT_SESSION; i++) {
// found session cwd
if (session_cwd[i].session_id == cur_session_id()) {
return &session_cwd[i];
}
if (free_idx == -1 && session_cwd[i].session_id == 0) {
free_idx = i;
}
}
// new a cwd pair for session
if (free_idx == -1) {
printf("Connect Session reaches max value.\n");
return NULL;
}
session_cwd[free_idx].session_id = cur_session_id();
session_cwd[free_idx].Inode = InodeGet(ROOT_INUM);
return &session_cwd[free_idx];
}
int IPC_DO_SERVE_FUNC(Ipc_ls)(char* path)
{
struct Inode *dp, *ip;
if (*path == '/') {
dp = InodeGet(ROOT_INUM);
} else {
struct CwdPair* cwd = get_session_cwd();
if (!cwd) {
printf("ls:find current work dir failed\n");
return -1;
}
dp = cwd->Inode;
}
if (!(ip = InodeSeek(dp, path))) {
printf("ls:find target Inode failed\n");
return -1;
}
if (ip->type != T_DIR) {
printf("ls:not a dir\n");
return -1;
}
uint32_t off;
struct DirectEntry de;
for (off = 0; off < ip->size; off += sizeof(de)) {
if (InodeRead(ip, (char*)&de, off, sizeof(de)) != sizeof(de)) {
printf("ls:read dir entry failed\n");
return -1;
}
if (de.inum == 0) {
continue;
}
printf("%s\n", de.name);
}
return 0;
}
int IPC_DO_SERVE_FUNC(Ipc_cd)(char* path)
{
struct CwdPair* cwd;
struct Inode *dp, *ip;
cwd = get_session_cwd();
if (!cwd) {
printf("cd:find current work dir failed\n");
return -1;
}
if (*path == '/') {
dp = InodeGet(ROOT_INUM);
} else {
dp = cwd->Inode;
}
if (!(ip = InodeSeek(dp, path))) {
/// @todo Is need to create the Inode when the dir is node existed?
printf("cd:find target Inode failed\n");
return -1;
}
if (ip->type != T_DIR) {
printf("cd:not a dir\n");
return -1;
}
cwd->Inode = ip;
return 0;
}
int IPC_DO_SERVE_FUNC(Ipc_mkdir)(char* path)
{
// printf("Create a new directory: %s\n", path);
struct Inode *dp, *ip;
if (*path == '/') {
dp = InodeGet(ROOT_INUM);
} else {
struct CwdPair* cwd = get_session_cwd();
if (!cwd) {
printf("find current work dir failed\n");
return -1;
}
dp = cwd->Inode;
}
if ((ip = InodeSeek(dp, path)) != NULL) {
/// @todo Is need to return target Inode?
printf("target Inode existed\n");
return -1;
}
char name[DIR_NAME_SIZE] = { 0 };
if (!(ip = InodeParentSeek(dp, path, name))) {
/// @todo Is need to return target Inode?
printf("target parent Inode is not existed\n");
return -1;
}
if (InodeCreate(ip, name, T_DIR, 0, 0) == 0) {
printf("create target Inode %s failed\n", path);
return -1;
}
return 0;
}
int IPC_DO_SERVE_FUNC(Ipc_delete)(char* path)
{
struct Inode *dp, *ip;
if (*path == '/') {
dp = InodeGet(ROOT_INUM);
} else {
struct CwdPair* cwd = get_session_cwd();
if (!cwd) {
printf("delete:find current work dir failed\n");
return -1;
}
dp = cwd->Inode;
}
char name[DIR_NAME_SIZE] = { 0 };
if (!(ip = InodeParentSeek(dp, path, name))) {
printf("delete:target file parent not existed\n");
return -1;
}
if (InodeDelete(ip, name) < 0) {
printf("delete:target file not existed\n");
return -1;
}
return 0;
}
/// @todo Support malloc for user
int IPC_DO_SERVE_FUNC(Ipc_cat)(char* path)
{
static char buffer[BLOCK_SIZE + 1] = { 0 };
buffer[BLOCK_SIZE] = '\0';
struct Inode *dp, *ip;
if (*path == '/') {
dp = InodeGet(ROOT_INUM);
} else {
struct CwdPair* cwd = get_session_cwd();
if (!cwd) {
printf("delete:find current work dir failed\n");
return -1;
}
dp = cwd->Inode;
}
if (!(ip = InodeSeek(dp, path))) {
printf("delete:target file not existed\n");
return -1;
}
if (ip->type != T_FILE) {
printf("cat: %s Is not a file\n", path);
return -1;
}
uint32_t off;
for (off = 0; off < ip->size; off += BLOCK_SIZE) {
if (InodeRead(ip, buffer, off, BLOCK_SIZE) < 0) {
printf("cat: read file data failed\n");
break;
}
printf("%s", buffer);
}
return 0;
}
int IPC_DO_SERVE_FUNC(Ipc_open)(char* path)
{
// printf("Ipc_open: %s\n", path);
int fd;
struct FileDescriptor* fdp;
fd = AllocFileDescriptor();
if (fd < 0) {
printf("open: alloc a new fd failed\n");
return -1;
}
fdp = GetFileDescriptor(fd);
struct Inode *dp, *ip;
if (*path == '/') {
dp = InodeGet(ROOT_INUM);
} else {
struct CwdPair* cwd = get_session_cwd();
if (!cwd) {
printf("ls:find current work dir failed\n");
return -1;
}
dp = cwd->Inode;
}
if ((ip = InodeSeek(dp, path)) == NULL) {
printf("open: find target Inode failed, path is %s\n", path);
return -1;
}
/// @todo record absolute path
strncpy(fdp->path, path, strlen(path) + 1);
ip->nlink++;
fdp->data = ip;
return fd;
}
int IPC_DO_SERVE_FUNC(Ipc_close)(int* fd)
{
struct FileDescriptor* fdp = GetFileDescriptor(*fd);
if (!fdp) {
printf("read: fd invalid\n");
return -1;
}
struct Inode* ip = fdp->data;
ip->nlink--;
FreeFileDescriptor(*fd);
return 0;
}
int IPC_DO_SERVE_FUNC(Ipc_read)(int* fd, char* dst, int* offset, int* len)
{
// printf("Ipc_read, fd is %d, dst: %x, offset: %d, len: %d\n", *fd, dst, *offset, *len);
struct FileDescriptor* fdp = GetFileDescriptor(*fd);
if (!fdp) {
printf("read: fd invalid\n");
return -1;
}
struct Inode* ip = fdp->data;
if (ip->type != T_FILE) {
printf("read: %s Is not a file\n", fdp->path);
return -1;
}
int cur_read_len = InodeRead(ip, dst, *offset, *len);
return *len;
}
int IPC_DO_SERVE_FUNC(Ipc_write)(int* fd, char* src, int* offset, int* len)
{
// printf("Ipc_write, fd is %d\n", *fd);
struct FileDescriptor* fdp = GetFileDescriptor(*fd);
if (!fdp) {
printf("read: fd invalid\n");
return -1;
}
struct Inode* ip = fdp->data;
if (ip->type != T_FILE) {
printf("read: %s Is not a file\n", fdp->path);
return -1;
}
int cur_write_len = InodeWrite(ip, src, *offset, *len);
return cur_write_len;
}
IPC_SERVER_INTERFACE(Ipc_ls, 1);
IPC_SERVER_INTERFACE(Ipc_cd, 1);
IPC_SERVER_INTERFACE(Ipc_mkdir, 1);
IPC_SERVER_INTERFACE(Ipc_delete, 1);
IPC_SERVER_INTERFACE(Ipc_cat, 1);
IPC_SERVER_INTERFACE(Ipc_open, 1);
IPC_SERVER_INTERFACE(Ipc_close, 1);
IPC_SERVER_INTERFACE(Ipc_read, 4);
IPC_SERVER_INTERFACE(Ipc_write, 4);
IPC_SERVER_REGISTER_INTERFACES(IpcFsServer, 9,
Ipc_ls,
Ipc_cd,
Ipc_mkdir,
Ipc_delete,
Ipc_cat,
Ipc_open,
Ipc_close,
Ipc_read,
Ipc_write);
int main(int argc, char* argv[])
{
sys_state_info info;
get_memblock_info(&info);
int len = info.memblock_info.memblock_end - info.memblock_info.memblock_start;
mmap(FS_IMG_ADDR, info.memblock_info.memblock_start, len, false);
MemFsInit((uintptr_t)FS_IMG_ADDR, (uint32_t)len);
if (register_server("MemFS") < 0) {
printf("register server name: %s failed.\n", "SimpleServer");
exit();
}
ipc_server_loop(&IpcFsServer);
// never reached
exit();
}
@@ -0,0 +1,42 @@
/*
* Copyright (c) 2020 AIIT XUOS Lab
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
#pragma once
#include <stdint.h>
#include "fs.h"
// Block size
#define BLOCK_SIZE 512
// bits size
#define BITS 8
// Bitmap size of one block
#define BITMAP_SIZE (BLOCK_SIZE * BITS)
// Inode size of one block
#define INODE_SIZE (BLOCK_SIZE / sizeof(struct Inode))
// Caculate block bit index
#define BLOCK_BIT_INDEX(b, ninodes) ((b / BITMAP_SIZE) + (ninodes / INODE_SIZE) + 3)
// Caculate block index by inode number
#define BLOCK_INDEX(inum) ((inum / INODE_SIZE) + 2)
// Caculate inode index in the block
#define INODE_INDEX(inum) (inum % INODE_SIZE)
uint8_t* BlockRead(int block_num);
void BlockFree(int block_num);
uint32_t BlockAlloc();
@@ -0,0 +1,109 @@
/*
* Copyright (c) 2020 AIIT XUOS Lab
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
#pragma once
#include <stdint.h>
#include "block_io.h"
// memory file system memlayout.
// [ block 0 ] [ block 1 ] [block 2] [...] [ block 28 ] [ ... ]
// [ unused ] [super block] [Inode bit map] [block bit map] [data blocks]
#define NR_DIRECT_BLOCKS 5 // direct block number
#define NR_INDIRECT_BLOCKS 8 // indirect block number
#define ROOT_INUM 1 // root inode number
#define MAX_INDIRECT_BLOCKS (BLOCK_SIZE / sizeof(uint32_t)) // Mmaximum number of indirect blocks mapped per block
#define MAX_FILE_SIZE (NR_DIRECT_BLOCKS + (NR_INDIRECT_BLOCKS * MAX_INDIRECT_BLOCKS)) // maximum size of a file
// memory fs range
struct MemFsRange {
uintptr_t memfs_start;
uint32_t memfs_nr_blocks;
};
// current state of the Inode
enum INODE_STATE {
I_RESERVED = 0,
I_BUSY,
I_VALID
};
// memfs file type
enum FILE_TYPE {
T_RESERVED = 0,
T_DIR, // Directory
T_FILE, // File
T_DEV, // Device
};
// File system super block
struct SuperBlock {
uint32_t size; // Number of total blocks of file system image
uint32_t nblocks; // Number of data blocks
uint32_t ninodes; // Number of inodes.
};
// state of the Inode
struct State {
short type; // Type of file
int dev; // File system's disk device
uint32_t ino; // Inode number
short nlink; // Number of links to file
uint32_t size; // Size of file in bytes
};
// Inode structure
struct Inode {
uint32_t inum; // Inode number
short type; // File type
short nlink; // Number of links to Inode in file system
uint32_t size; // Size of file (bytes)
uint32_t addrs[NR_DIRECT_BLOCKS + NR_INDIRECT_BLOCKS]; // Data block addresses
};
// directory entry
#define DIR_NAME_SIZE 14
struct DirectEntry {
uint16_t inum;
char name[DIR_NAME_SIZE];
};
// file descriptor definition
#define MAX_PATH_LEN 128
struct FileDescriptor {
char path[MAX_PATH_LEN];
void* data;
struct State st;
};
// range of memory fs
extern struct MemFsRange MemFsRange;
void MemFsInit(uintptr_t _binary_fs_img_start, uint32_t fs_img_len);
void ReadSuperBlock(struct SuperBlock*);
// fs Inode ops
struct Inode* InodeGet(uint32_t inum);
struct Inode* InodeCreate(struct Inode*, char*, short, short, short);
int InodeDelete(struct Inode*, char*);
int InodeRead(struct Inode*, char*, int, int);
int InodeWrite(struct Inode*, char*, uint32_t, uint32_t);
struct Inode* InodeSeek(struct Inode*, char*);
struct Inode* InodeParentSeek(struct Inode*, char*, char*);
// fs fd ops
struct FileDescriptor* GetFileDescriptor(int fd);
void FreeFileDescriptor(int fd);
int AllocFileDescriptor(void);
@@ -0,0 +1,79 @@
/*
* Copyright (c) 2020 AIIT XUOS Lab
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
#pragma once
struct double_list_node {
struct double_list_node* next;
struct double_list_node* prev;
};
#define CONTAINER_OF(item, type, member) \
((type*)((char*)(item) - (unsigned long)(&((type*)0)->member)))
#define IS_DOUBLE_LIST_EMPTY(head) \
((head)->next == (head))
/*********************************************
*
* Double linked list operation functions
*
*********************************************/
#define DOUBLE_LIST_ENTRY(item, type, member) \
CONTAINER_OF(item, type, member)
#define DOUBLE_LIST_FOR_EACH_ENTRY(item, head, member) \
for (item = DOUBLE_LIST_ENTRY((head)->next, typeof(*item), member); \
&item->member != (head); \
item = DOUBLE_LIST_ENTRY(item->member.next, typeof(*item), member))
#define DOUBLE_LIST_FOR_EACH_ENTRY_REVERSE(item, head, member) \
for (item = DOUBLE_LIST_ENTRY((head)->prev, typeof(*item), member); \
&item->member != (head); \
item = DOUBLE_LIST_ENTRY(item->member.prev, typeof(*item), member))
__attribute__((always_inline)) static void inline doubleListNodeInit(struct double_list_node* list)
{
list->next = list;
list->prev = list;
}
__attribute__((always_inline)) static void inline _double_list_add(struct double_list_node* new_node, struct double_list_node* prev, struct double_list_node* next)
{
next->prev = new_node;
new_node->next = next;
new_node->prev = prev;
prev->next = new_node;
}
__attribute__((always_inline)) static void inline _double_list_del(struct double_list_node* prev, struct double_list_node* next)
{
next->prev = prev;
prev->next = next;
}
__attribute__((always_inline)) static void inline doubleListAddOnHead(struct double_list_node* new_node, struct double_list_node* head)
{
_double_list_add(new_node, head, head->next);
}
__attribute__((always_inline)) static void inline doubleListAddOnBack(struct double_list_node* new_node, struct double_list_node* head)
{
_double_list_add(new_node, head->prev, head);
}
__attribute__((always_inline)) static void inline doubleListDel(struct double_list_node* entry)
{
_double_list_del(entry->prev, entry->next);
entry->next = entry;
entry->prev = entry;
}