Index: linux-2.6/net/unix/af_unix.c =================================================================== --- linux-2.6.orig/net/unix/af_unix.c 2006-07-15 21:01:06.000000000 +0800 +++ linux-2.6/net/unix/af_unix.c 2006-07-15 21:01:13.000000000 +0800 @@ -706,6 +706,7 @@ static struct sock *unix_find_other(stru int err = 0; if (sunname->sun_path[0]) { + intent_init(&nd.intent, IT_LOOKUP); err = path_lookup(sunname->sun_path, LOOKUP_FOLLOW, &nd); if (err) goto fail; Index: linux-2.6/fs/open.c =================================================================== --- linux-2.6.orig/fs/open.c 2006-07-15 21:01:10.000000000 +0800 +++ linux-2.6/fs/open.c 2006-07-15 21:01:31.000000000 +0800 @@ -198,9 +198,10 @@ out: } int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs, - struct file *filp) + struct file *filp, int called_from_open) { int err; + struct inode_operations *op = dentry->d_inode->i_op; struct iattr newattrs; /* Not pretty: "inode->i_size" shouldn't really be signed. But it is. */ @@ -215,7 +216,17 @@ int do_truncate(struct dentry *dentry, l } mutex_lock(&dentry->d_inode->i_mutex); - err = notify_change(dentry, &newattrs); + if (called_from_open) + newattrs.ia_valid |= ATTR_FROM_OPEN; + if (op->setattr_raw) { + newattrs.ia_valid |= ATTR_RAW; + newattrs.ia_ctime = CURRENT_TIME; + down_write(&dentry->d_inode->i_alloc_sem); + err = op->setattr_raw(dentry->d_inode, &newattrs); + up_write(&dentry->d_inode->i_alloc_sem); + } else + err = notify_change(dentry, &newattrs); + mutex_unlock(&dentry->d_inode->i_mutex); return err; } @@ -270,7 +281,7 @@ static long do_sys_truncate(const char _ error = locks_verify_truncate(inode, NULL, length); if (!error) { DQUOT_INIT(inode); - error = do_truncate(nd.dentry, length, 0, NULL); + error = do_truncate(nd.dentry, length, 0, NULL, 0); } put_write_access(inode); @@ -322,7 +333,7 @@ static long do_sys_ftruncate(unsigned in error = locks_verify_truncate(inode, file, length); if (!error) - error = do_truncate(dentry, length, ATTR_MTIME|ATTR_CTIME, file); + error = do_truncate(dentry, length, ATTR_MTIME|ATTR_CTIME, file, 0); out_putf: fput(file); out: @@ -407,9 +418,20 @@ asmlinkage long sys_utime(char __user * (error = vfs_permission(&nd, MAY_WRITE)) != 0) goto dput_and_out; } - mutex_lock(&inode->i_mutex); - error = notify_change(nd.dentry, &newattrs); - mutex_unlock(&inode->i_mutex); + if (inode->i_op->setattr_raw) { + struct inode_operations *op = nd.dentry->d_inode->i_op; + + newattrs.ia_valid |= ATTR_RAW; + error = op->setattr_raw(inode, &newattrs); + /* the file system wants to use normal vfs path now */ + if (error != -EOPNOTSUPP) + goto dput_and_out; + } else { + mutex_lock(&inode->i_mutex); + error = notify_change(nd.dentry, &newattrs); + mutex_unlock(&inode->i_mutex); + } + dput_and_out: path_release(&nd); out: @@ -621,38 +643,53 @@ out: return error; } -asmlinkage long sys_fchmod(unsigned int fd, mode_t mode) +int chmod_common(struct dentry *dentry, mode_t mode) { - struct inode * inode; - struct dentry * dentry; - struct file * file; - int err = -EBADF; + struct inode * inode = dentry->d_inode; struct iattr newattrs; - - file = fget(fd); - if (!file) + int error = -EROFS; + + if (IS_RDONLY(inode)) goto out; - dentry = file->f_dentry; - inode = dentry->d_inode; + if (inode->i_op->setattr_raw) { + struct inode_operations *op = dentry->d_inode->i_op; - audit_inode(NULL, inode); + newattrs.ia_mode = mode; + newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; + newattrs.ia_valid |= ATTR_RAW; + error = op->setattr_raw(inode, &newattrs); + /* the file system wants to use normal vfs path now */ + if (error != -EOPNOTSUPP) + goto out; + } - err = -EROFS; - if (IS_RDONLY(inode)) - goto out_putf; - err = -EPERM; + error = -EPERM; if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) - goto out_putf; + goto out; + mutex_lock(&inode->i_mutex); if (mode == (mode_t) -1) mode = inode->i_mode; newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; - err = notify_change(dentry, &newattrs); + error = notify_change(dentry, &newattrs); mutex_unlock(&inode->i_mutex); +out: + return error; +} -out_putf: + +asmlinkage long sys_fchmod(unsigned int fd, mode_t mode) +{ + struct file * file; + int err = -EBADF; + + file = fget(fd); + if (!file) + goto out; + + err = chmod_common(file->f_dentry, mode); fput(file); out: return err; @@ -662,32 +699,12 @@ asmlinkage long sys_fchmodat(int dfd, co mode_t mode) { struct nameidata nd; - struct inode * inode; int error; - struct iattr newattrs; error = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW, &nd); if (error) goto out; - inode = nd.dentry->d_inode; - - error = -EROFS; - if (IS_RDONLY(inode)) - goto dput_and_out; - - error = -EPERM; - if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) - goto dput_and_out; - - mutex_lock(&inode->i_mutex); - if (mode == (mode_t) -1) - mode = inode->i_mode; - newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); - newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; - error = notify_change(nd.dentry, &newattrs); - mutex_unlock(&inode->i_mutex); - -dput_and_out: + error = chmod_common(nd.dentry, mode); path_release(&nd); out: return error; @@ -713,6 +730,18 @@ static int chown_common(struct dentry * if (IS_RDONLY(inode)) goto out; error = -EPERM; + if (inode->i_op->setattr_raw) { + struct inode_operations *op = dentry->d_inode->i_op; + + newattrs.ia_uid = user; + newattrs.ia_gid = group; + newattrs.ia_valid = ATTR_UID | ATTR_GID | ATTR_CTIME; + newattrs.ia_valid |= ATTR_RAW; + error = op->setattr_raw(inode, &newattrs); + /* the file system wants to use normal vfs path now */ + if (error != -EOPNOTSUPP) + return error; + } if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) goto out; newattrs.ia_valid = ATTR_CTIME; Index: linux-2.6/fs/namei.c =================================================================== --- linux-2.6.orig/fs/namei.c 2006-07-15 21:01:10.000000000 +0800 +++ linux-2.6/fs/namei.c 2006-07-15 21:01:13.000000000 +0800 @@ -1642,7 +1642,7 @@ int may_open(struct nameidata *nd, int a if (!error) { DQUOT_INIT(inode); - error = do_truncate(dentry, 0, ATTR_MTIME|ATTR_CTIME, NULL); + error = do_truncate(dentry, 0, ATTR_MTIME|ATTR_CTIME, NULL, 1); } put_write_access(inode); if (error) @@ -1916,6 +1916,7 @@ asmlinkage long sys_mknodat(int dfd, con char * tmp; struct dentry * dentry; struct nameidata nd; + intent_init(&nd.intent, IT_LOOKUP); if (S_ISDIR(mode)) return -EPERM; @@ -1926,6 +1927,15 @@ asmlinkage long sys_mknodat(int dfd, con error = do_path_lookup(dfd, tmp, LOOKUP_PARENT, &nd); if (error) goto out; + + if (nd.dentry->d_inode->i_op->mknod_raw) { + struct inode_operations *op = nd.dentry->d_inode->i_op; + error = op->mknod_raw(&nd, mode, dev); + /* the file system wants to use normal vfs path now */ + if (error != -EOPNOTSUPP) + goto out2; + } + dentry = lookup_create(&nd, 0); error = PTR_ERR(dentry); @@ -1952,6 +1962,7 @@ asmlinkage long sys_mknodat(int dfd, con dput(dentry); } mutex_unlock(&nd.dentry->d_inode->i_mutex); +out2: path_release(&nd); out: putname(tmp); @@ -1997,9 +2008,18 @@ asmlinkage long sys_mkdirat(int dfd, con struct dentry *dentry; struct nameidata nd; + intent_init(&nd.intent, IT_LOOKUP); error = do_path_lookup(dfd, tmp, LOOKUP_PARENT, &nd); if (error) goto out; + if (nd.dentry->d_inode->i_op->mkdir_raw) { + struct inode_operations *op = nd.dentry->d_inode->i_op; + error = op->mkdir_raw(&nd, mode); + /* the file system wants to use normal vfs path now */ + if (error != -EOPNOTSUPP) + goto out2; + } + dentry = lookup_create(&nd, 1); error = PTR_ERR(dentry); if (!IS_ERR(dentry)) { @@ -2009,6 +2029,7 @@ asmlinkage long sys_mkdirat(int dfd, con dput(dentry); } mutex_unlock(&nd.dentry->d_inode->i_mutex); +out2: path_release(&nd); out: putname(tmp); @@ -2089,6 +2110,7 @@ static long do_rmdir(int dfd, const char char * name; struct dentry *dentry; struct nameidata nd; + intent_init(&nd.intent, IT_LOOKUP); name = getname(pathname); if(IS_ERR(name)) @@ -2109,6 +2131,14 @@ static long do_rmdir(int dfd, const char error = -EBUSY; goto exit1; } + if (nd.dentry->d_inode->i_op->rmdir_raw) { + struct inode_operations *op = nd.dentry->d_inode->i_op; + + error = op->rmdir_raw(&nd); + /* the file system wants to use normal vfs path now */ + if (error != -EOPNOTSUPP) + goto exit1; + } mutex_lock_nested(&nd.dentry->d_inode->i_mutex, I_MUTEX_PARENT); dentry = lookup_hash(&nd); error = PTR_ERR(dentry); @@ -2172,6 +2202,7 @@ static long do_unlinkat(int dfd, const c struct dentry *dentry; struct nameidata nd; struct inode *inode = NULL; + intent_init(&nd.intent, IT_LOOKUP); name = getname(pathname); if(IS_ERR(name)) @@ -2183,6 +2214,13 @@ static long do_unlinkat(int dfd, const c error = -EISDIR; if (nd.last_type != LAST_NORM) goto exit1; + if (nd.dentry->d_inode->i_op->unlink_raw) { + struct inode_operations *op = nd.dentry->d_inode->i_op; + error = op->unlink_raw(&nd); + /* the file system wants to use normal vfs path now */ + if (error != -EOPNOTSUPP) + goto exit1; + } mutex_lock_nested(&nd.dentry->d_inode->i_mutex, I_MUTEX_PARENT); dentry = lookup_hash(&nd); error = PTR_ERR(dentry); @@ -2265,9 +2303,17 @@ asmlinkage long sys_symlinkat(const char struct dentry *dentry; struct nameidata nd; + intent_init(&nd.intent, IT_LOOKUP); error = do_path_lookup(newdfd, to, LOOKUP_PARENT, &nd); if (error) goto out; + if (nd.dentry->d_inode->i_op->symlink_raw) { + struct inode_operations *op = nd.dentry->d_inode->i_op; + error = op->symlink_raw(&nd, from); + /* the file system wants to use normal vfs path now */ + if (error != -EOPNOTSUPP) + goto out2; + } dentry = lookup_create(&nd, 0); error = PTR_ERR(dentry); if (!IS_ERR(dentry)) { @@ -2275,6 +2321,7 @@ asmlinkage long sys_symlinkat(const char dput(dentry); } mutex_unlock(&nd.dentry->d_inode->i_mutex); +out2: path_release(&nd); out: putname(to); @@ -2365,6 +2412,13 @@ asmlinkage long sys_linkat(int olddfd, c error = -EXDEV; if (old_nd.mnt != nd.mnt) goto out_release; + if (nd.dentry->d_inode->i_op->link_raw) { + struct inode_operations *op = nd.dentry->d_inode->i_op; + error = op->link_raw(&old_nd, &nd); + /* the file system wants to use normal vfs path now */ + if (error != -EOPNOTSUPP) + goto out_release; + } new_dentry = lookup_create(&nd, 0); error = PTR_ERR(new_dentry); if (!IS_ERR(new_dentry)) { @@ -2541,6 +2595,8 @@ static int do_rename(int olddfd, const c struct dentry * old_dentry, *new_dentry; struct dentry * trap; struct nameidata oldnd, newnd; + intent_init(&oldnd.intent, IT_LOOKUP); + intent_init(&newnd.intent, IT_LOOKUP); error = do_path_lookup(olddfd, oldname, LOOKUP_PARENT, &oldnd); if (error) @@ -2563,6 +2619,13 @@ static int do_rename(int olddfd, const c if (newnd.last_type != LAST_NORM) goto exit2; + if (old_dir->d_inode->i_op->rename_raw) { + error = old_dir->d_inode->i_op->rename_raw(&oldnd, &newnd); + /* the file system wants to use normal vfs path now */ + if (error != -EOPNOTSUPP) + goto exit2; + } + trap = lock_rename(new_dir, old_dir); old_dentry = lookup_hash(&oldnd); @@ -2594,8 +2657,7 @@ static int do_rename(int olddfd, const c if (new_dentry == trap) goto exit5; - error = vfs_rename(old_dir->d_inode, old_dentry, - new_dir->d_inode, new_dentry); + error = vfs_rename(old_dir->d_inode, old_dentry, new_dir->d_inode, new_dentry); exit5: dput(new_dentry); exit4: Index: linux-2.6/fs/exec.c =================================================================== --- linux-2.6.orig/fs/exec.c 2006-07-15 21:01:10.000000000 +0800 +++ linux-2.6/fs/exec.c 2006-07-15 21:01:13.000000000 +0800 @@ -1533,7 +1533,7 @@ int do_coredump(long signr, int exit_cod goto close_fail; if (!file->f_op->write) goto close_fail; - if (do_truncate(file->f_dentry, 0, 0, file) != 0) + if (do_truncate(file->f_dentry, 0, 0, file, 0) != 0) goto close_fail; retval = binfmt->core_dump(signr, regs, file); Index: linux-2.6/include/linux/fs.h =================================================================== --- linux-2.6.orig/include/linux/fs.h 2006-07-15 21:01:10.000000000 +0800 +++ linux-2.6/include/linux/fs.h 2006-07-15 21:01:13.000000000 +0800 @@ -1090,13 +1090,20 @@ struct inode_operations { int (*create) (struct inode *,struct dentry *,int, struct nameidata *); struct dentry * (*lookup) (struct inode *,struct dentry *, struct nameidata *); int (*link) (struct dentry *,struct inode *,struct dentry *); + int (*link_raw) (struct nameidata *,struct nameidata *); int (*unlink) (struct inode *,struct dentry *); + int (*unlink_raw) (struct nameidata *); int (*symlink) (struct inode *,struct dentry *,const char *); + int (*symlink_raw) (struct nameidata *,const char *); int (*mkdir) (struct inode *,struct dentry *,int); + int (*mkdir_raw) (struct nameidata *,int); int (*rmdir) (struct inode *,struct dentry *); + int (*rmdir_raw) (struct nameidata *); int (*mknod) (struct inode *,struct dentry *,int,dev_t); + int (*mknod_raw) (struct nameidata *,int,dev_t); int (*rename) (struct inode *, struct dentry *, struct inode *, struct dentry *); + int (*rename_raw) (struct nameidata *, struct nameidata *); int (*readlink) (struct dentry *, char __user *,int); void * (*follow_link) (struct dentry *, struct nameidata *); void (*put_link) (struct dentry *, struct nameidata *, void *); @@ -1426,7 +1433,7 @@ static inline int break_lease(struct ino /* fs/open.c */ extern int do_truncate(struct dentry *, loff_t start, unsigned int time_attrs, - struct file *filp); + struct file *filp, int called_from_open); extern long do_sys_open(int fdf, const char __user *filename, int flags, int mode); extern struct file *filp_open(const char *, int, int);