From 378a65a0c14603813738df722c9b50afbdc5ac67 Mon Sep 17 00:00:00 2001 From: Maximiliano Villarreal-Blozis Date: Sun, 29 Sep 2024 13:13:00 -0700 Subject: [PATCH 1/5] added entry for the statvfs sys call --- kernel/syscall.h | 1 + kernel/sysproc.c | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/kernel/syscall.h b/kernel/syscall.h index bc5f356..e483bf1 100644 --- a/kernel/syscall.h +++ b/kernel/syscall.h @@ -20,3 +20,4 @@ #define SYS_link 19 #define SYS_mkdir 20 #define SYS_close 21 +#define SYS_statvfs 26 diff --git a/kernel/sysproc.c b/kernel/sysproc.c index 1de184e..549779c 100644 --- a/kernel/sysproc.c +++ b/kernel/sysproc.c @@ -5,6 +5,9 @@ #include "memlayout.h" #include "spinlock.h" #include "proc.h" +#include "fs.h" +#include "file.h" +#include "statvfs.h" uint64 sys_exit(void) @@ -89,3 +92,35 @@ sys_uptime(void) release(&tickslock); return xticks; } + +/** + * Fills the given statvfs structure with filesystem statistics. + * + * @param stats Pointer to a statvfs structure that will be populated with: + * - f_blocks: Total number of blocks. + * - f_bfree: Free blocks. + * - f_bavail: Free blocks available to non-superusers. + * - f_files: Total number of inodes. + * - f_ffree: Free inodes. + * - f_frsize: Block size (set to 512 bytes). + * + * Helper functions bmap_free_blocks() and free_inodes() are used to fetch free blocks and inodes. + */ +void get_fs_stats(struct statvfs *stats) { + struct superblock *sb = &sb; + + stats->f_blocks = sb->nblocks; + stats->f_bfree = bmap_free_blocks(); + stats->f_bavail = stats->f_bfree; + + stats->f_files = sb->ninodes; + stats->f_ffree = free_inodes(); + + stats->f_frsize = 512; +} + +uint64 sys_statvfs(void) { + struct statvfs stats; + get_fs_stats(&stats); + return (uint64)&stats; +} From 12ee89d6e0db86753a7a5a377b98afaa4ce71114 Mon Sep 17 00:00:00 2001 From: Maximiliano Villarreal-Blozis Date: Sun, 29 Sep 2024 13:14:51 -0700 Subject: [PATCH 2/5] added prototype for statvfs --- kernel/syscall.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kernel/syscall.c b/kernel/syscall.c index ed65409..d205bb6 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -101,6 +101,7 @@ extern uint64 sys_unlink(void); extern uint64 sys_link(void); extern uint64 sys_mkdir(void); extern uint64 sys_close(void); +extern uint64 sys_statvfs(void); // An array mapping syscall numbers from syscall.h // to the function that handles the system call. @@ -126,6 +127,7 @@ static uint64 (*syscalls[])(void) = { [SYS_link] sys_link, [SYS_mkdir] sys_mkdir, [SYS_close] sys_close, +[SYS_statvfs] sys_statvfs, }; void From a6def593d809e34d979cbd393cf26cae7870df86 Mon Sep 17 00:00:00 2001 From: Maximiliano Villarreal-Blozis Date: Sun, 29 Sep 2024 13:24:55 -0700 Subject: [PATCH 3/5] refactored sys call in sysproc.c to work with helper functions --- kernel/sysproc.c | 53 +++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/kernel/sysproc.c b/kernel/sysproc.c index 549779c..1b5e0f4 100644 --- a/kernel/sysproc.c +++ b/kernel/sysproc.c @@ -7,7 +7,10 @@ #include "proc.h" #include "fs.h" #include "file.h" -#include "statvfs.h" +#include "stat.h" + +static int bmap_free_blocks(void); +static int free_inodes(void); uint64 sys_exit(void) @@ -94,33 +97,27 @@ sys_uptime(void) } /** - * Fills the given statvfs structure with filesystem statistics. - * - * @param stats Pointer to a statvfs structure that will be populated with: - * - f_blocks: Total number of blocks. - * - f_bfree: Free blocks. - * - f_bavail: Free blocks available to non-superusers. - * - f_files: Total number of inodes. - * - f_ffree: Free inodes. - * - f_frsize: Block size (set to 512 bytes). - * - * Helper functions bmap_free_blocks() and free_inodes() are used to fetch free blocks and inodes. + * sys_statvfs - system call to gather filesystem statistics + * @returns total_blocks, free_blocks, used_blocks, total_inodes, free_inodes */ -void get_fs_stats(struct statvfs *stats) { - struct superblock *sb = &sb; - - stats->f_blocks = sb->nblocks; - stats->f_bfree = bmap_free_blocks(); - stats->f_bavail = stats->f_bfree; - - stats->f_files = sb->ninodes; - stats->f_ffree = free_inodes(); - - stats->f_frsize = 512; -} - uint64 sys_statvfs(void) { - struct statvfs stats; - get_fs_stats(&stats); - return (uint64)&stats; + struct { + uint total_blocks; + uint free_blocks; + uint used_blocks; + uint total_inodes; + uint free_inodes; + } stats; + + stats.total_blocks = sb.nblocks; + stats.free_blocks = bmap_free_blocks(); + stats.used_blocks = stats.total_blocks - stats.free_blocks; + stats.total_inodes = sb.ninodes; + stats.free_inodes = free_inodes(); + + if (argptr(0, (void*)&stats, sizeof(stats)) < 0) { + return -1; + } + + return 0; } From e7cb0740b59809881ec61d69ca9341b86a7b22d1 Mon Sep 17 00:00:00 2001 From: Maximiliano Villarreal-Blozis Date: Sun, 29 Sep 2024 14:06:22 -0700 Subject: [PATCH 4/5] added entry for new sys call --- Makefile | 1 + kernel/buf.h | 4 +++ kernel/file.h | 2 ++ kernel/fs.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++ kernel/fs.h | 7 ++++- kernel/sleeplock.h | 4 +++ kernel/sysproc.c | 24 ++++++++--------- user/user.h | 3 +++ user/usys.pl | 1 + 9 files changed, 97 insertions(+), 13 deletions(-) diff --git a/Makefile b/Makefile index 2584e4a..c954e41 100644 --- a/Makefile +++ b/Makefile @@ -132,6 +132,7 @@ UPROGS=\ $U/_grind\ $U/_wc\ $U/_zombie\ + $U/_df\ fs.img: mkfs/mkfs README.md $(UPROGS) mkfs/mkfs fs.img README.md $(UPROGS) diff --git a/kernel/buf.h b/kernel/buf.h index 4616e9e..5a20510 100644 --- a/kernel/buf.h +++ b/kernel/buf.h @@ -1,3 +1,6 @@ +#ifndef BUF_H +#define BUF_H + struct buf { int valid; // has data been read from disk? int disk; // does disk "own" buf? @@ -10,3 +13,4 @@ struct buf { uchar data[BSIZE]; }; +#endif diff --git a/kernel/file.h b/kernel/file.h index b076d1d..6f2926f 100644 --- a/kernel/file.h +++ b/kernel/file.h @@ -1,3 +1,5 @@ +#include "sleeplock.h" + struct file { enum { FD_NONE, FD_PIPE, FD_INODE, FD_DEVICE } type; int ref; // reference count diff --git a/kernel/fs.c b/kernel/fs.c index c6bab15..119ecb8 100644 --- a/kernel/fs.c +++ b/kernel/fs.c @@ -695,3 +695,67 @@ nameiparent(char *path, char *name) { return namex(path, 1, name); } + +#include "fs.h" +#include "buf.h" + +/** + * bmap_isfree - Check if a block is free by inspecting the block bitmap. + * @param blockno: The block number to check + * @returns 1 if the block is free, 0 if the block is allocated + */ +int bmap_isfree(int blockno) { + struct buf *bp; + int bmap_block; + int block_offset; + int bit_index; + + // Calculate which block in the bitmap we need to check + bmap_block = blockno / (BSIZE * 8); // Each block in bitmap covers (BSIZE * 8) blocks + block_offset = blockno % (BSIZE * 8); // Offset within the block + bit_index = block_offset % 8; // Which bit in the byte to check + + // Read the block bitmap into a buffer + bp = bread(ROOTDEV, sb.bmapstart + bmap_block); + + // Check the relevant bit in the byte + int is_free = !(bp->data[block_offset / 8] & (1 << bit_index)); // 0 means free + + brelse(bp); // Release the buffer after use + return is_free; +} + + +/** + * bmap_free_blocks - Count the number of free blocks by inspecting the block bitmap. + * @returns the number of free blocks + */ +int bmap_free_blocks(void) { + int free_blocks = 0; + + for (int b = 0; b < sb.nblocks; b++) { + if (bmap_isfree(b)) { + free_blocks++; + } + } + + return free_blocks; +} + +/** + * free_inodes - Count the number of free inodes by inspecting the inode bitmap. + * @returns the number of free inodes + */ +int free_inodes(void) { + int free_inodes = 0; + + for (int i = 1; i < sb.ninodes; i++) { + struct inode *ip = iget(ROOTDEV, i); + if (ip->type == 0) { + free_inodes++; + } + iput(ip); + } + + return free_inodes; +} diff --git a/kernel/fs.h b/kernel/fs.h index 139dcc9..7fd35d8 100644 --- a/kernel/fs.h +++ b/kernel/fs.h @@ -1,6 +1,10 @@ +#ifndef FS_H +#define FS_H + // On-disk file system format. // Both the kernel and user programs use this header file. - +int bmap_free_blocks(void); +int free_inodes(void); #define ROOTINO 1 // root i-number #define BSIZE 1024 // block size @@ -58,3 +62,4 @@ struct dirent { char name[DIRSIZ]; }; +#endif diff --git a/kernel/sleeplock.h b/kernel/sleeplock.h index 110e6f3..e827ad1 100644 --- a/kernel/sleeplock.h +++ b/kernel/sleeplock.h @@ -1,3 +1,6 @@ +#ifndef SLEEPLOCK_H +#define SLEEPLOCK_H + // Long-term locks for processes struct sleeplock { uint locked; // Is the lock held? @@ -8,3 +11,4 @@ struct sleeplock { int pid; // Process holding lock }; +#endif diff --git a/kernel/sysproc.c b/kernel/sysproc.c index 1b5e0f4..33e188b 100644 --- a/kernel/sysproc.c +++ b/kernel/sysproc.c @@ -7,10 +7,9 @@ #include "proc.h" #include "fs.h" #include "file.h" -#include "stat.h" +#include "user/stat.h" -static int bmap_free_blocks(void); -static int free_inodes(void); +extern struct superblock sb; uint64 sys_exit(void) @@ -98,26 +97,27 @@ sys_uptime(void) /** * sys_statvfs - system call to gather filesystem statistics - * @returns total_blocks, free_blocks, used_blocks, total_inodes, free_inodes + * @returns 0 on success, -1 on failure */ uint64 sys_statvfs(void) { - struct { - uint total_blocks; - uint free_blocks; - uint used_blocks; - uint total_inodes; - uint free_inodes; - } stats; + struct statvfs stats; + // Fill the stats structure with filesystem information stats.total_blocks = sb.nblocks; stats.free_blocks = bmap_free_blocks(); stats.used_blocks = stats.total_blocks - stats.free_blocks; stats.total_inodes = sb.ninodes; stats.free_inodes = free_inodes(); - if (argptr(0, (void*)&stats, sizeof(stats)) < 0) { + uint64 addr; + + argaddr(0,&addr); + + // Copy the stats structure to the user space + if (copyout(myproc()->pagetable, addr, (char *)&stats, sizeof(stats)) < 0) { return -1; } + // Return success return 0; } diff --git a/user/user.h b/user/user.h index 2e6fc55..349c3ca 100644 --- a/user/user.h +++ b/user/user.h @@ -1,5 +1,7 @@ struct stat; +typedef unsigned int uint; + // system calls int fork(void); int exit(int) __attribute__((noreturn)); @@ -41,3 +43,4 @@ void free(void*); int atoi(const char*); int memcmp(const void *, const void *, uint); void *memcpy(void *, const void *, uint); +int statvfs(void*); diff --git a/user/usys.pl b/user/usys.pl index 01e426e..2a73774 100755 --- a/user/usys.pl +++ b/user/usys.pl @@ -36,3 +36,4 @@ sub entry { entry("sbrk"); entry("sleep"); entry("uptime"); +entry("statvfs"); From 867a205701200aa7a0f98aa1f9d8ff43a06b354b Mon Sep 17 00:00:00 2001 From: Maximiliano Villarreal-Blozis Date: Tue, 1 Oct 2024 09:50:09 -0700 Subject: [PATCH 5/5] forgot to commit user space program --- user/df.c | 37 +++++++++++++++++++++++++++++++++++++ user/stat.h | 12 ++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 user/df.c create mode 100644 user/stat.h diff --git a/user/df.c b/user/df.c new file mode 100644 index 0000000..1f8c48f --- /dev/null +++ b/user/df.c @@ -0,0 +1,37 @@ +#include "user/user.h" +#include "user/stat.h" +#include "kernel/types.h" + + +int main(int argc, char *argv[]) { + struct statvfs stats; + int human_readable = 0; + int inode_usage = 0; + + for (int i = 1; i < argc; i++) { + if (strcmp(argv[i], "-h") == 0) { + human_readable = 1; + } else if (strcmp(argv[i], "-i") == 0) { + inode_usage = 1; + } + } + + if (statvfs(&stats) < 0) { + printf("Error: Failed to retrieve filesystem stats\n"); + exit(1); + } + + if (inode_usage) { + printf("Inodes: Total: %d, Free: %d\n", stats.total_inodes, stats.free_inodes); + } else { + if (human_readable) { + printf("Disk: Total: %dKB, Used: %dKB, Free: %dKB\n", + stats.total_blocks / 2, stats.used_blocks / 2, stats.free_blocks / 2); + } else { + printf("Disk: Total: %d blocks, Used: %d blocks, Free: %d blocks\n", + stats.total_blocks, stats.used_blocks, stats.free_blocks); + } + } + + return 0; +} diff --git a/user/stat.h b/user/stat.h new file mode 100644 index 0000000..df88f37 --- /dev/null +++ b/user/stat.h @@ -0,0 +1,12 @@ +#ifndef STAT_H +#define STAT_H + +struct statvfs { + unsigned int total_blocks; + unsigned int free_blocks; + unsigned int used_blocks; + unsigned int total_inodes; + unsigned int free_inodes; +}; + +#endif