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/init.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
@ -13,6 +9,7 @@
|
|||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/hashtable.h>
|
#include <linux/hashtable.h>
|
||||||
#include <linux/fs_context.h>
|
#include <linux/fs_context.h>
|
||||||
|
#include <linux/statfs.h>
|
||||||
|
|
||||||
#define FS_MAGIC 0x20240615
|
#define FS_MAGIC 0x20240615
|
||||||
#define BOOKS_MODE 01777
|
#define BOOKS_MODE 01777
|
||||||
@ -32,7 +29,7 @@ struct link_entry {
|
|||||||
struct inode *target;
|
struct inode *target;
|
||||||
};
|
};
|
||||||
|
|
||||||
DEFINE_HASHTABLE(link_table, 6); // 64 buckets
|
DEFINE_HASHTABLE(link_table, 6);
|
||||||
|
|
||||||
static void remove_links_to_inode(struct inode *inode) {
|
static void remove_links_to_inode(struct inode *inode) {
|
||||||
struct link_entry *entry;
|
struct link_entry *entry;
|
||||||
@ -40,6 +37,7 @@ static void remove_links_to_inode(struct inode *inode) {
|
|||||||
int bkt;
|
int bkt;
|
||||||
hash_for_each_safe(link_table, bkt, tmp, entry, node) {
|
hash_for_each_safe(link_table, bkt, tmp, entry, node) {
|
||||||
if (entry->target == inode) {
|
if (entry->target == inode) {
|
||||||
|
printk(KERN_INFO "customfs: removing hardlink to inode %lu\n", inode->i_ino);
|
||||||
d_delete(entry->link);
|
d_delete(entry->link);
|
||||||
hash_del(&entry->node);
|
hash_del(&entry->node);
|
||||||
kfree(entry);
|
kfree(entry);
|
||||||
@ -57,6 +55,16 @@ static void fs_evict_inode(struct inode *inode) {
|
|||||||
clear_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) {
|
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);
|
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 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) {
|
static int author_mkdir(struct user_namespace *ns, struct inode *dir, struct dentry *dentry, umode_t mode) {
|
||||||
struct inode *inode;
|
struct inode *inode = new_inode(dir->i_sb);
|
||||||
inode = new_inode(dir->i_sb);
|
|
||||||
if (!inode)
|
if (!inode)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
inode->i_ino = get_next_ino();
|
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_op = &author_subdir_iops;
|
||||||
inode->i_fop = &simple_dir_operations;
|
inode->i_fop = &simple_dir_operations;
|
||||||
|
inc_nlink(inode);
|
||||||
|
inc_nlink(dir);
|
||||||
d_add(dentry, inode);
|
d_add(dentry, inode);
|
||||||
|
printk(KERN_INFO "customfs: created author subdir '%s'\n", dentry->d_name.name);
|
||||||
return 0;
|
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->link = dget(new_dentry);
|
||||||
entry->target = inode;
|
entry->target = inode;
|
||||||
hash_add(link_table, &entry->node, inode->i_ino);
|
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;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct inode_operations author_subdir_iops = {
|
static const struct inode_operations author_subdir_iops = {
|
||||||
.lookup = author_lookup,
|
.lookup = simple_lookup,
|
||||||
.mkdir = author_mkdir,
|
.mkdir = author_mkdir,
|
||||||
.rmdir = simple_rmdir,
|
.rmdir = simple_rmdir,
|
||||||
.link = author_link,
|
.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) {
|
static struct inode *fs_make_inode(struct super_block *sb, umode_t mode) {
|
||||||
struct inode *inode = new_inode(sb);
|
struct inode *inode = new_inode(sb);
|
||||||
if (!inode)
|
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_sb = sb;
|
||||||
inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
|
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_op = &simple_dir_inode_operations;
|
||||||
inode->i_fop = &simple_dir_operations;
|
inode->i_fop = &simple_dir_operations;
|
||||||
|
inc_nlink(inode);
|
||||||
} else if (S_ISREG(mode)) {
|
} else if (S_ISREG(mode)) {
|
||||||
inode->i_fop = &books_file_fops;
|
inode->i_fop = &books_file_fops;
|
||||||
inode->i_op = &books_file_iops;
|
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)
|
if (!root_dentry)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
sb->s_root = root_dentry;
|
|
||||||
|
|
||||||
books_inode = fs_make_inode(sb, S_IFDIR | BOOKS_MODE);
|
books_inode = fs_make_inode(sb, S_IFDIR | BOOKS_MODE);
|
||||||
if (!books_inode)
|
if (!books_inode)
|
||||||
return -ENOMEM;
|
goto out_root;
|
||||||
books_inode->i_op = &simple_dir_inode_operations;
|
books_inode->i_op = &simple_dir_inode_operations;
|
||||||
books_inode->i_fop = &simple_dir_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");
|
books_dentry = d_alloc_name(root_dentry, "books");
|
||||||
if (!books_dentry)
|
if (!books_dentry)
|
||||||
return -ENOMEM;
|
goto out_books;
|
||||||
d_add(books_dentry, books_inode);
|
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);
|
authors_inode = fs_make_inode(sb, S_IFDIR | AUTHORS_MODE);
|
||||||
if (!authors_inode)
|
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");
|
authors_dentry = d_alloc_name(root_dentry, "authors");
|
||||||
if (!authors_dentry)
|
if (!authors_dentry)
|
||||||
return -ENOMEM;
|
goto out_authors;
|
||||||
authors_inode->i_op = &author_subdir_iops;
|
|
||||||
d_add(authors_dentry, authors_inode);
|
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;
|
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,
|
static struct dentry *fs_mount(struct file_system_type *type, int flags,
|
||||||
const char *dev, void *data) {
|
const char *dev, void *data) {
|
||||||
|
printk(KERN_INFO "customfs: mounting\n");
|
||||||
return mount_nodev(type, flags, data, fs_fill_super);
|
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) {
|
static int __init fs_init(void) {
|
||||||
hash_init(link_table);
|
hash_init(link_table);
|
||||||
|
printk(KERN_INFO "customfs: module loaded\n");
|
||||||
return register_filesystem(&fs_type);
|
return register_filesystem(&fs_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __exit fs_exit(void) {
|
static void __exit fs_exit(void) {
|
||||||
unregister_filesystem(&fs_type);
|
unregister_filesystem(&fs_type);
|
||||||
|
printk(KERN_INFO "customfs: module unloaded\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
module_init(fs_init);
|
module_init(fs_init);
|
||||||
|
23
restart.bash
23
restart.bash
@ -1,21 +1,12 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
# Убить все процессы, использующие /mnt/test
|
sudo umount /mnt/customfs 2>/dev/null || true
|
||||||
sudo fuser -km /mnt/test || true
|
sudo rmmod libfs 2>/dev/null || true
|
||||||
|
|
||||||
# Подождать, пока умрут
|
make
|
||||||
sleep 0.5
|
|
||||||
|
|
||||||
# Умонтировать
|
sudo insmod libfs.ko
|
||||||
sudo umount /mnt/test || true
|
sudo mount -t customfs none /mnt/customfs
|
||||||
|
ls -l /mnt/customfs
|
||||||
# Выгрузить модуль
|
|
||||||
sudo rmmod statsfs || true
|
|
||||||
|
|
||||||
# Подождать, пока освободится
|
|
||||||
sleep 0.5
|
|
||||||
|
|
||||||
# Вставить модуль и смонтировать
|
|
||||||
sudo insmod statsfs.ko
|
|
||||||
sudo mount -t libfs none /mnt/test
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user