Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
4 changes: 4 additions & 0 deletions kernel/buf.h
Original file line number Diff line number Diff line change
@@ -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?
Expand All @@ -10,3 +13,4 @@ struct buf {
uchar data[BSIZE];
};

#endif
2 changes: 2 additions & 0 deletions kernel/file.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#include "sleeplock.h"

struct file {
enum { FD_NONE, FD_PIPE, FD_INODE, FD_DEVICE } type;
int ref; // reference count
Expand Down
64 changes: 64 additions & 0 deletions kernel/fs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
7 changes: 6 additions & 1 deletion kernel/fs.h
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -58,3 +62,4 @@ struct dirent {
char name[DIRSIZ];
};

#endif
4 changes: 4 additions & 0 deletions kernel/sleeplock.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
#ifndef SLEEPLOCK_H
#define SLEEPLOCK_H

// Long-term locks for processes
struct sleeplock {
uint locked; // Is the lock held?
Expand All @@ -8,3 +11,4 @@ struct sleeplock {
int pid; // Process holding lock
};

#endif
2 changes: 2 additions & 0 deletions kernel/syscall.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
Expand Down
1 change: 1 addition & 0 deletions kernel/syscall.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@
#define SYS_link 19
#define SYS_mkdir 20
#define SYS_close 21
#define SYS_statvfs 26
32 changes: 32 additions & 0 deletions kernel/sysproc.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@
#include "memlayout.h"
#include "spinlock.h"
#include "proc.h"
#include "fs.h"
#include "file.h"
#include "user/stat.h"

extern struct superblock sb;

uint64
sys_exit(void)
Expand Down Expand Up @@ -89,3 +94,30 @@ sys_uptime(void)
release(&tickslock);
return xticks;
}

/**
* sys_statvfs - system call to gather filesystem statistics
* @returns 0 on success, -1 on failure
*/
uint64 sys_statvfs(void) {
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();

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;
}
37 changes: 37 additions & 0 deletions user/df.c
Original file line number Diff line number Diff line change
@@ -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;
}
12 changes: 12 additions & 0 deletions user/stat.h
Original file line number Diff line number Diff line change
@@ -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
3 changes: 3 additions & 0 deletions user/user.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
struct stat;

typedef unsigned int uint;

// system calls
int fork(void);
int exit(int) __attribute__((noreturn));
Expand Down Expand Up @@ -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*);
1 change: 1 addition & 0 deletions user/usys.pl
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,4 @@ sub entry {
entry("sbrk");
entry("sleep");
entry("uptime");
entry("statvfs");