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);