From 6563925b3148b78e83440fe53f395d5b11b1c91c Mon Sep 17 00:00:00 2001 From: worthant Date: Fri, 27 Dec 2024 02:53:14 +0300 Subject: [PATCH 1/4] :hammer: feat(vtfs.c)!: Http network storage --- vfs-kernel-module/source/vtfs.c | 934 ++++++++++++++++++++++++++++++++ 1 file changed, 934 insertions(+) diff --git a/vfs-kernel-module/source/vtfs.c b/vfs-kernel-module/source/vtfs.c index e95eb1b..8864b03 100644 --- a/vfs-kernel-module/source/vtfs.c +++ b/vfs-kernel-module/source/vtfs.c @@ -1,21 +1,955 @@ +#include #include #include #include +#include +#include + +#include "http.h" + +const char* SERVER_IP = "0.0.0.0"; +const int SERVER_PORT = 8080; + +// callee should call free_request on received buffer +int fill_request( + struct kvec* vec, const char* token, const char* method, size_t arg_size, va_list args +) { + // 2048 bytes for URL and 64 bytes for anything else + char* request_buffer = kzalloc(2048 + 64, GFP_KERNEL); + if (request_buffer == 0) { + return -ENOMEM; + } + + strcpy(request_buffer, "GET /api/"); + strcat(request_buffer, method); + + strcat(request_buffer, "?token="); + strcat(request_buffer, token); + + int i; + for (i = 0; i < arg_size; i++) { + strcat(request_buffer, "&"); + strcat(request_buffer, va_arg(args, char*)); + strcat(request_buffer, "="); + strcat(request_buffer, va_arg(args, char*)); + } + + strcat(request_buffer, " HTTP/1.1\r\nHost:"); + strcat(request_buffer, SERVER_IP); + strcat(request_buffer, "\r\nConnection: close\r\n\r\n"); + + memset(vec, 0, sizeof(struct kvec)); + vec->iov_base = request_buffer; + vec->iov_len = strlen(request_buffer); + + return 0; +} + +int receive_all(struct socket* sock, char* buffer, size_t buffer_size) { + struct msghdr hdr; + struct kvec vec; + + int read = 0; + + while (read < buffer_size) { + memset(&hdr, 0, sizeof(struct msghdr)); + memset(&vec, 0, sizeof(struct kvec)); + vec.iov_base = buffer + read; + vec.iov_len = buffer_size - read; + int ret = kernel_recvmsg(sock, &hdr, &vec, 1, vec.iov_len, 0); + if (ret == 0) { + break; + } else if (ret < 0) { + return -4; + } + read += ret; + } + + return read; +} + +int64_t parse_http_response( + char* raw_response, size_t raw_response_size, char* response, size_t response_size +) { + char* buffer = raw_response; + + // Read Response Line + { + char* status_line = strsep(&buffer, "\r"); + strsep(&status_line, " "); + if (status_line == 0) { + return -6; + } + char* status_code = strsep(&status_line, " "); + printk(KERN_INFO "Received response with status code %s\n", status_code); + if (strcmp(status_code, "200") != 0) { + return -5; + } + } + + int length = -1; + + while (true) { + if (buffer == 0) { + return -6; + } + char* header = strsep(&buffer, "\r"); + ++header; // skip \n + if (strcmp(header, "") == 0) { + // end of headers + break; + } + + if (strncmp(header, "Content-Length: ", 16) == 0) { + int error = kstrtoint(header + 16, 0, &length); + if (error != 0) { + return -6; + } + printk(KERN_INFO "Received response with content length %d\n", length); + } + } + ++buffer; // skip last '\n' + + if (length == -1) { + return -6; + } + + if (buffer + length > raw_response + raw_response_size) { + return -6; + } + + if (length < sizeof(int64_t)) { + return -7; + } + + length -= sizeof(int64_t); + + if (length > response_size) { + return -ENOSPC; + } + + int64_t return_value; + memcpy(&return_value, buffer, sizeof(int64_t)); + + buffer += sizeof(int64_t); + memcpy(response, buffer, length); + + return return_value; +} + +int64_t vtfs_http_call( + const char* token, + const char* method, + char* response_buffer, + size_t buffer_size, + size_t arg_size, + ... +) { + struct socket* sock; + int64_t error; + + error = sock_create_kern(&init_net, AF_INET, SOCK_STREAM, IPPROTO_TCP, &sock); + if (error < 0) { + return -1; + } + + struct sockaddr_in s_addr = { + .sin_family = AF_INET, + .sin_addr = {.s_addr = in_aton(SERVER_IP)}, + .sin_port = htons(SERVER_PORT) + }; + + error = kernel_connect(sock, (struct sockaddr*)&s_addr, sizeof(struct sockaddr_in), 0); + if (error != 0) { + sock_release(sock); + return -2; + } + + struct kvec kvec; + va_list args; + va_start(args, arg_size); + error = fill_request(&kvec, token, method, arg_size, args); + va_end(args); + + if (error != 0) { + kernel_sock_shutdown(sock, SHUT_RDWR); + sock_release(sock); + return error; + } + + struct msghdr msg; + memset(&msg, 0, sizeof(struct msghdr)); + + error = kernel_sendmsg(sock, &msg, &kvec, 1, kvec.iov_len); + kfree(kvec.iov_base); + + if (error < 0) { + kernel_sock_shutdown(sock, SHUT_RDWR); + sock_release(sock); + return -3; + } + + size_t raw_buffer_size = buffer_size + 1024; // add 1KB for HTTP headers + char* raw_response_buffer = kmalloc(raw_buffer_size, GFP_KERNEL); + if (raw_response_buffer == 0) { + kernel_sock_shutdown(sock, SHUT_RDWR); + sock_release(sock); + return -ENOMEM; + } + int read_bytes = receive_all(sock, raw_response_buffer, raw_buffer_size); + + kernel_sock_shutdown(sock, SHUT_RDWR); + sock_release(sock); + + if (read_bytes < 0) { + kfree(raw_response_buffer); + return -4; + } + + error = parse_http_response(raw_response_buffer, read_bytes, response_buffer, buffer_size); + + kfree(raw_response_buffer); + return error; +} + +void encode(const char* src, char* dst) { + while (*src != '\0') { + if ((*src >= '0' && *src <= '9') || (*src >= 'a' && *src <= 'z') || + (*src >= 'A' && *src <= 'Z')) { + *dst = *src; + dst++; + } else { + sprintf(dst, "%%%02X", (unsigned char)*src); + dst += 3; + } + src++; + } + *dst = '\0'; +} + +struct __attribute__((__packed__)) lookup_response { + uint32_t ino; + uint8_t mode; +}; + +struct __attribute__((__packed__)) create_response { + uint32_t ino; +}; + +struct __attribute__((__packed__)) remove_response {}; + +struct __attribute__((__packed__)) iterate_response { + uint32_t count; + struct __attribute__((__packed__)) r_dentry { + char name[256]; + uint32_t ino; + uint8_t mode; + } r_dentries[8]; +}; + +struct __attribute__((__packed__)) read_response { + uint32_t size; + char data[2048]; +}; + +struct __attribute__((__packed__)) write_response {}; + +struct __attribute__((__packed__)) max_ino_response { + uint32_t ino; +}; #define MODULE_NAME "vtfs" +#define ROOT_INODE_INO 100 + MODULE_LICENSE("GPL"); MODULE_AUTHOR("secs-dev"); MODULE_DESCRIPTION("A simple FS kernel module"); #define LOG(fmt, ...) pr_info("[" MODULE_NAME "]: " fmt, ##__VA_ARGS__) +unsigned long next_ino = ROOT_INODE_INO; + +struct inode* vtfs_get_inode(struct super_block*, const struct inode*, umode_t, int); + +struct vtfs_inode { + int ino; + umode_t mode; + size_t i_size; + char i_data[1024]; +}; + +struct vtfs_dentry { + struct dentry* d_dentry; + char d_name[256]; + int d_parent_ino; + struct vtfs_inode* d_inode; + struct list_head list; +}; + +struct { + struct super_block* sb; + struct list_head dentries; +} vtfs_sb; + +struct dentry* vtfs_lookup( + struct inode* parent_inode, struct dentry* child_dentry, unsigned int flag +) { + // ----------------| RAM |--------------------- + + // struct vtfs_dentry *dentry; + // struct list_head *pos; + // struct inode *inode; + + // list_for_each(pos, &vtfs_sb.dentries) { + // dentry = list_entry(pos, struct vtfs_dentry, list); + + // if (dentry->d_parent_ino == parent_inode->i_ino && strcmp(dentry->d_name, + // child_dentry->d_name.name) == 0) { + // inode = vtfs_get_inode(vtfs_sb.sb, parent_inode, dentry->d_inode->mode, + // dentry->d_inode->ino); d_add(child_dentry, inode); + // } + // } + + // ----------------| NET |--------------------- + unsigned long parent_ino = parent_inode->i_ino; + char* name = child_dentry->d_name.name; + + char inode_str[11]; + (void)snprintf(inode_str, sizeof(inode_str), "%d", parent_ino); + + char name_enc[255 * 3 + 1]; + encode(name, name_enc); + + struct lookup_response response; + int64_t code = vtfs_http_call( + "admin", + "lookup", + (void*)&response, + sizeof(response), + 2, + "parentInode", + inode_str, + "name", + name_enc + ); + if ((code) != 0) { + printk(KERN_ERR "networkfs_http_call error code %lld\n", code); + return NULL; + } + + struct inode* inode = vtfs_get_inode(vtfs_sb.sb, NULL, response.mode, response.ino); + d_add(child_dentry, inode); + + return NULL; +}; + +int vtfs_create(struct inode* parent_inode, struct dentry* child_dentry, umode_t mode, bool b) { + // ----------------| RAM |--------------------- + + // struct inode *inode; + // struct vtfs_dentry *new_dentry; + // struct vtfs_inode *new_inode; + + // inode = vtfs_get_inode(vtfs_sb.sb, parent_inode, mode, next_ino++); + // if (!inode) + // return -ENOMEM; + + // new_dentry = kmalloc(sizeof(struct vtfs_dentry), GFP_KERNEL); + // if (!new_dentry) { + // iput(inode); + // return -ENOMEM; + // } + + // new_inode = kmalloc(sizeof(struct vtfs_inode), GFP_KERNEL); + // if (!new_inode) { + // kfree(new_dentry); + // iput(inode); + // return -ENOMEM; + // } + + // new_dentry->d_dentry = child_dentry; + // strcpy(new_dentry->d_name, child_dentry->d_name.name); + // new_dentry->d_parent_ino = parent_inode->i_ino; + // new_dentry->d_inode = new_inode; + // new_dentry->d_inode->ino = inode->i_ino; + // new_dentry->d_inode->mode = inode->i_mode; + // new_dentry->d_inode->i_size = 0; + + // list_add(&new_dentry->list, &vtfs_sb.dentries); + + // d_add(child_dentry, inode); + + // printk(KERN_INFO "File %s added successfully\n", child_dentry->d_name.name); + + // return 0; + + // ----------------| NET |--------------------- + unsigned long parent_ino = parent_inode->i_ino; + char* name = child_dentry->d_name.name; + + char inode_str[11]; + (void)snprintf(inode_str, sizeof(inode_str), "%d", parent_ino); + + char name_enc[255 * 3 + 1]; + encode(name, name_enc); + + char mode_str[2]; + (void)snprintf(mode_str, sizeof(mode_str), "%d", (int)mode); + + struct create_response response; + int64_t code = vtfs_http_call( + "admin", + "create", + (void*)&response, + sizeof(response), + 3, + "parentInode", + inode_str, + "name", + name_enc, + "mode", + mode_str + ); + if (code != 0) { + printk(KERN_ERR "networkfs_http_call create failed"); + return -ENOMEM; + } + + struct inode* inode = vtfs_get_inode(vtfs_sb.sb, NULL, S_IFREG, response.ino); + if (!inode) + return -ENOMEM; + + d_add(child_dentry, inode); + + return 0; +} + +int vtfs_unlink(struct inode* parent_inode, struct dentry* child_dentry) { + // ----------------| RAM |--------------------- + + // struct vtfs_dentry *found_dentry = NULL; + // struct list_head *pos; + + // list_for_each(pos, &vtfs_sb.dentries) { + // found_dentry = list_entry(pos, struct vtfs_dentry, list); + + // if (strcmp(found_dentry->d_name, child_dentry->d_name.name) == 0 && + // found_dentry->d_parent_ino == parent_inode->i_ino) { + + // list_del(&found_dentry->list); + + // kfree(found_dentry); + + // printk(KERN_INFO "File %s deleted successfully\n", child_dentry->d_name.name); + + // return 0; + // } + // } + + // return -ENOENT; + + // ----------------| NET |--------------------- + unsigned long parent_ino = parent_inode->i_ino; + char* name = child_dentry->d_name.name; + + char inode_str[11]; + (void)snprintf(inode_str, sizeof(inode_str), "%d", parent_ino); + + char name_enc[255 * 3 + 1]; + encode(name, name_enc); + + struct remove_response response; + int64_t code = vtfs_http_call( + "admin", + "remove", + (void*)&response, + sizeof(response), + 2, + "parentInode", + inode_str, + "name", + name_enc + ); + if (code != 0) { + printk(KERN_ERR "networkfs_http_call error code %lld\n", code); + return -ENOENT; + } + + return 0; +} + +int vtfs_mkdir(struct inode* parent_inode, struct dentry* child_dentry, umode_t mode) { + // ----------------| RAM |--------------------- + + // struct inode *inode; + // struct vtfs_dentry *new_dentry; + + // inode = vtfs_get_inode(vtfs_sb.sb, parent_inode, mode | S_IFDIR, next_ino++); + // if (!inode) { + // return -ENOMEM; + // } + + // new_dentry = kmalloc(sizeof(struct vtfs_dentry), GFP_KERNEL); + // if (!new_dentry) { + // iput(inode); + // return -ENOMEM; + // } + + // new_dentry->d_inode = kmalloc(sizeof(struct vtfs_inode), GFP_KERNEL); + // if (!new_dentry->d_inode) { + // kfree(new_dentry); + // iput(inode); + // return -ENOMEM; + // } + + // new_dentry->d_dentry = child_dentry; + // strcpy(new_dentry->d_name, child_dentry->d_name.name); + // new_dentry->d_parent_ino = parent_inode->i_ino; + // new_dentry->d_inode->ino = inode->i_ino; + // new_dentry->d_inode->mode = inode->i_mode; + // new_dentry->d_inode->i_size = 0; + + // list_add(&new_dentry->list, &vtfs_sb.dentries); + + // d_add(child_dentry, inode); + + // printk(KERN_INFO "Directory %s created successfully\n", child_dentry->d_name.name); + + // return 0; + + // ----------------| NET |--------------------- + unsigned long parent_ino = parent_inode->i_ino; + char* name = child_dentry->d_name.name; + + char inode_str[11]; + (void)snprintf(inode_str, sizeof(inode_str), "%d", parent_ino); + + char name_enc[255 * 3 + 1]; + encode(name, name_enc); + + char mode_str[2]; + (void)snprintf(mode_str, sizeof(mode_str), "%d", (int)mode); + + struct create_response response; + int64_t code = vtfs_http_call( + "admin", + "create", + (void*)&response, + sizeof(response), + 3, + "parentInode", + inode_str, + "name", + name_enc, + "mode", + mode_str + ); + if (code != 0) { + printk(KERN_ERR "networkfs_http_call create failed"); + return -ENOMEM; + } + + struct inode* inode = vtfs_get_inode(vtfs_sb.sb, NULL, S_IFDIR, response.ino); + if (!inode) + return -ENOMEM; + + d_add(child_dentry, inode); + + return 0; +} + +int vtfs_rmdir(struct inode* parent_inode, struct dentry* child_dentry) { + // ----------------| RAM |--------------------- + + // struct vtfs_dentry *found_dentry = NULL; + // struct list_head *pos; + + // list_for_each(pos, &vtfs_sb.dentries) { + // found_dentry = list_entry(pos, struct vtfs_dentry, list); + + // if (strcmp(found_dentry->d_name, child_dentry->d_name.name) == 0 && + // found_dentry->d_parent_ino == parent_inode->i_ino) { + + // list_del(&found_dentry->list); + // kfree(found_dentry); + + // printk(KERN_INFO "File %s deleted successfully\n", child_dentry->d_name.name); + + // return 0; + // } + // } + + // return -ENOENT; + + // ----------------| NET |--------------------- + unsigned long parent_ino = parent_inode->i_ino; + char* name = child_dentry->d_name.name; + + char inode_str[11]; + (void)snprintf(inode_str, sizeof(inode_str), "%d", parent_ino); + + char name_enc[255 * 3 + 1]; + encode(name, name_enc); + + struct remove_response response; + int64_t code = vtfs_http_call( + "admin", + "remove", + (void*)&response, + sizeof(response), + 2, + "parentInode", + inode_str, + "name", + name_enc + ); + if (code != 0) { + printk(KERN_ERR "networkfs_http_call error code %lld\n", code); + return -ENOENT; + } + + return 0; +} + +// int vtfs_link(struct dentry *old_dentry, struct inode *parent_inode, struct dentry *new_dentry) { +// struct vtfs_dentry *existing_dentry = NULL; +// struct list_head *pos; +// struct vtfs_dentry *new_link_dentry; + +// list_for_each(pos, &vtfs_sb.dentries) { +// existing_dentry = list_entry(pos, struct vtfs_dentry, list); + +// if (strcmp(existing_dentry->d_name, old_dentry->d_name.name) == 0 && +// existing_dentry->d_parent_ino == old_dentry->d_parent->d_inode->i_ino) { + +// new_link_dentry = kmalloc(sizeof(struct vtfs_dentry), GFP_KERNEL); +// if (!new_link_dentry) +// return -ENOMEM; + +// new_link_dentry->d_dentry = new_dentry; +// strcpy(new_link_dentry->d_name, new_dentry->d_name.name); +// new_link_dentry->d_parent_ino = parent_inode->i_ino; +// new_link_dentry->d_inode = existing_dentry->d_inode; + +// list_add(&new_link_dentry->list, &vtfs_sb.dentries); +// inc_nlink(old_dentry->d_inode); + +// d_add(new_dentry, old_dentry->d_inode); + +// printk(KERN_INFO "File %s linked successfully\n", new_dentry->d_name.name); +// return 0; +// } +// } + +// return -ENOENT; +// } + +struct inode_operations vtfs_inode_ops = { + .lookup = vtfs_lookup, + .create = vtfs_create, + .unlink = vtfs_unlink, + .mkdir = vtfs_mkdir, + .rmdir = vtfs_rmdir, + // .link = vtfs_link, +}; + +int vtfs_iterate(struct file* file, struct dir_context* ctx) { + // struct vtfs_dentry *dentry; + // struct list_head *pos; + // struct inode *dir_inode = file->f_path.dentry->d_inode; + // unsigned char type; + + // if (!dir_emit_dots(file, ctx)) + // return 0; + + // if (ctx->pos >= 3) { + // return ctx->pos; + // } + + // list_for_each(pos, &vtfs_sb.dentries) { + // dentry = list_entry(pos, struct vtfs_dentry, list); + + // printk(KERN_INFO "Dentry %s inode %ld data %s\n", dentry->d_name, dentry->d_inode->ino, + // dentry->d_inode->i_data); + + // if (S_ISDIR(dentry->d_inode->mode)) + // type = DT_DIR; + // else if (S_ISREG(dentry->d_inode->mode)) + // type = DT_REG; + // else + // type = DT_UNKNOWN; + + // if (dentry->d_parent_ino == dir_inode->i_ino && !dir_emit(ctx, dentry->d_name, + // strlen(dentry->d_name), dentry->d_inode->ino, type)) { + // return -ENOMEM; + // } + + // ctx->pos += 1; + // } + // + // return ctx->pos; + + // ----------------| NET |--------------------- + + if (!dir_emit_dots(file, ctx)) + return 0; + + if (ctx->pos >= 3) { + return ctx->pos; + } + + char inode_str[11]; + (void)snprintf(inode_str, sizeof(inode_str), "%d", file->f_path.dentry->d_inode->i_ino); + + struct iterate_response response; + int64_t code = vtfs_http_call( + "admin", "iterate", (void*)&response, sizeof(response), 1, "parentInode", inode_str + ); + if (code != 0) { + printk(KERN_ERR "networkfs_http_call error code %lld\n", code); + } + + int i; + for (i = 0; i < response.count; i++) { + if (!dir_emit( + ctx, + response.r_dentries[i].name, + strlen(response.r_dentries[i].name), + response.r_dentries[i].ino, + response.r_dentries[i].mode + )) { + printk(KERN_ERR "dir_emit error"); + } + ctx->pos += 1; + } + + return (int)(ctx->pos - file->f_pos); +} + +ssize_t vtfs_read(struct file* file, char* buffer, size_t len, loff_t* offset) { + // ----------------| RAM |--------------------- + + // struct vtfs_inode *found_inode; + // struct vtfs_dentry *found_dentry; + // struct inode *file_inode = file->f_inode; + // struct list_head *pos; + // ssize_t to_read; + + // list_for_each(pos, &vtfs_sb.dentries) { + // found_dentry = list_entry(pos, struct vtfs_dentry, list); + // found_inode = found_dentry->d_inode; + + // if (found_dentry->d_inode->ino == file_inode->i_ino) { + // if (*offset > found_inode->i_size) + // return 0; + + // to_read = min(len, found_inode->i_size - *offset); + // if (copy_to_user(buffer, found_inode->i_data + *offset, to_read)) + // return -EFAULT; + + // *offset += to_read; + + // return to_read; + // } + // } + + // return -ENOENT; + + // ----------------| NET |--------------------- + char inode_str[11]; + (void)snprintf(inode_str, sizeof(inode_str), "%d", file->f_path.dentry->d_inode->i_ino); + + int64_t code; + struct read_response response; + if ((code = vtfs_http_call( + "admin", "read", (void*)&response, sizeof(response), 1, "inode", inode_str + )) != 0) { + printk(KERN_INFO "networkfs_http_call error code %lld\n", code); + return -ENOENT; + } + + if (*offset >= response.size) { + return 0; + } + + ssize_t to_read = min(len, response.size - *offset); + if (copy_to_user(buffer, response.data + *offset, to_read)) { + return -EFAULT; + } + + *offset += to_read; + + return to_read; +} + +ssize_t vtfs_write(struct file* file, const char* buffer, size_t len, loff_t* offset) { + // ----------------| RAM |--------------------- + + // struct vtfs_inode *found_inode; + // struct vtfs_dentry *found_dentry; + // struct inode *file_inode = file->f_inode; + // struct list_head *pos; + // void *new_data; + // ssize_t new_size; + + // list_for_each(pos, &vtfs_sb.dentries) { + // found_dentry = list_entry(pos, struct vtfs_dentry, list); + // found_inode = found_dentry->d_inode; + + // if (found_dentry->d_inode->ino == file_inode->i_ino) { + // new_size = max(found_inode->i_size, *offset + len); + + // if (copy_from_user(found_inode->i_data + *offset, buffer, len)) { + // return -EFAULT; + // } + + // found_inode->i_size = new_size; + + // *offset += len; + + // return len; + // } + // } + + // return -ENOENT; + + // ----------------| NET |--------------------- + if (*offset >= 2048) { + return 0; + } + + len = min(len, 2047); + + char data[2048]; + if (copy_from_user(data, buffer, len) != 0) { + return 0; + } + data[len] = 0; + + char inode_str[11]; + (void)snprintf(inode_str, sizeof(inode_str), "%d", file->f_path.dentry->d_inode->i_ino); + + char data_enc[2047 * 3 + 1]; + encode(data, data_enc); + + int64_t code; + struct write_response response; + if ((code = vtfs_http_call( + "admin", + "write", + (void*)&response, + sizeof(response), + 2, + "inode", + inode_str, + "data", + data_enc + )) != 0) { + printk(KERN_ERR "networkfs_http_call error code %lld\n", code); + return -1; + } + + *offset += len; + + return len; +} + +struct file_operations vtfs_dir_ops = { + .iterate = vtfs_iterate, + .read = vtfs_read, + .write = vtfs_write, +}; + +struct inode* vtfs_get_inode( + struct super_block* sb, const struct inode* dir, umode_t mode, int i_ino +) { + struct inode* inode = new_inode(sb); + if (inode != NULL) { + inode_init_owner(inode, dir, mode); + } + + inode->i_ino = i_ino; + inode->i_op = &vtfs_inode_ops; + inode->i_fop = &vtfs_dir_ops; + + inc_nlink(inode); + + return inode; +} + +int vtfs_fill_super(struct super_block* sb, void* data, int silent) { + umode_t mode = S_IFDIR | 0777; + + struct inode* inode = vtfs_get_inode(sb, NULL, mode, ROOT_INODE_INO); + if (!inode) { + printk(KERN_ERR "Failed to create a root inode"); + return -ENOMEM; + } + + sb->s_root = d_make_root(inode); + if (sb->s_root == NULL) { + printk(KERN_ERR "Failed to create a root dentry"); + return -ENOMEM; + } + + vtfs_sb.sb = sb; + INIT_LIST_HEAD(&vtfs_sb.dentries); + + printk(KERN_INFO "return 0\n"); + + return 0; +} + +struct dentry* vtfs_mount( + struct file_system_type* fs_type, int flags, const char* token, void* data +) { + struct dentry* ret = mount_nodev(fs_type, flags, data, vtfs_fill_super); + if (ret == NULL) { + printk(KERN_ERR "Can't mount file system"); + } else { + printk(KERN_INFO "Mounted successfuly"); + } + return ret; +} + +int init(void) { + struct max_ino_response response; + int64_t code = vtfs_http_call("admin", "max_ino", (void*)&response, sizeof(response), 0); + if ((code) != 0) { + printk(KERN_ERR "vtfs_init error code %lld\n", code); + return -1; + } + + next_ino = response.ino; + + return 0; +} + +void vtfs_kill_sb(struct super_block* sb) { + printk(KERN_INFO "vtfs super block is destroyed. Unmount successfully.\n"); +} + +struct file_system_type vtfs_fs_type = { + .name = "vtfs", + .mount = vtfs_mount, + .kill_sb = vtfs_kill_sb, +}; + static int __init vtfs_init(void) { + register_filesystem(&vtfs_fs_type); + + if (init() != 0) { + LOG("VTFS could not join the kernel\n"); + return -1; + } + LOG("VTFS joined the kernel\n"); return 0; } static void __exit vtfs_exit(void) { + unregister_filesystem(&vtfs_fs_type); LOG("VTFS left the kernel\n"); } From a5638d5bbc33d8166fab72b5bcfd49eb58858ff6 Mon Sep 17 00:00:00 2001 From: worthant Date: Fri, 27 Dec 2024 04:14:07 +0300 Subject: [PATCH 2/4] :hammer: feat(vtfs.c)!: RAM vfs module --- vfs-kernel-module/source/vtfs.c | 629 +++++++++----------------------- 1 file changed, 164 insertions(+), 465 deletions(-) diff --git a/vfs-kernel-module/source/vtfs.c b/vfs-kernel-module/source/vtfs.c index 8864b03..536a47f 100644 --- a/vfs-kernel-module/source/vtfs.c +++ b/vfs-kernel-module/source/vtfs.c @@ -292,405 +292,176 @@ struct { struct list_head dentries; } vtfs_sb; +// Find child file or dir in vtfs_sb.dentries struct dentry* vtfs_lookup( struct inode* parent_inode, struct dentry* child_dentry, unsigned int flag ) { // ----------------| RAM |--------------------- - // struct vtfs_dentry *dentry; - // struct list_head *pos; - // struct inode *inode; - - // list_for_each(pos, &vtfs_sb.dentries) { - // dentry = list_entry(pos, struct vtfs_dentry, list); - - // if (dentry->d_parent_ino == parent_inode->i_ino && strcmp(dentry->d_name, - // child_dentry->d_name.name) == 0) { - // inode = vtfs_get_inode(vtfs_sb.sb, parent_inode, dentry->d_inode->mode, - // dentry->d_inode->ino); d_add(child_dentry, inode); - // } - // } - - // ----------------| NET |--------------------- - unsigned long parent_ino = parent_inode->i_ino; - char* name = child_dentry->d_name.name; - - char inode_str[11]; - (void)snprintf(inode_str, sizeof(inode_str), "%d", parent_ino); - - char name_enc[255 * 3 + 1]; - encode(name, name_enc); - - struct lookup_response response; - int64_t code = vtfs_http_call( - "admin", - "lookup", - (void*)&response, - sizeof(response), - 2, - "parentInode", - inode_str, - "name", - name_enc - ); - if ((code) != 0) { - printk(KERN_ERR "networkfs_http_call error code %lld\n", code); - return NULL; - } - - struct inode* inode = vtfs_get_inode(vtfs_sb.sb, NULL, response.mode, response.ino); - d_add(child_dentry, inode); + struct vtfs_dentry* dentry; + struct list_head* pos; + struct inode* inode; + + list_for_each(pos, &vtfs_sb.dentries) { + dentry = list_entry(pos, struct vtfs_dentry, list); - return NULL; + if (dentry->d_parent_ino == parent_inode->i_ino && + strcmp(dentry->d_name, child_dentry->d_name.name) == 0) { + inode = vtfs_get_inode(vtfs_sb.sb, parent_inode, dentry->d_inode->mode, dentry->d_inode->ino); + d_add(child_dentry, inode); + return NULL; + } + } + return NULL; // if nothing is found }; +// Create file in RAM int vtfs_create(struct inode* parent_inode, struct dentry* child_dentry, umode_t mode, bool b) { // ----------------| RAM |--------------------- - // struct inode *inode; - // struct vtfs_dentry *new_dentry; - // struct vtfs_inode *new_inode; - - // inode = vtfs_get_inode(vtfs_sb.sb, parent_inode, mode, next_ino++); - // if (!inode) - // return -ENOMEM; - - // new_dentry = kmalloc(sizeof(struct vtfs_dentry), GFP_KERNEL); - // if (!new_dentry) { - // iput(inode); - // return -ENOMEM; - // } - - // new_inode = kmalloc(sizeof(struct vtfs_inode), GFP_KERNEL); - // if (!new_inode) { - // kfree(new_dentry); - // iput(inode); - // return -ENOMEM; - // } - - // new_dentry->d_dentry = child_dentry; - // strcpy(new_dentry->d_name, child_dentry->d_name.name); - // new_dentry->d_parent_ino = parent_inode->i_ino; - // new_dentry->d_inode = new_inode; - // new_dentry->d_inode->ino = inode->i_ino; - // new_dentry->d_inode->mode = inode->i_mode; - // new_dentry->d_inode->i_size = 0; - - // list_add(&new_dentry->list, &vtfs_sb.dentries); - - // d_add(child_dentry, inode); - - // printk(KERN_INFO "File %s added successfully\n", child_dentry->d_name.name); - - // return 0; - - // ----------------| NET |--------------------- - unsigned long parent_ino = parent_inode->i_ino; - char* name = child_dentry->d_name.name; - - char inode_str[11]; - (void)snprintf(inode_str, sizeof(inode_str), "%d", parent_ino); - - char name_enc[255 * 3 + 1]; - encode(name, name_enc); - - char mode_str[2]; - (void)snprintf(mode_str, sizeof(mode_str), "%d", (int)mode); - - struct create_response response; - int64_t code = vtfs_http_call( - "admin", - "create", - (void*)&response, - sizeof(response), - 3, - "parentInode", - inode_str, - "name", - name_enc, - "mode", - mode_str - ); - if (code != 0) { - printk(KERN_ERR "networkfs_http_call create failed"); + struct inode* inode; + struct vtfs_dentry* new_dentry; + struct vtfs_inode* new_inode; + + inode = vtfs_get_inode(vtfs_sb.sb, parent_inode, mode, next_ino++); + if (!inode) { return -ENOMEM; } - struct inode* inode = vtfs_get_inode(vtfs_sb.sb, NULL, S_IFREG, response.ino); - if (!inode) + new_dentry = kmalloc(sizeof(struct vtfs_dentry), GFP_KERNEL); + if (!new_dentry) { + iput(inode); return -ENOMEM; + } + + new_inode = kmalloc(sizeof(struct vtfs_inode), GFP_KERNEL); + if (!new_inode) { + kfree(new_dentry); + iput(inode); + return -ENOMEM; + } + + new_dentry->d_dentry = child_dentry; + strcpy(new_dentry->d_name, child_dentry->d_name.name); + new_dentry->d_parent_ino = parent_inode->i_ino; + new_dentry->d_inode = new_inode; + new_dentry->d_inode->ino = inode->i_ino; + new_dentry->d_inode->mode = inode->i_mode; + new_dentry->d_inode->i_size = 0; + + list_add(&new_dentry->list, &vtfs_sb.dentries); d_add(child_dentry, inode); + printk(KERN_INFO "File %s added successfully\n", child_dentry->d_name.name); + return 0; } +// Delete file from RAM int vtfs_unlink(struct inode* parent_inode, struct dentry* child_dentry) { // ----------------| RAM |--------------------- - // struct vtfs_dentry *found_dentry = NULL; - // struct list_head *pos; - - // list_for_each(pos, &vtfs_sb.dentries) { - // found_dentry = list_entry(pos, struct vtfs_dentry, list); - - // if (strcmp(found_dentry->d_name, child_dentry->d_name.name) == 0 && - // found_dentry->d_parent_ino == parent_inode->i_ino) { - - // list_del(&found_dentry->list); - - // kfree(found_dentry); + struct vtfs_dentry* found_dentry = NULL; + struct list_head* pos; - // printk(KERN_INFO "File %s deleted successfully\n", child_dentry->d_name.name); + list_for_each(pos, &vtfs_sb.dentries) { + found_dentry = list_entry(pos, struct vtfs_dentry, list); - // return 0; - // } - // } + if (strcmp(found_dentry->d_name, child_dentry->d_name.name) == 0 && + found_dentry->d_parent_ino == parent_inode->i_ino) { + list_del(&found_dentry->list); - // return -ENOENT; + kfree(found_dentry); - // ----------------| NET |--------------------- - unsigned long parent_ino = parent_inode->i_ino; - char* name = child_dentry->d_name.name; + printk(KERN_INFO "File %s deleted successfully\n", child_dentry->d_name.name); - char inode_str[11]; - (void)snprintf(inode_str, sizeof(inode_str), "%d", parent_ino); - - char name_enc[255 * 3 + 1]; - encode(name, name_enc); - - struct remove_response response; - int64_t code = vtfs_http_call( - "admin", - "remove", - (void*)&response, - sizeof(response), - 2, - "parentInode", - inode_str, - "name", - name_enc - ); - if (code != 0) { - printk(KERN_ERR "networkfs_http_call error code %lld\n", code); - return -ENOENT; + return 0; + } } - return 0; + return -ENOENT; } +// Create dir in RAM int vtfs_mkdir(struct inode* parent_inode, struct dentry* child_dentry, umode_t mode) { // ----------------| RAM |--------------------- - // struct inode *inode; - // struct vtfs_dentry *new_dentry; - - // inode = vtfs_get_inode(vtfs_sb.sb, parent_inode, mode | S_IFDIR, next_ino++); - // if (!inode) { - // return -ENOMEM; - // } - - // new_dentry = kmalloc(sizeof(struct vtfs_dentry), GFP_KERNEL); - // if (!new_dentry) { - // iput(inode); - // return -ENOMEM; - // } - - // new_dentry->d_inode = kmalloc(sizeof(struct vtfs_inode), GFP_KERNEL); - // if (!new_dentry->d_inode) { - // kfree(new_dentry); - // iput(inode); - // return -ENOMEM; - // } - - // new_dentry->d_dentry = child_dentry; - // strcpy(new_dentry->d_name, child_dentry->d_name.name); - // new_dentry->d_parent_ino = parent_inode->i_ino; - // new_dentry->d_inode->ino = inode->i_ino; - // new_dentry->d_inode->mode = inode->i_mode; - // new_dentry->d_inode->i_size = 0; - - // list_add(&new_dentry->list, &vtfs_sb.dentries); - - // d_add(child_dentry, inode); - - // printk(KERN_INFO "Directory %s created successfully\n", child_dentry->d_name.name); - - // return 0; - - // ----------------| NET |--------------------- - unsigned long parent_ino = parent_inode->i_ino; - char* name = child_dentry->d_name.name; - - char inode_str[11]; - (void)snprintf(inode_str, sizeof(inode_str), "%d", parent_ino); - - char name_enc[255 * 3 + 1]; - encode(name, name_enc); - - char mode_str[2]; - (void)snprintf(mode_str, sizeof(mode_str), "%d", (int)mode); - - struct create_response response; - int64_t code = vtfs_http_call( - "admin", - "create", - (void*)&response, - sizeof(response), - 3, - "parentInode", - inode_str, - "name", - name_enc, - "mode", - mode_str - ); - if (code != 0) { - printk(KERN_ERR "networkfs_http_call create failed"); + struct inode* inode; + struct vtfs_dentry* new_dentry; + + inode = vtfs_get_inode(vtfs_sb.sb, parent_inode, mode | S_IFDIR, next_ino++); + if (!inode) { + return -ENOMEM; + } + + new_dentry = kmalloc(sizeof(struct vtfs_dentry), GFP_KERNEL); + if (!new_dentry) { + iput(inode); return -ENOMEM; } - struct inode* inode = vtfs_get_inode(vtfs_sb.sb, NULL, S_IFDIR, response.ino); - if (!inode) + new_dentry->d_inode = kmalloc(sizeof(struct vtfs_inode), GFP_KERNEL); + if (!new_dentry->d_inode) { + kfree(new_dentry); + iput(inode); return -ENOMEM; + } + + new_dentry->d_dentry = child_dentry; + strcpy(new_dentry->d_name, child_dentry->d_name.name); + new_dentry->d_parent_ino = parent_inode->i_ino; + new_dentry->d_inode->ino = inode->i_ino; + new_dentry->d_inode->mode = inode->i_mode; + new_dentry->d_inode->i_size = 0; + + list_add(&new_dentry->list, &vtfs_sb.dentries); d_add(child_dentry, inode); + printk(KERN_INFO "Directory %s created successfully\n", child_dentry->d_name.name); + return 0; } +// Delete dir from RAM int vtfs_rmdir(struct inode* parent_inode, struct dentry* child_dentry) { // ----------------| RAM |--------------------- - // struct vtfs_dentry *found_dentry = NULL; - // struct list_head *pos; - - // list_for_each(pos, &vtfs_sb.dentries) { - // found_dentry = list_entry(pos, struct vtfs_dentry, list); - - // if (strcmp(found_dentry->d_name, child_dentry->d_name.name) == 0 && - // found_dentry->d_parent_ino == parent_inode->i_ino) { - - // list_del(&found_dentry->list); - // kfree(found_dentry); + struct vtfs_dentry* found_dentry = NULL; + struct list_head* pos; - // printk(KERN_INFO "File %s deleted successfully\n", child_dentry->d_name.name); + list_for_each(pos, &vtfs_sb.dentries) { + found_dentry = list_entry(pos, struct vtfs_dentry, list); - // return 0; - // } - // } + if (strcmp(found_dentry->d_name, child_dentry->d_name.name) == 0 && + found_dentry->d_parent_ino == parent_inode->i_ino) { + list_del(&found_dentry->list); + kfree(found_dentry); - // return -ENOENT; + printk(KERN_INFO "File %s deleted successfully\n", child_dentry->d_name.name); - // ----------------| NET |--------------------- - unsigned long parent_ino = parent_inode->i_ino; - char* name = child_dentry->d_name.name; - - char inode_str[11]; - (void)snprintf(inode_str, sizeof(inode_str), "%d", parent_ino); - - char name_enc[255 * 3 + 1]; - encode(name, name_enc); - - struct remove_response response; - int64_t code = vtfs_http_call( - "admin", - "remove", - (void*)&response, - sizeof(response), - 2, - "parentInode", - inode_str, - "name", - name_enc - ); - if (code != 0) { - printk(KERN_ERR "networkfs_http_call error code %lld\n", code); - return -ENOENT; + return 0; + } } - return 0; + return -ENOENT; // couldn't find any dir } -// int vtfs_link(struct dentry *old_dentry, struct inode *parent_inode, struct dentry *new_dentry) { -// struct vtfs_dentry *existing_dentry = NULL; -// struct list_head *pos; -// struct vtfs_dentry *new_link_dentry; - -// list_for_each(pos, &vtfs_sb.dentries) { -// existing_dentry = list_entry(pos, struct vtfs_dentry, list); - -// if (strcmp(existing_dentry->d_name, old_dentry->d_name.name) == 0 && -// existing_dentry->d_parent_ino == old_dentry->d_parent->d_inode->i_ino) { - -// new_link_dentry = kmalloc(sizeof(struct vtfs_dentry), GFP_KERNEL); -// if (!new_link_dentry) -// return -ENOMEM; - -// new_link_dentry->d_dentry = new_dentry; -// strcpy(new_link_dentry->d_name, new_dentry->d_name.name); -// new_link_dentry->d_parent_ino = parent_inode->i_ino; -// new_link_dentry->d_inode = existing_dentry->d_inode; - -// list_add(&new_link_dentry->list, &vtfs_sb.dentries); -// inc_nlink(old_dentry->d_inode); - -// d_add(new_dentry, old_dentry->d_inode); - -// printk(KERN_INFO "File %s linked successfully\n", new_dentry->d_name.name); -// return 0; -// } -// } - -// return -ENOENT; -// } - struct inode_operations vtfs_inode_ops = { .lookup = vtfs_lookup, .create = vtfs_create, .unlink = vtfs_unlink, .mkdir = vtfs_mkdir, .rmdir = vtfs_rmdir, - // .link = vtfs_link, }; +// Iterate through all dir includes in RAM int vtfs_iterate(struct file* file, struct dir_context* ctx) { - // struct vtfs_dentry *dentry; - // struct list_head *pos; - // struct inode *dir_inode = file->f_path.dentry->d_inode; - // unsigned char type; - - // if (!dir_emit_dots(file, ctx)) - // return 0; - - // if (ctx->pos >= 3) { - // return ctx->pos; - // } - - // list_for_each(pos, &vtfs_sb.dentries) { - // dentry = list_entry(pos, struct vtfs_dentry, list); - - // printk(KERN_INFO "Dentry %s inode %ld data %s\n", dentry->d_name, dentry->d_inode->ino, - // dentry->d_inode->i_data); - - // if (S_ISDIR(dentry->d_inode->mode)) - // type = DT_DIR; - // else if (S_ISREG(dentry->d_inode->mode)) - // type = DT_REG; - // else - // type = DT_UNKNOWN; - - // if (dentry->d_parent_ino == dir_inode->i_ino && !dir_emit(ctx, dentry->d_name, - // strlen(dentry->d_name), dentry->d_inode->ino, type)) { - // return -ENOMEM; - // } - - // ctx->pos += 1; - // } - // - // return ctx->pos; - - // ----------------| NET |--------------------- + struct vtfs_dentry* dentry; + struct list_head* pos; + struct inode* dir_inode = file->f_path.dentry->d_inode; + unsigned char type; if (!dir_emit_dots(file, ctx)) return 0; @@ -699,160 +470,96 @@ int vtfs_iterate(struct file* file, struct dir_context* ctx) { return ctx->pos; } - char inode_str[11]; - (void)snprintf(inode_str, sizeof(inode_str), "%d", file->f_path.dentry->d_inode->i_ino); + list_for_each(pos, &vtfs_sb.dentries) { + dentry = list_entry(pos, struct vtfs_dentry, list); - struct iterate_response response; - int64_t code = vtfs_http_call( - "admin", "iterate", (void*)&response, sizeof(response), 1, "parentInode", inode_str - ); - if (code != 0) { - printk(KERN_ERR "networkfs_http_call error code %lld\n", code); - } + printk( + KERN_INFO "Dentry %s inode %ld data %s\n", + dentry->d_name, + dentry->d_inode->ino, + dentry->d_inode->i_data + ); - int i; - for (i = 0; i < response.count; i++) { - if (!dir_emit( - ctx, - response.r_dentries[i].name, - strlen(response.r_dentries[i].name), - response.r_dentries[i].ino, - response.r_dentries[i].mode - )) { - printk(KERN_ERR "dir_emit error"); + if (S_ISDIR(dentry->d_inode->mode)) + type = DT_DIR; + else if (S_ISREG(dentry->d_inode->mode)) + type = DT_REG; + else + type = DT_UNKNOWN; + + if (dentry->d_parent_ino == dir_inode->i_ino && + !dir_emit(ctx, dentry->d_name, strlen(dentry->d_name), dentry->d_inode->ino, type)) { + return -ENOMEM; } + ctx->pos += 1; } - return (int)(ctx->pos - file->f_pos); + return ctx->pos; } +// Read file data from RAM ssize_t vtfs_read(struct file* file, char* buffer, size_t len, loff_t* offset) { // ----------------| RAM |--------------------- - // struct vtfs_inode *found_inode; - // struct vtfs_dentry *found_dentry; - // struct inode *file_inode = file->f_inode; - // struct list_head *pos; - // ssize_t to_read; - - // list_for_each(pos, &vtfs_sb.dentries) { - // found_dentry = list_entry(pos, struct vtfs_dentry, list); - // found_inode = found_dentry->d_inode; + struct vtfs_inode* found_inode; + struct vtfs_dentry* found_dentry; + struct inode* file_inode = file->f_inode; + struct list_head* pos; + ssize_t to_read; - // if (found_dentry->d_inode->ino == file_inode->i_ino) { - // if (*offset > found_inode->i_size) - // return 0; + list_for_each(pos, &vtfs_sb.dentries) { + found_dentry = list_entry(pos, struct vtfs_dentry, list); + found_inode = found_dentry->d_inode; - // to_read = min(len, found_inode->i_size - *offset); - // if (copy_to_user(buffer, found_inode->i_data + *offset, to_read)) - // return -EFAULT; + if (found_dentry->d_inode->ino == file_inode->i_ino) { + if (*offset > found_inode->i_size) + return 0; - // *offset += to_read; + to_read = min(len, found_inode->i_size - *offset); + if (copy_to_user(buffer, found_inode->i_data + *offset, to_read)) + return -EFAULT; - // return to_read; - // } - // } + *offset += to_read; - // return -ENOENT; - - // ----------------| NET |--------------------- - char inode_str[11]; - (void)snprintf(inode_str, sizeof(inode_str), "%d", file->f_path.dentry->d_inode->i_ino); - - int64_t code; - struct read_response response; - if ((code = vtfs_http_call( - "admin", "read", (void*)&response, sizeof(response), 1, "inode", inode_str - )) != 0) { - printk(KERN_INFO "networkfs_http_call error code %lld\n", code); - return -ENOENT; - } - - if (*offset >= response.size) { - return 0; - } - - ssize_t to_read = min(len, response.size - *offset); - if (copy_to_user(buffer, response.data + *offset, to_read)) { - return -EFAULT; + return to_read; + } } - *offset += to_read; - - return to_read; + return -ENOENT; } +// write file data to RAM ssize_t vtfs_write(struct file* file, const char* buffer, size_t len, loff_t* offset) { // ----------------| RAM |--------------------- - // struct vtfs_inode *found_inode; - // struct vtfs_dentry *found_dentry; - // struct inode *file_inode = file->f_inode; - // struct list_head *pos; - // void *new_data; - // ssize_t new_size; - - // list_for_each(pos, &vtfs_sb.dentries) { - // found_dentry = list_entry(pos, struct vtfs_dentry, list); - // found_inode = found_dentry->d_inode; - - // if (found_dentry->d_inode->ino == file_inode->i_ino) { - // new_size = max(found_inode->i_size, *offset + len); + struct vtfs_inode* found_inode; + struct vtfs_dentry* found_dentry; + struct inode* file_inode = file->f_inode; + struct list_head* pos; + void* new_data; + ssize_t new_size; - // if (copy_from_user(found_inode->i_data + *offset, buffer, len)) { - // return -EFAULT; - // } + list_for_each(pos, &vtfs_sb.dentries) { + found_dentry = list_entry(pos, struct vtfs_dentry, list); + found_inode = found_dentry->d_inode; - // found_inode->i_size = new_size; + if (found_dentry->d_inode->ino == file_inode->i_ino) { + new_size = max(found_inode->i_size, *offset + len); - // *offset += len; - - // return len; - // } - // } - - // return -ENOENT; + if (copy_from_user(found_inode->i_data + *offset, buffer, len)) { + return -EFAULT; + } - // ----------------| NET |--------------------- - if (*offset >= 2048) { - return 0; - } + found_inode->i_size = new_size; - len = min(len, 2047); + *offset += len; - char data[2048]; - if (copy_from_user(data, buffer, len) != 0) { - return 0; - } - data[len] = 0; - - char inode_str[11]; - (void)snprintf(inode_str, sizeof(inode_str), "%d", file->f_path.dentry->d_inode->i_ino); - - char data_enc[2047 * 3 + 1]; - encode(data, data_enc); - - int64_t code; - struct write_response response; - if ((code = vtfs_http_call( - "admin", - "write", - (void*)&response, - sizeof(response), - 2, - "inode", - inode_str, - "data", - data_enc - )) != 0) { - printk(KERN_ERR "networkfs_http_call error code %lld\n", code); - return -1; + return len; + } } - *offset += len; - - return len; + return -ENOENT; } struct file_operations vtfs_dir_ops = { @@ -914,15 +621,7 @@ struct dentry* vtfs_mount( } int init(void) { - struct max_ino_response response; - int64_t code = vtfs_http_call("admin", "max_ino", (void*)&response, sizeof(response), 0); - if ((code) != 0) { - printk(KERN_ERR "vtfs_init error code %lld\n", code); - return -1; - } - - next_ino = response.ino; - + next_ino = ROOT_INODE_INO; return 0; } From 713dbebab7068d3279996b6788e9a97d0dbeefd1 Mon Sep 17 00:00:00 2001 From: worthant Date: Fri, 27 Dec 2024 06:35:12 +0300 Subject: [PATCH 3/4] :ledger: docs(readme): Add raid0 additional task doc --- README.md | 42 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index a5eb417..09d2b18 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ # Форк учебной ОС Xv6 для ITMO CSE > [!IMPORTANT] -> Этот репозиторий **содержит решения** лабораторных работ. Он -> создан исключительно для ревью их качества практиком курса Операционных систем -> ITMO CSE. +> Этот репозиторий **содержит решения** лабораторных работ. Он создан +> исключительно для ревью их качества практиком курса Операционных систем ITMO +> CSE. ## Начало работы @@ -25,7 +25,7 @@ Сделать утилиту для вывода системной информации => `sysinfo` -- executing `dump2tests`: +### executing `dump2tests`: ```fish $ dump2tests > /dev &; sysinfo @@ -38,7 +38,7 @@ System info: Number of open files: 8 ``` -- idle +### idle ```fish $ sysinfo @@ -46,3 +46,35 @@ System info: Number of procs: 3 Number of open files: 1 ``` + +## Доп. задание к лаб.4 - `RAID0` + +### Аппаратная реализация на x86_64 + +Два HDD диска от Seagate подключаются по SATA3 к материнской плате Х99 v205 на сокете LGA 2011v3. Операции производятся процессором Xeon Е5-2630v3, на плате установлено 32 гигабайта ECC DDR4 оперативной памяти, работающей на частоте 2400 Мгц. + +|![image](https://github.com/user-attachments/assets/57bb1f4a-2043-4623-9db1-47a025b8443a)| +|-| + +### Теория + +RAID 0 работает так: данные делятся на страйпы (обычно 64KB) и записываются поочерёдно на два диска: первый блок на диск A, второй на диск B и так далее. При записи оба диска работают параллельно, что увеличивает пропускную способность. Прирост есть только в скорости записи (и иногда последовательного чтения), так как данные записываются/читаются одновременно с двух дисков. Избыточности нет — выход из строя одного диска уничтожает все данные. + +|![image](https://github.com/user-attachments/assets/53618427-77aa-4d69-a55e-fef2c51cab24)| +|-| + + +### Программная реализация массива raid0 на ОС windows 10 + +|![image_2024-12-19_23-14-41](https://github.com/user-attachments/assets/63b5521a-48b8-4ecb-8c26-877f5eb1985f)| +|-| + +### Профилирование + +> [!NOTE] +> Видим жёский прирост на записи, спасибо raid0 + +|jbod (just hdd)|raid0 array| +|-|-| +|![image_2024-12-19_23-18-47](https://github.com/user-attachments/assets/9b814864-d75f-48c5-a412-aa5b93628c69)|![image_2024-12-19_23-11-58](https://github.com/user-attachments/assets/da892e34-ef42-4ea1-adfd-2005d834f788)| + From 5550fa9eb31e4500bada0d0d480f1c874e06e433 Mon Sep 17 00:00:00 2001 From: worthant Date: Wed, 1 Jul 2026 20:23:05 +0300 Subject: [PATCH 4/4] :wrench: fix(ci): restore mkfs dropped by refactor; fix .gitignore --- xv6-os/.gitignore | 2 +- xv6-os/mkfs/mkfs.c | 303 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 304 insertions(+), 1 deletion(-) create mode 100644 xv6-os/mkfs/mkfs.c diff --git a/xv6-os/.gitignore b/xv6-os/.gitignore index c19de7b..23c9fdf 100644 --- a/xv6-os/.gitignore +++ b/xv6-os/.gitignore @@ -11,7 +11,7 @@ entryother initcode initcode.out kernelmemfs -mkfs +mkfs/mkfs kernel/kernel user/usys.S .gdbinit diff --git a/xv6-os/mkfs/mkfs.c b/xv6-os/mkfs/mkfs.c new file mode 100644 index 0000000..f39983d --- /dev/null +++ b/xv6-os/mkfs/mkfs.c @@ -0,0 +1,303 @@ +#include +#include +#include +#include +#include +#include + +#define stat xv6_stat // avoid clash with host struct stat +#include "kernel/types.h" +#include "kernel/fs.h" +#include "kernel/stat.h" +#include "kernel/param.h" + +#ifndef static_assert +#define static_assert(a, b) do { switch (0) case 0: case (a): ; } while (0) +#endif + +#define NINODES 200 + +// Disk layout: +// [ boot block | sb block | log | inode blocks | free bit map | data blocks ] + +int nbitmap = FSSIZE/BPB + 1; +int ninodeblocks = NINODES / IPB + 1; +int nlog = LOGSIZE; +int nmeta; // Number of meta blocks (boot, sb, nlog, inode, bitmap) +int nblocks; // Number of data blocks + +int fsfd; +struct superblock sb; +char zeroes[BSIZE]; +uint freeinode = 1; +uint freeblock; + + +void balloc(int); +void wsect(uint, void*); +void winode(uint, struct dinode*); +void rinode(uint inum, struct dinode *ip); +void rsect(uint sec, void *buf); +uint ialloc(ushort type); +void iappend(uint inum, void *p, int n); +void die(const char *); + +// convert to riscv byte order +ushort +xshort(ushort x) +{ + ushort y; + uchar *a = (uchar*)&y; + a[0] = x; + a[1] = x >> 8; + return y; +} + +uint +xint(uint x) +{ + uint y; + uchar *a = (uchar*)&y; + a[0] = x; + a[1] = x >> 8; + a[2] = x >> 16; + a[3] = x >> 24; + return y; +} + +int +main(int argc, char *argv[]) +{ + int i, cc, fd; + uint rootino, inum, off; + struct dirent de; + char buf[BSIZE]; + struct dinode din; + + + static_assert(sizeof(int) == 4, "Integers must be 4 bytes!"); + + if(argc < 2){ + fprintf(stderr, "Usage: mkfs fs.img files...\n"); + exit(1); + } + + assert((BSIZE % sizeof(struct dinode)) == 0); + assert((BSIZE % sizeof(struct dirent)) == 0); + + fsfd = open(argv[1], O_RDWR|O_CREAT|O_TRUNC, 0666); + if(fsfd < 0) + die(argv[1]); + + // 1 fs block = 1 disk sector + nmeta = 2 + nlog + ninodeblocks + nbitmap; + nblocks = FSSIZE - nmeta; + + sb.magic = FSMAGIC; + sb.size = xint(FSSIZE); + sb.nblocks = xint(nblocks); + sb.ninodes = xint(NINODES); + sb.nlog = xint(nlog); + sb.logstart = xint(2); + sb.inodestart = xint(2+nlog); + sb.bmapstart = xint(2+nlog+ninodeblocks); + + printf("nmeta %d (boot, super, log blocks %u inode blocks %u, bitmap blocks %u) blocks %d total %d\n", + nmeta, nlog, ninodeblocks, nbitmap, nblocks, FSSIZE); + + freeblock = nmeta; // the first free block that we can allocate + + for(i = 0; i < FSSIZE; i++) + wsect(i, zeroes); + + memset(buf, 0, sizeof(buf)); + memmove(buf, &sb, sizeof(sb)); + wsect(1, buf); + + rootino = ialloc(T_DIR); + assert(rootino == ROOTINO); + + bzero(&de, sizeof(de)); + de.inum = xshort(rootino); + strcpy(de.name, "."); + iappend(rootino, &de, sizeof(de)); + + bzero(&de, sizeof(de)); + de.inum = xshort(rootino); + strcpy(de.name, ".."); + iappend(rootino, &de, sizeof(de)); + + for(i = 2; i < argc; i++){ + // get rid of "user/" + char *shortname; + if(strncmp(argv[i], "user/", 5) == 0) + shortname = argv[i] + 5; + else + shortname = argv[i]; + + assert(index(shortname, '/') == 0); + + if((fd = open(argv[i], 0)) < 0) + die(argv[i]); + + // Skip leading _ in name when writing to file system. + // The binaries are named _rm, _cat, etc. to keep the + // build operating system from trying to execute them + // in place of system binaries like rm and cat. + if(shortname[0] == '_') + shortname += 1; + + assert(strlen(shortname) <= DIRSIZ); + + inum = ialloc(T_FILE); + + bzero(&de, sizeof(de)); + de.inum = xshort(inum); + strncpy(de.name, shortname, DIRSIZ); + iappend(rootino, &de, sizeof(de)); + + while((cc = read(fd, buf, sizeof(buf))) > 0) + iappend(inum, buf, cc); + + close(fd); + } + + // fix size of root inode dir + rinode(rootino, &din); + off = xint(din.size); + off = ((off/BSIZE) + 1) * BSIZE; + din.size = xint(off); + winode(rootino, &din); + + balloc(freeblock); + + exit(0); +} + +void +wsect(uint sec, void *buf) +{ + if(lseek(fsfd, sec * BSIZE, 0) != sec * BSIZE) + die("lseek"); + if(write(fsfd, buf, BSIZE) != BSIZE) + die("write"); +} + +void +winode(uint inum, struct dinode *ip) +{ + char buf[BSIZE]; + uint bn; + struct dinode *dip; + + bn = IBLOCK(inum, sb); + rsect(bn, buf); + dip = ((struct dinode*)buf) + (inum % IPB); + *dip = *ip; + wsect(bn, buf); +} + +void +rinode(uint inum, struct dinode *ip) +{ + char buf[BSIZE]; + uint bn; + struct dinode *dip; + + bn = IBLOCK(inum, sb); + rsect(bn, buf); + dip = ((struct dinode*)buf) + (inum % IPB); + *ip = *dip; +} + +void +rsect(uint sec, void *buf) +{ + if(lseek(fsfd, sec * BSIZE, 0) != sec * BSIZE) + die("lseek"); + if(read(fsfd, buf, BSIZE) != BSIZE) + die("read"); +} + +uint +ialloc(ushort type) +{ + uint inum = freeinode++; + struct dinode din; + + bzero(&din, sizeof(din)); + din.type = xshort(type); + din.nlink = xshort(1); + din.size = xint(0); + winode(inum, &din); + return inum; +} + +void +balloc(int used) +{ + uchar buf[BSIZE]; + int i; + + printf("balloc: first %d blocks have been allocated\n", used); + assert(used < BPB); + bzero(buf, BSIZE); + for(i = 0; i < used; i++){ + buf[i/8] = buf[i/8] | (0x1 << (i%8)); + } + printf("balloc: write bitmap block at sector %d\n", sb.bmapstart); + wsect(sb.bmapstart, buf); +} + +#define min(a, b) ((a) < (b) ? (a) : (b)) + +void +iappend(uint inum, void *xp, int n) +{ + char *p = (char*)xp; + uint fbn, off, n1; + struct dinode din; + char buf[BSIZE]; + uint indirect[NINDIRECT]; + uint x; + + rinode(inum, &din); + off = xint(din.size); + // printf("append inum %d at off %d sz %d\n", inum, off, n); + while(n > 0){ + fbn = off / BSIZE; + assert(fbn < MAXFILE); + if(fbn < NDIRECT){ + if(xint(din.addrs[fbn]) == 0){ + din.addrs[fbn] = xint(freeblock++); + } + x = xint(din.addrs[fbn]); + } else { + if(xint(din.addrs[NDIRECT]) == 0){ + din.addrs[NDIRECT] = xint(freeblock++); + } + rsect(xint(din.addrs[NDIRECT]), (char*)indirect); + if(indirect[fbn - NDIRECT] == 0){ + indirect[fbn - NDIRECT] = xint(freeblock++); + wsect(xint(din.addrs[NDIRECT]), (char*)indirect); + } + x = xint(indirect[fbn-NDIRECT]); + } + n1 = min(n, (fbn + 1) * BSIZE - off); + rsect(x, buf); + bcopy(p, buf + off - (fbn * BSIZE), n1); + wsect(x, buf); + n -= n1; + off += n1; + p += n1; + } + din.size = xint(off); + winode(inum, &din); +} + +void +die(const char *s) +{ + perror(s); + exit(1); +}