diff -uprN -X dontdiff vanilla/fs/attr.c linux/fs/attr.c --- vanilla/fs/attr.c 2003-10-08 21:24:02.000000000 +0200 +++ linux/fs/attr.c 2004-03-08 23:35:58.000000000 +0100 @@ -105,28 +105,6 @@ out: EXPORT_SYMBOL(inode_setattr); -int setattr_mask(unsigned int ia_valid) -{ - unsigned long dn_mask = 0; - - if (ia_valid & ATTR_UID) - dn_mask |= DN_ATTRIB; - if (ia_valid & ATTR_GID) - dn_mask |= DN_ATTRIB; - if (ia_valid & ATTR_SIZE) - dn_mask |= DN_MODIFY; - /* both times implies a utime(s) call */ - if ((ia_valid & (ATTR_ATIME|ATTR_MTIME)) == (ATTR_ATIME|ATTR_MTIME)) - dn_mask |= DN_ATTRIB; - else if (ia_valid & ATTR_ATIME) - dn_mask |= DN_ACCESS; - else if (ia_valid & ATTR_MTIME) - dn_mask |= DN_MODIFY; - if (ia_valid & ATTR_MODE) - dn_mask |= DN_ATTRIB; - return dn_mask; -} - int notify_change(struct dentry * dentry, struct iattr * attr) { struct inode *inode = dentry->d_inode; @@ -183,9 +161,13 @@ int notify_change(struct dentry * dentry } } if (!error) { - unsigned long dn_mask = setattr_mask(ia_valid); - if (dn_mask) - dnotify_parent(dentry, dn_mask); + if (((ia_valid & (ATTR_UID|ATTR_GID|ATTR_MODE)) != 0) || + ((ia_valid & (ATTR_ATIME|ATTR_MTIME)) == (ATTR_ATIME|ATTR_MTIME))) + dnotify_attrib(dentry,attr); + if (ia_valid & ATTR_ATIME) + dnotify_access(dentry,0,inode->i_size); + if (ia_valid & (ATTR_MTIME|ATTR_SIZE)) + dnotify_modify(dentry,0,inode->i_size); } return error; } diff -uprN -X dontdiff vanilla/fs/dcache.c linux/fs/dcache.c --- vanilla/fs/dcache.c 2004-02-19 09:55:41.000000000 +0100 +++ linux/fs/dcache.c 2004-03-18 15:29:15.000000000 +0100 @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -76,6 +77,7 @@ static void d_callback(void *arg) */ static void d_free(struct dentry *dentry) { + dnotify_dispose_dentry(dentry); if (dentry->d_op && dentry->d_op->d_release) dentry->d_op->d_release(dentry); call_rcu(&dentry->d_rcu, d_callback, dentry); @@ -729,7 +731,11 @@ struct dentry * d_alloc(struct dentry * } else { INIT_LIST_HEAD(&dentry->d_child); } - + + dentry->d_dnotify=NULL; + dentry->d_dn_mask=0; + dentry->d_dn_rmask=0; + dnotify_init_dentry(dentry); spin_lock(&dcache_lock); if (parent) list_add(&dentry->d_child, &parent->d_subdirs); @@ -1238,6 +1244,7 @@ already_unhashed: spin_unlock(&dentry->d_lock); write_sequnlock(&rename_lock); spin_unlock(&dcache_lock); + dnotify_move_dentry(dentry); } /** diff -uprN -X dontdiff vanilla/fs/dnotify.c linux/fs/dnotify.c --- vanilla/fs/dnotify.c 2004-02-05 09:19:48.000000000 +0100 +++ linux/fs/dnotify.c 2004-03-21 21:26:10.000000000 +0100 @@ -1,179 +1,132 @@ -/* - * Directory notifications for Linux. - * - * Copyright (C) 2000,2001,2002 Stephen Rothwell - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ -#include #include -#include #include #include #include #include +#include int dir_notify_enable = 1; -static rwlock_t dn_lock = RW_LOCK_UNLOCKED; -static kmem_cache_t *dn_cache; - -static void redo_inode_mask(struct inode *inode) +struct dnotify_ops { + void (*dnotify_flush)(struct file *,fl_owner_t); + int (*fcntl_dirnotify)(int,struct file *,unsigned long); + int (*fcntl_getdirnotify)(int,struct file *,unsigned long); + void (*dnotify_init_dentry)(struct dentry *dentry); + void (*dnotify_move_dentry)(struct dentry *dentry); + void (*dnotify_dispose_dentry)(struct dentry *dentry); + void (*dnotify_parent)(struct dentry *dentry,unsigned long event,void *args,int nargs); +}; + +struct dnotify_ops *dnotify_ops; +EXPORT_SYMBOL(dnotify_ops); +extern void send_sigio(struct fown_struct *fown,int fd,int band); +EXPORT_SYMBOL(send_sigio); +static inline int check(struct dentry *dentry,unsigned long mask) { + return (dentry->d_dn_mask|dentry->d_dn_rmask)&mask; +} + +void dnotify_flush(struct file *file,fl_owner_t owner) { - unsigned long new_mask; - struct dnotify_struct *dn; - - new_mask = 0; - for (dn = inode->i_dnotify; dn != NULL; dn = dn->dn_next) - new_mask |= dn->dn_mask & ~DN_MULTISHOT; - inode->i_dnotify_mask = new_mask; + struct dnotify_ops *ops=dnotify_ops; + if(ops!=NULL)ops->dnotify_flush(file,owner); } - -void dnotify_flush(struct file *filp, fl_owner_t id) +int fcntl_dirnotify(int cmd,struct file *file,unsigned long arg) { - struct dnotify_struct *dn; - struct dnotify_struct **prev; - struct inode *inode; - - inode = filp->f_dentry->d_inode; - if (!S_ISDIR(inode->i_mode)) - return; - write_lock(&dn_lock); - prev = &inode->i_dnotify; - while ((dn = *prev) != NULL) { - if ((dn->dn_owner == id) && (dn->dn_filp == filp)) { - *prev = dn->dn_next; - redo_inode_mask(inode); - kmem_cache_free(dn_cache, dn); - break; - } - prev = &dn->dn_next; - } - write_unlock(&dn_lock); + struct dnotify_ops *ops=dnotify_ops; + if(ops!=NULL)return ops->fcntl_dirnotify(cmd,file,arg); + else return -EFAULT; } - -int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg) +int fcntl_getdirnotify(int cmd,struct file *file,unsigned long arg) { - struct dnotify_struct *dn; - struct dnotify_struct *odn; - struct dnotify_struct **prev; - struct inode *inode; - fl_owner_t id = current->files; - int error = 0; - - if ((arg & ~DN_MULTISHOT) == 0) { - dnotify_flush(filp, id); - return 0; - } - if (!dir_notify_enable) - return -EINVAL; - inode = filp->f_dentry->d_inode; - if (!S_ISDIR(inode->i_mode)) - return -ENOTDIR; - dn = kmem_cache_alloc(dn_cache, SLAB_KERNEL); - if (dn == NULL) - return -ENOMEM; - write_lock(&dn_lock); - prev = &inode->i_dnotify; - while ((odn = *prev) != NULL) { - if ((odn->dn_owner == id) && (odn->dn_filp == filp)) { - odn->dn_fd = fd; - odn->dn_mask |= arg; - inode->i_dnotify_mask |= arg & ~DN_MULTISHOT; - goto out_free; - } - prev = &odn->dn_next; - } - - error = f_setown(filp, current->pid, 0); - if (error) - goto out_free; - - dn->dn_mask = arg; - dn->dn_fd = fd; - dn->dn_filp = filp; - dn->dn_owner = id; - inode->i_dnotify_mask |= arg & ~DN_MULTISHOT; - dn->dn_next = inode->i_dnotify; - inode->i_dnotify = dn; -out: - write_unlock(&dn_lock); - return error; -out_free: - kmem_cache_free(dn_cache, dn); - goto out; + struct dnotify_ops *ops=dnotify_ops; + if(ops!=NULL)return ops->fcntl_getdirnotify(cmd,file,arg); + else return -EFAULT; } - -void __inode_dir_notify(struct inode *inode, unsigned long event) +void dnotify_init_dentry(struct dentry *dentry) { - struct dnotify_struct * dn; - struct dnotify_struct **prev; - struct fown_struct * fown; - int changed = 0; - - write_lock(&dn_lock); - prev = &inode->i_dnotify; - while ((dn = *prev) != NULL) { - if ((dn->dn_mask & event) == 0) { - prev = &dn->dn_next; - continue; - } - fown = &dn->dn_filp->f_owner; - send_sigio(fown, dn->dn_fd, POLL_MSG); - if (dn->dn_mask & DN_MULTISHOT) - prev = &dn->dn_next; - else { - *prev = dn->dn_next; - changed = 1; - kmem_cache_free(dn_cache, dn); - } - } - if (changed) - redo_inode_mask(inode); - write_unlock(&dn_lock); + struct dnotify_ops *ops=dnotify_ops; + if(ops!=NULL)ops->dnotify_init_dentry(dentry); } - -EXPORT_SYMBOL(__inode_dir_notify); - -/* - * This is hopelessly wrong, but unfixable without API changes. At - * least it doesn't oops the kernel... - * - * To safely access ->d_parent we need to keep d_move away from it. Use the - * dentry's d_lock for this. - */ -void dnotify_parent(struct dentry *dentry, unsigned long event) +void dnotify_move_dentry(struct dentry *dentry) { - struct dentry *parent; - - spin_lock(&dentry->d_lock); - parent = dentry->d_parent; - if (parent->d_inode->i_dnotify_mask & event) { - dget(parent); - spin_unlock(&dentry->d_lock); - __inode_dir_notify(parent->d_inode, event); - dput(parent); - } else { - spin_unlock(&dentry->d_lock); - } + struct dnotify_ops *ops=dnotify_ops; + if(ops!=NULL)ops->dnotify_move_dentry(dentry); } -EXPORT_SYMBOL_GPL(dnotify_parent); - -static int __init dnotify_init(void) +void dnotify_dispose_dentry(struct dentry *dentry) { - dn_cache = kmem_cache_create("dnotify_cache", - sizeof(struct dnotify_struct), 0, 0, NULL, NULL); - if (!dn_cache) - panic("cannot create dnotify slab cache"); - return 0; + struct dnotify_ops *ops=dnotify_ops; + if(ops!=NULL)ops->dnotify_dispose_dentry(dentry); +} +void dnotify_parent(struct dentry *dentry,unsigned long event,void *args,int nargs) +{ + struct dnotify_ops *ops=dnotify_ops; + if(ops!=NULL)ops->dnotify_parent(dentry,event,args,nargs); +} +void dnotify_create(struct dentry *dentry) +{ + if(!check(dentry,DN_CREATE)) + return; + dnotify_parent(dentry,DN_CREATE,NULL,0); +} +void dnotify_delete(struct dentry *dentry) +{ + if(!check(dentry,DN_DELETE)) + return; + dnotify_parent(dentry,DN_DELETE,NULL,0); +} +void dnotify_access(struct dentry *dentry,loff_t off,size_t size) +{ + if(!check(dentry,DN_ACCESS)) + return; + struct rwinfo rwinfo; + rwinfo_init(&rwinfo,dentry,DNT_ACCESS,off,size); + dnotify_parent(dentry,DN_ACCESS,&rwinfo,1); +} +void dnotify_modify(struct dentry *dentry,loff_t off,size_t size) +{ + if(!check(dentry,DN_MODIFY)) + return; + struct rwinfo rwinfo; + rwinfo_init(&rwinfo,dentry,DNT_MODIFY,off,size); + dnotify_parent(dentry,DN_MODIFY,&rwinfo,1); +} +void dnotify_attrib(struct dentry *dentry,struct iattr *attr) +{ + if(!check(dentry,DN_ATTRIB)) + return; + struct attribinfo attribinfo; + attribinfo_init(&attribinfo,dentry,attr); + dnotify_parent(dentry,DN_ATTRIB,&attribinfo,1); +} +void dnotify_mmap(struct dentry *dentry,unsigned long ofs,unsigned long len) +{ + if(!check(dentry,DN_MMAP)) + return; + struct changeinfo info; + changeinfo_init(&info,dentry,DNT_MMAP); + dnotify_parent(dentry,DN_MMAP,&info,1); +} +void dnotify_munmap(struct dentry *dentry) +{ + if(!check(dentry,DN_MUNMAP)) + return; + struct changeinfo info; + changeinfo_init(&info,dentry,DNT_MUNMAP); + dnotify_parent(dentry,DN_MUNMAP,&info,1); +} +void dnotify_mount(struct dentry *dentry) +{ + if(!check(dentry,DN_MOUNT)) + return; + struct changeinfo info; + changeinfo_init(&info,dentry,DNT_MOUNT); + dnotify_parent(dentry,DN_MOUNT,&info,1); +} +void dnotify_unmount(struct dentry *dentry) +{ + if(!check(dentry,DN_UNMOUNT)) + return; + struct changeinfo info; + changeinfo_init(&info,dentry,DNT_UNMOUNT); + dnotify_parent(dentry,DN_UNMOUNT,&info,1); } - -module_init(dnotify_init) diff -uprN -X dontdiff vanilla/fs/fcntl.c linux/fs/fcntl.c --- vanilla/fs/fcntl.c 2004-02-05 09:19:49.000000000 +0100 +++ linux/fs/fcntl.c 2004-03-08 23:35:58.000000000 +0100 @@ -346,6 +346,8 @@ static long do_fcntl(unsigned int fd, un case F_NOTIFY: err = fcntl_dirnotify(fd, filp, arg); break; + case F_GETNOTIFY: + err = fcntl_getdirnotify(fd, filp, arg); default: break; } diff -uprN -X dontdiff vanilla/fs/namei.c linux/fs/namei.c --- vanilla/fs/namei.c 2004-02-19 09:55:43.000000000 +0100 +++ linux/fs/namei.c 2004-03-08 23:35:58.000000000 +0100 @@ -1145,7 +1145,7 @@ int vfs_create(struct inode *dir, struct DQUOT_INIT(dir); error = dir->i_op->create(dir, dentry, mode, nd); if (!error) { - inode_dir_notify(dir, DN_CREATE); + dnotify_create(dentry); security_inode_post_create(dir, dentry, mode); } return error; @@ -1446,7 +1446,7 @@ int vfs_mknod(struct inode *dir, struct DQUOT_INIT(dir); error = dir->i_op->mknod(dir, dentry, mode, dev); if (!error) { - inode_dir_notify(dir, DN_CREATE); + dnotify_create(dentry); security_inode_post_mknod(dir, dentry, mode, dev); } return error; @@ -1519,7 +1519,7 @@ int vfs_mkdir(struct inode *dir, struct DQUOT_INIT(dir); error = dir->i_op->mkdir(dir, dentry, mode); if (!error) { - inode_dir_notify(dir, DN_CREATE); + dnotify_create(dentry); security_inode_post_mkdir(dir,dentry, mode); } return error; @@ -1614,7 +1614,7 @@ int vfs_rmdir(struct inode *dir, struct } up(&dentry->d_inode->i_sem); if (!error) { - inode_dir_notify(dir, DN_DELETE); + dnotify_delete(dentry); d_delete(dentry); } dput(dentry); @@ -1687,8 +1687,8 @@ int vfs_unlink(struct inode *dir, struct /* We don't d_delete() NFS sillyrenamed files--they still exist. */ if (!error && !(dentry->d_flags & DCACHE_NFSFS_RENAMED)) { + dnotify_delete(dentry); d_delete(dentry); - inode_dir_notify(dir, DN_DELETE); } return error; } @@ -1764,7 +1764,7 @@ int vfs_symlink(struct inode *dir, struc DQUOT_INIT(dir); error = dir->i_op->symlink(dir, dentry, oldname); if (!error) { - inode_dir_notify(dir, DN_CREATE); + dnotify_create(dentry); security_inode_post_symlink(dir, dentry, oldname); } return error; @@ -1837,7 +1837,7 @@ int vfs_link(struct dentry *old_dentry, error = dir->i_op->link(old_dentry, dir, new_dentry); up(&old_dentry->d_inode->i_sem); if (!error) { - inode_dir_notify(dir, DN_CREATE); + dnotify_create(new_dentry); security_inode_post_link(old_dentry, dir, new_dentry); } return error; @@ -2027,12 +2027,8 @@ int vfs_rename(struct inode *old_dir, st else error = vfs_rename_other(old_dir,old_dentry,new_dir,new_dentry); if (!error) { - if (old_dir == new_dir) - inode_dir_notify(old_dir, DN_RENAME); - else { - inode_dir_notify(old_dir, DN_DELETE); - inode_dir_notify(new_dir, DN_CREATE); - } + dnotify_delete(old_dentry); + dnotify_create(new_dentry); } return error; } diff -uprN -X dontdiff vanilla/fs/namespace.c linux/fs/namespace.c --- vanilla/fs/namespace.c 2004-02-19 09:55:43.000000000 +0100 +++ linux/fs/namespace.c 2004-03-18 19:49:29.000000000 +0100 @@ -22,6 +22,7 @@ #include #include #include +#include extern int __init init_rootfs(void); extern int __init sysfs_init(void); @@ -293,12 +294,14 @@ void umount_tree(struct vfsmount *mnt) static int do_umount(struct vfsmount *mnt, int flags) { + struct dentry *mountpoint=dget(mnt->mnt_mountpoint); + struct super_block * sb = mnt->mnt_sb; int retval; retval = security_sb_umount(mnt, flags); if (retval) - return retval; + goto out; /* * If we may have to abort operations to get out of this @@ -336,7 +339,7 @@ static int do_umount(struct vfsmount *mn unlock_kernel(); } up_write(&sb->s_umount); - return retval; + goto out; } down_write(¤t->namespace->sem); @@ -362,6 +365,10 @@ static int do_umount(struct vfsmount *mn if (retval) security_sb_umount_busy(mnt); up_write(¤t->namespace->sem); +out: + if(retval>=0) + dnotify_unmount(mountpoint); + dput(mountpoint); return retval; } @@ -786,6 +793,7 @@ long do_mount(char * dev_name, char * di else retval = do_add_mount(&nd, type_page, flags, mnt_flags, dev_name, data_page); + dnotify_mount(nd.dentry); dput_out: path_release(&nd); return retval; diff -uprN -X dontdiff vanilla/fs/nfsd/vfs.c linux/fs/nfsd/vfs.c --- vanilla/fs/nfsd/vfs.c 2004-02-05 09:19:49.000000000 +0100 +++ linux/fs/nfsd/vfs.c 2004-03-09 00:02:37.000000000 +0100 @@ -681,7 +681,7 @@ nfsd_read(struct svc_rqst *rqstp, struct nfsdstats.io_read += err; *count = err; err = 0; - dnotify_parent(file.f_dentry, DN_ACCESS); + dnotify_parent(file.f_dentry, DN_ACCESS, NULL, 0); } else err = nfserrno(err); out_close: @@ -750,7 +750,7 @@ nfsd_write(struct svc_rqst *rqstp, struc set_fs(oldfs); if (err >= 0) { nfsdstats.io_write += cnt; - dnotify_parent(file.f_dentry, DN_MODIFY); + dnotify_parent(file.f_dentry, DN_MODIFY, NULL, 0); } /* clear setuid/setgid flag after write */ diff -uprN -X dontdiff vanilla/fs/read_write.c linux/fs/read_write.c --- vanilla/fs/read_write.c 2004-02-05 09:19:50.000000000 +0100 +++ linux/fs/read_write.c 2004-03-08 23:35:58.000000000 +0100 @@ -199,6 +199,7 @@ ssize_t vfs_read(struct file *file, char { struct inode *inode = file->f_dentry->d_inode; ssize_t ret; + loff_t ofs=*pos; if (!(file->f_mode & FMODE_READ)) return -EBADF; @@ -214,7 +215,7 @@ ssize_t vfs_read(struct file *file, char else ret = do_sync_read(file, buf, count, pos); if (ret > 0) - dnotify_parent(file->f_dentry, DN_ACCESS); + dnotify_access(file->f_dentry, ofs, ret); } } @@ -243,6 +244,7 @@ ssize_t vfs_write(struct file *file, con { struct inode *inode = file->f_dentry->d_inode; ssize_t ret; + loff_t ofs=*pos; if (!(file->f_mode & FMODE_WRITE)) return -EBADF; @@ -257,8 +259,9 @@ ssize_t vfs_write(struct file *file, con ret = file->f_op->write(file, buf, count, pos); else ret = do_sync_write(file, buf, count, pos); + if (ret > 0) - dnotify_parent(file->f_dentry, DN_MODIFY); + dnotify_modify(file->f_dentry, ofs, ret); } } @@ -371,7 +374,8 @@ static ssize_t do_readv_writev(int type, int seg; io_fn_t fn; iov_fn_t fnv; - struct inode *inode; + struct inode *inode = file->f_dentry->d_inode; + /* * SuS says "The readv() function *may* fail if the iovcnt argument @@ -424,7 +428,6 @@ static ssize_t do_readv_writev(int type, goto out; } - inode = file->f_dentry->d_inode; /* VERIFY_WRITE actually means a read, as we write to user space */ ret = locks_verify_area((type == READ ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE), @@ -471,9 +474,12 @@ static ssize_t do_readv_writev(int type, out: if (iov != iovstack) kfree(iov); - if ((ret + (type == READ)) > 0) - dnotify_parent(file->f_dentry, - (type == READ) ? DN_ACCESS : DN_MODIFY); + if ((ret + (type == READ)) > 0) { + if(type==READ) + dnotify_access(file->f_dentry,0,inode->i_size); + else + dnotify_modify(file->f_dentry,0,inode->i_size); + } return ret; } diff -uprN -X dontdiff vanilla/fs/sysfs/file.c linux/fs/sysfs/file.c --- vanilla/fs/sysfs/file.c 2003-09-28 06:44:18.000000000 +0200 +++ linux/fs/sysfs/file.c 2004-03-08 23:35:58.000000000 +0100 @@ -401,7 +401,7 @@ int sysfs_update_file(struct kobject * k if (victim->d_inode && (victim->d_parent->d_inode == dir->d_inode)) { victim->d_inode->i_mtime = CURRENT_TIME; - dnotify_parent(victim, DN_MODIFY); + dnotify_parent(victim, DN_MODIFY,NULL,0); /** * Drop reference from initial sysfs_get_dentry(). diff -uprN -X dontdiff vanilla/include/linux/changeinfo.h linux/include/linux/changeinfo.h --- vanilla/include/linux/changeinfo.h 1970-01-01 01:00:00.000000000 +0100 +++ linux/include/linux/changeinfo.h 2004-03-21 23:05:51.000000000 +0100 @@ -0,0 +1,162 @@ +#define DNT_ACCESS 0 +#define DNT_MODIFY 1 +#define DNT_CREATE 2 +#define DNT_DELETE 3 +#define DNT_RENAME 4 +#define DNT_ATTRIB 5 +#define DNT_REGISTER 6 +#define DNT_UNREGISTER 7 +#define DNT_MMAP 8 +#define DNT_MUNMAP 9 +#define DNT_MOUNT 10 +#define DNT_UNMOUNT 11 + +struct block +{ + size_t size; + char data[512-sizeof(size_t)]; +}; + + +/* + * this is the "base class". The type field determines the type. This can be + * used for all types that require no further data, such as + * -deleting a file + * -removing a dentry from the dcache + */ +struct changeinfo /* :block*/ { + size_t size; + unsigned long type; + pid_t pid; + unsigned long id; +}; + +/* + * This is used for name creation. It is the only type of type + * that has a variable length. That is why the constructor is a bit more + * complicated for this one. + */ +struct registerinfo /* :changeinfo*/ { + size_t size; + unsigned long type; + pid_t pid; + unsigned long id; + unsigned long parentid; + char text[sizeof(struct block)-sizeof(unsigned long)*3-sizeof(size_t)]; +}; +/* + * this is used for file creations + */ +struct createinfo { + size_t size; + unsigned long type; + pid_t pid; + unsigned long id; + int mode; + dev_t dev; +}; +/* + * this is used for attribute changes. + * I could copy the whole iattr struct into this? + */ +struct attribinfo { + size_t size; + unsigned long type; + pid_t pid; + unsigned long id; + unsigned int ia_valid; +}; + +/* + * this is used for read and write access. + */ +struct rwinfo { + size_t size; + unsigned long type; + pid_t pid; + unsigned long id; + loff_t foff; + size_t fsize; +}; + +/* + * Changeinfo structs are created in kernel space and consumed in user space. + * So we do not need the constructors in user space. + */ +#ifdef __KERNEL__ +static inline int block_copy(struct block *dst,struct block *src) +{ + if(dst->size>=src->size) { + memcpy(dst,src,src->size); + return 0; + } else { + memcpy(dst,src,dst->size); + return -1; + } +} + +static inline struct block *block_next(struct block *block) +{ + char *temp=(char*)block; + //sanity check + if(block->size<4 || block->size>sizeof(struct block)) + BUG(); + temp+=block->size; + return (struct block*)temp; +} + +/* + * this is how we create a unique id for a dentry. + * Currently we just return the address of the dentry. + * We might also use something more sophisticated like a lossless hash. + * Is it a security risk to let the userspace know the dentry adresses? + * I don't think so. + */ +static inline unsigned long getid(struct dentry *dentry) { + return (unsigned long)dentry; +} + +static inline void changeinfo_init(struct changeinfo *info,struct dentry *dentry,unsigned long type) { + info->size=sizeof(*info); + info->type=type; + info->pid=current->pid; + info->id=getid(dentry); +} + +static inline void registerinfo_init( + struct registerinfo *info, + struct dentry *dentry) +{ + const int min=offsetof(struct registerinfo,text); + const int max=sizeof(struct registerinfo); + int n=dentry->d_name.len; + if(n>max-min) + n=max-min; + info->size=min; + info->type=DNT_REGISTER; + info->pid=current->pid; + info->id=getid(dentry); + info->parentid=getid(dentry->d_parent); + memcpy(info->text,dentry->d_name.name,n); + info->size+=n; +} + +static inline void attribinfo_init(struct attribinfo *info,struct dentry *dentry,struct iattr *attr) +{ + info->size=sizeof(struct attribinfo); + info->type=DNT_ATTRIB; + info->pid=current->pid; + info->id=getid(dentry); + info->ia_valid=attr->ia_valid; +} + +static inline void rwinfo_init(struct rwinfo *info,struct dentry *dentry,unsigned long type,loff_t foff,size_t fsize) +{ + info->size=sizeof(struct rwinfo); + info->type=type; + info->pid=current->pid; + info->id=getid(dentry); + info->foff=foff; + info->fsize=fsize; +} +#endif diff -uprN -X dontdiff vanilla/include/linux/dcache.h linux/include/linux/dcache.h --- vanilla/include/linux/dcache.h 2004-02-05 09:19:55.000000000 +0100 +++ linux/include/linux/dcache.h 2004-03-08 23:35:58.000000000 +0100 @@ -101,6 +101,9 @@ struct dentry { struct qstr d_name; struct hlist_node d_hash; /* lookup hash list */ struct hlist_head * d_bucket; /* lookup hash bucket */ + struct dnotify_struct * d_dnotify; /* list for dnotify */ + unsigned long d_dn_mask; /* dn mask of dentry */ + unsigned long d_dn_rmask; /* dn mask of parent */ unsigned char d_iname[DNAME_INLINE_LEN_MIN]; /* small names */ } ____cacheline_aligned; diff -uprN -X dontdiff vanilla/include/linux/dnotify.h linux/include/linux/dnotify.h --- vanilla/include/linux/dnotify.h 2003-04-07 19:30:34.000000000 +0200 +++ linux/include/linux/dnotify.h 2004-03-18 14:25:31.000000000 +0100 @@ -6,22 +6,32 @@ #include +struct blockbuffer; struct dnotify_struct { struct dnotify_struct * dn_next; - unsigned long dn_mask; /* Events to be notified - see linux/fcntl.h */ + unsigned long dn_mask; //Events to be notified + //see linux/fcntl.h int dn_fd; struct file * dn_filp; fl_owner_t dn_owner; + size_t size; + size_t max; + char * buffer; }; -extern void __inode_dir_notify(struct inode *, unsigned long); -extern void dnotify_flush(struct file *filp, fl_owner_t id); -extern int fcntl_dirnotify(int, struct file *, unsigned long); -void dnotify_parent(struct dentry *dentry, unsigned long event); - -static inline void inode_dir_notify(struct inode *inode, unsigned long event) -{ - if ((inode)->i_dnotify_mask & (event)) - __inode_dir_notify(inode, event); -} +int fcntl_dirnotify(int cmd,struct file *file,unsigned long arg); +int fcntl_getdirnotify(int cmd,struct file *file,unsigned long arg); +void dnotify_flush(struct file *file,fl_owner_t owner); +void dnotify_init_dentry(struct dentry *dentry); +void dnotify_dispose_dentry(struct dentry *dentry); +void dnotify_move_dentry(struct dentry *dentry); +void dnotify_access(struct dentry *dentry,loff_t off,size_t size); +void dnotify_modify(struct dentry *dentry,loff_t off,size_t size); +void dnotify_attrib(struct dentry *dentry,struct iattr *attr); +void dnotify_create(struct dentry *dentry); +void dnotify_delete(struct dentry *dentry); +void dnotify_mmap(struct dentry *dentry,unsigned long ofs,unsigned long len); +void dnotify_munmap(struct dentry *dentry); +void dnotify_mount(struct dentry *dentry); +void dnotify_unmount(struct dentry *dentry); +void dnotify_parent(struct dentry *dentry,unsigned long event,void *args,int nargs); diff -uprN -X dontdiff vanilla/include/linux/fcntl.h linux/include/linux/fcntl.h --- vanilla/include/linux/fcntl.h 2002-10-19 06:01:19.000000000 +0200 +++ linux/include/linux/fcntl.h 2004-03-21 21:50:58.000000000 +0100 @@ -11,6 +11,7 @@ * See below for events that may be notified. */ #define F_NOTIFY (F_LINUX_SPECIFIC_BASE+2) +#define F_GETNOTIFY (F_LINUX_SPECIFIC_BASE+3) /* * Types of directory notifications that may be requested. @@ -21,6 +22,15 @@ #define DN_DELETE 0x00000008 /* File removed */ #define DN_RENAME 0x00000010 /* File renamed */ #define DN_ATTRIB 0x00000020 /* File changed attibutes */ +#define DN_REGISTER 0x00000040 +#define DN_UNREGISTER 0x00000080 +#define DN_MMAP 0x00000100 +#define DN_MUNMAP 0x00000200 +#define DN_MOUNT 0x00000400 +#define DN_UNMOUNT 0x00000800 + +#define DN_EXTENDED 0x20000000 /* Extended notify info */ +#define DN_RECURSIVE 0x40000000 /* Recursive notification */ #define DN_MULTISHOT 0x80000000 /* Don't remove notifier */ #ifdef __KERNEL__ diff -uprN -X dontdiff vanilla/include/linux/fs.h linux/include/linux/fs.h --- vanilla/include/linux/fs.h 2004-02-19 09:55:54.000000000 +0100 +++ linux/include/linux/fs.h 2004-03-08 23:35:58.000000000 +0100 @@ -409,9 +409,6 @@ struct inode { struct cdev *i_cdev; int i_cindex; - unsigned long i_dnotify_mask; /* Directory notify events */ - struct dnotify_struct *i_dnotify; /* for directory notifications */ - unsigned long i_state; unsigned int i_flags; diff -uprN -X dontdiff vanilla/mm/mmap.c linux/mm/mmap.c --- vanilla/mm/mmap.c 2004-02-05 09:19:57.000000000 +0100 +++ linux/mm/mmap.c 2004-03-18 20:20:14.000000000 +0100 @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -694,6 +695,8 @@ out: pgoff, flags & MAP_NONBLOCK); down_write(&mm->mmap_sem); } + if(file!=NULL) + dnotify_mmap(file->f_dentry,addr,len); return addr; unmap_and_free_vma: @@ -1295,7 +1298,6 @@ int do_munmap(struct mm_struct *mm, unsi /* Fix up all other VM information */ unmap_vma_list(mm, mpnt); - return 0; } diff -uprN -X dontdiff vanilla/net/sunrpc/rpc_pipe.c linux/net/sunrpc/rpc_pipe.c --- vanilla/net/sunrpc/rpc_pipe.c 2004-02-19 09:56:09.000000000 +0100 +++ linux/net/sunrpc/rpc_pipe.c 2004-03-08 23:35:58.000000000 +0100 @@ -569,7 +569,7 @@ __rpc_mkdir(struct inode *dir, struct de inode->i_ino = iunique(dir->i_sb, 100); d_instantiate(dentry, inode); dir->i_nlink++; - inode_dir_notify(dir, DN_CREATE); + dnotify_parent(dentry, DN_CREATE, NULL, 0); rpc_get_mount(); return 0; out_err: @@ -591,7 +591,7 @@ __rpc_rmdir(struct inode *dir, struct de if ((error = simple_rmdir(dir, dentry)) != 0) return error; if (!error) { - inode_dir_notify(dir, DN_DELETE); + dnotify_parent(dentry, DN_DELETE, NULL, 0); d_drop(dentry); rpc_put_mount(); } @@ -707,7 +707,7 @@ rpc_mkpipe(char *path, void *private, st rpci->private = private; rpci->flags = flags; rpci->ops = ops; - inode_dir_notify(dir, DN_CREATE); + dnotify_parent(dentry, DN_CREATE, NULL, 0); out: up(&dir->i_sem); rpc_release_path(&nd);