Bill Strosberg wrote:
> I can see the appeal of this, but this would certainly incur a
> performance penalty (checking the name/inode) on every file operation
> done on the system. Would you not be better to write a daemon function
> to monitor the specific file, checking for alterations and performing
> whatever magic you wish on after the fact? This way no performance
> penalty is added to everything else using the file system.
>
> Sounds like you want whatever is happening to be transparent to the
> user. Or you don't want the user to see the magic performed.
>
> --
> Bill
I managed to write the following module and it works ok but needs to be
checked
for eventual bugs and to make the code robust:
Note that there is no overhead incurred for files that are not cloned; only
the cloned file
call to write is intercepted.
I appreciate any help to make the code robust and to complete what could be
missing
(ie. do I have to lock/unlock the inode before setting i_fop).
/*
* clone-1.c - intercept the write calls of a given file
* usage:
* > insmod clone.ko path=/tmp/test.dat
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/errno.h>
#include <linux/file.h>
#include <linux/highuid.h>
#include <linux/fs.h>
#include <linux/namei.h>
#include <linux/security.h>
#include <linux/syscalls.h>
#include <linux/pagemap.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Taoufik Dachraoui");
static char *path;
module_param(path, charp, 0000);
MODULE_PARM_DESC(path, "Path");
struct inode *inode;
struct file_operations *orig_fop;
struct file_operations *my_fop;
ssize_t my_write (struct file * filp, const char __user *buf, size_t len,
loff_t *ppos)
{
printk(KERN_INFO "my_write len=%d\n", len);
return orig_fop->write(filp, buf, len, ppos);
}
ssize_t my_aio_write (struct kiocb *iocb, const struct iovec *iov, unsigned
long nr_segs, loff_t pos)
{
printk(KERN_INFO "my_aio_write\n");
return orig_fop->aio_write(iocb, iov, nr_segs, pos);
}
static int __init clone_1_init(void)
//int init_module(void)
{
int error;
struct nameidata nd;
if (path==NULL) return 0;
error = path_lookup(path, LOOKUP_FOLLOW, &nd);
if (error) {
printk(KERN_INFO "Clone-1. Error %d\n", error);
return error;
}
inode=nd.path.dentry->d_inode;
printk(KERN_INFO "Clone-1. inode %lu\n", inode->i_ino);
// copy inode->i_fop into my_fop
my_fop=kmalloc(sizeof(*my_fop), GFP_KERNEL);
memcpy(my_fop, inode->i_fop,sizeof(*my_fop));
// set my fop functions
my_fop->write=my_write;
my_fop->aio_write=my_aio_write;
// lock inode ?
orig_fop=inode->i_fop;
inode->i_fop=my_fop;
// unlock inode ?
return error;
}
static void __exit clone_1_exit(void)
//void cleanup_module(void)
{
// lock inode ?
if (orig_fop) {
inode->i_fop=orig_fop;
}
// unlock inode ?
kfree(my_fop);
printk(KERN_INFO "Goodbye world 1.\n");
}
module_init(clone_1_init);
module_exit(clone_1_exit);