1
This commit is contained in:
parent
212617e63f
commit
42839e6cd9
81
libfs.c
81
libfs.c
@ -1,7 +1,3 @@
|
||||
/*
|
||||
* Custom Filesystem Module - Implements the described behavior for "books" and "authors" directories.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/fs.h>
|
||||
@ -13,6 +9,7 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/hashtable.h>
|
||||
#include <linux/fs_context.h>
|
||||
#include <linux/statfs.h>
|
||||
|
||||
#define FS_MAGIC 0x20240615
|
||||
#define BOOKS_MODE 01777
|
||||
@ -32,7 +29,7 @@ struct link_entry {
|
||||
struct inode *target;
|
||||
};
|
||||
|
||||
DEFINE_HASHTABLE(link_table, 6); // 64 buckets
|
||||
DEFINE_HASHTABLE(link_table, 6);
|
||||
|
||||
static void remove_links_to_inode(struct inode *inode) {
|
||||
struct link_entry *entry;
|
||||
@ -40,6 +37,7 @@ static void remove_links_to_inode(struct inode *inode) {
|
||||
int bkt;
|
||||
hash_for_each_safe(link_table, bkt, tmp, entry, node) {
|
||||
if (entry->target == inode) {
|
||||
printk(KERN_INFO "customfs: removing hardlink to inode %lu\n", inode->i_ino);
|
||||
d_delete(entry->link);
|
||||
hash_del(&entry->node);
|
||||
kfree(entry);
|
||||
@ -57,6 +55,16 @@ static void fs_evict_inode(struct inode *inode) {
|
||||
clear_inode(inode);
|
||||
}
|
||||
|
||||
static int fs_statfs(struct dentry *dentry, struct kstatfs *buf) {
|
||||
buf->f_type = FS_MAGIC;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct super_operations fs_ops = {
|
||||
.evict_inode = fs_evict_inode,
|
||||
.statfs = fs_statfs,
|
||||
};
|
||||
|
||||
static ssize_t books_file_read(struct file *file, char __user *buf, size_t len, loff_t *ppos) {
|
||||
return simple_read_from_buffer(buf, len, ppos, file->private_data, PAGE_SIZE);
|
||||
}
|
||||
@ -78,20 +86,18 @@ static const struct inode_operations books_file_iops = {
|
||||
|
||||
static const struct inode_operations author_subdir_iops;
|
||||
|
||||
static struct dentry *author_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) {
|
||||
return simple_lookup(dir, dentry, flags);
|
||||
}
|
||||
|
||||
static int author_mkdir(struct user_namespace *ns, struct inode *dir, struct dentry *dentry, umode_t mode) {
|
||||
struct inode *inode;
|
||||
inode = new_inode(dir->i_sb);
|
||||
struct inode *inode = new_inode(dir->i_sb);
|
||||
if (!inode)
|
||||
return -ENOMEM;
|
||||
inode->i_ino = get_next_ino();
|
||||
inode_init_owner(ns, inode, dir, S_IFDIR | AUTHOR_SUBDIR_MODE);
|
||||
inode_init_owner(&init_user_ns, inode, dir, S_IFDIR | AUTHOR_SUBDIR_MODE);
|
||||
inode->i_op = &author_subdir_iops;
|
||||
inode->i_fop = &simple_dir_operations;
|
||||
inc_nlink(inode);
|
||||
inc_nlink(dir);
|
||||
d_add(dentry, inode);
|
||||
printk(KERN_INFO "customfs: created author subdir '%s'\n", dentry->d_name.name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -106,22 +112,20 @@ static int author_link(struct dentry *old_dentry, struct inode *dir, struct dent
|
||||
entry->link = dget(new_dentry);
|
||||
entry->target = inode;
|
||||
hash_add(link_table, &entry->node, inode->i_ino);
|
||||
printk(KERN_INFO "customfs: created hardlink '%s' to inode %lu\n",
|
||||
new_dentry->d_name.name, inode->i_ino);
|
||||
}
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct inode_operations author_subdir_iops = {
|
||||
.lookup = author_lookup,
|
||||
.lookup = simple_lookup,
|
||||
.mkdir = author_mkdir,
|
||||
.rmdir = simple_rmdir,
|
||||
.link = author_link,
|
||||
};
|
||||
|
||||
static const struct super_operations fs_ops = {
|
||||
.evict_inode = fs_evict_inode,
|
||||
};
|
||||
|
||||
static struct inode *fs_make_inode(struct super_block *sb, umode_t mode) {
|
||||
struct inode *inode = new_inode(sb);
|
||||
if (!inode)
|
||||
@ -131,9 +135,10 @@ static struct inode *fs_make_inode(struct super_block *sb, umode_t mode) {
|
||||
inode->i_sb = sb;
|
||||
inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
|
||||
|
||||
if (S_ISDIR(mode) && !inode->i_op) {
|
||||
if (S_ISDIR(mode)) {
|
||||
inode->i_op = &simple_dir_inode_operations;
|
||||
inode->i_fop = &simple_dir_operations;
|
||||
inc_nlink(inode);
|
||||
} else if (S_ISREG(mode)) {
|
||||
inode->i_fop = &books_file_fops;
|
||||
inode->i_op = &books_file_iops;
|
||||
@ -159,33 +164,55 @@ static int fs_fill_super(struct super_block *sb, void *data, int silent) {
|
||||
if (!root_dentry)
|
||||
return -ENOMEM;
|
||||
|
||||
sb->s_root = root_dentry;
|
||||
|
||||
books_inode = fs_make_inode(sb, S_IFDIR | BOOKS_MODE);
|
||||
if (!books_inode)
|
||||
return -ENOMEM;
|
||||
goto out_root;
|
||||
books_inode->i_op = &simple_dir_inode_operations;
|
||||
books_inode->i_fop = &simple_dir_operations;
|
||||
books_inode->i_mode |= S_IWUSR | S_IWGRP | S_IWOTH;
|
||||
inc_nlink(books_inode);
|
||||
books_dentry = d_alloc_name(root_dentry, "books");
|
||||
if (!books_dentry)
|
||||
return -ENOMEM;
|
||||
goto out_books;
|
||||
d_add(books_dentry, books_inode);
|
||||
d_rehash(books_dentry);
|
||||
printk(KERN_INFO "customfs: 'books' directory created\n");
|
||||
|
||||
authors_inode = fs_make_inode(sb, S_IFDIR | AUTHORS_MODE);
|
||||
if (!authors_inode)
|
||||
return -ENOMEM;
|
||||
goto out_books_dentry;
|
||||
authors_inode->i_op = &author_subdir_iops;
|
||||
inc_nlink(authors_inode);
|
||||
authors_dentry = d_alloc_name(root_dentry, "authors");
|
||||
if (!authors_dentry)
|
||||
return -ENOMEM;
|
||||
authors_inode->i_op = &author_subdir_iops;
|
||||
goto out_authors;
|
||||
d_add(authors_dentry, authors_inode);
|
||||
d_rehash(authors_dentry);
|
||||
printk(KERN_INFO "customfs: 'authors' directory created\n");
|
||||
|
||||
sb->s_root = root_dentry;
|
||||
|
||||
printk(KERN_INFO "customfs: fill_super completed\n");
|
||||
printk(KERN_INFO "customfs: root inode=%lu\n", root_inode->i_ino);
|
||||
printk(KERN_INFO "customfs: books inode=%lu\n", books_inode->i_ino);
|
||||
printk(KERN_INFO "customfs: authors inode=%lu\n", authors_inode->i_ino);
|
||||
|
||||
return 0;
|
||||
|
||||
out_authors:
|
||||
iput(authors_inode);
|
||||
out_books_dentry:
|
||||
dput(books_dentry);
|
||||
out_books:
|
||||
iput(books_inode);
|
||||
out_root:
|
||||
dput(root_dentry);
|
||||
iput(root_inode);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static struct dentry *fs_mount(struct file_system_type *type, int flags,
|
||||
const char *dev, void *data) {
|
||||
printk(KERN_INFO "customfs: mounting\n");
|
||||
return mount_nodev(type, flags, data, fs_fill_super);
|
||||
}
|
||||
|
||||
@ -198,11 +225,13 @@ static struct file_system_type fs_type = {
|
||||
|
||||
static int __init fs_init(void) {
|
||||
hash_init(link_table);
|
||||
printk(KERN_INFO "customfs: module loaded\n");
|
||||
return register_filesystem(&fs_type);
|
||||
}
|
||||
|
||||
static void __exit fs_exit(void) {
|
||||
unregister_filesystem(&fs_type);
|
||||
printk(KERN_INFO "customfs: module unloaded\n");
|
||||
}
|
||||
|
||||
module_init(fs_init);
|
||||
|
23
restart.bash
23
restart.bash
@ -1,21 +1,12 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
# Убить все процессы, использующие /mnt/test
|
||||
sudo fuser -km /mnt/test || true
|
||||
sudo umount /mnt/customfs 2>/dev/null || true
|
||||
sudo rmmod libfs 2>/dev/null || true
|
||||
|
||||
# Подождать, пока умрут
|
||||
sleep 0.5
|
||||
make
|
||||
|
||||
# Умонтировать
|
||||
sudo umount /mnt/test || true
|
||||
|
||||
# Выгрузить модуль
|
||||
sudo rmmod statsfs || true
|
||||
|
||||
# Подождать, пока освободится
|
||||
sleep 0.5
|
||||
|
||||
# Вставить модуль и смонтировать
|
||||
sudo insmod statsfs.ko
|
||||
sudo mount -t libfs none /mnt/test
|
||||
sudo insmod libfs.ko
|
||||
sudo mount -t customfs none /mnt/customfs
|
||||
ls -l /mnt/customfs
|
||||
|
Loading…
x
Reference in New Issue
Block a user