linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH 0/4] VFS updates
@ 2007-08-09 15:27 miklos
  2007-08-09 15:27 ` [RFC PATCH 1/4] pass open file to ->setattr() miklos
                   ` (3 more replies)
  0 siblings, 4 replies; 10+ messages in thread
From: miklos @ 2007-08-09 15:27 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: linux-kernel, Al Viro, Christoph Hellwig

VFS tweaks needed for some FUSE features, but possibly useful to other
filesystems as well.

Comments are welcome.
-- 

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [RFC PATCH 1/4] pass open file to ->setattr()
  2007-08-09 15:27 [RFC PATCH 0/4] VFS updates miklos
@ 2007-08-09 15:27 ` miklos
  2007-08-09 15:35   ` J. Bruce Fields
  2007-08-09 15:27 ` [RFC PATCH 2/4] pass open file to ->getattr() miklos
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 10+ messages in thread
From: miklos @ 2007-08-09 15:27 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: linux-kernel, Al Viro, Christoph Hellwig

[-- Attachment #1: vfs_setattr_file.patch --]
[-- Type: text/plain, Size: 3321 bytes --]

From: Miklos Szeredi <mszeredi@suse.cz>

Pass the open file into the filesystem's ->setattr() method for
fchmod, fchown and some of the utimes variants.

This is needed to be able to correctly implement open-unlink-fsetattr
semantics in some filesystem such as sshfs, without having to resort
to "silly-renaming".

The infrastructure is already there, so just need to fill in
attrs.ia_file and set ATTR_FILE in attrs.ia_valid.

Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
---

Index: linux/fs/open.c
===================================================================
--- linux.orig/fs/open.c	2007-08-09 16:47:30.000000000 +0200
+++ linux/fs/open.c	2007-08-09 16:48:43.000000000 +0200
@@ -581,7 +581,8 @@ asmlinkage long sys_fchmod(unsigned int 
 	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;
+	newattrs.ia_valid = ATTR_MODE | ATTR_CTIME | ATTR_FILE;
+	newattrs.ia_file = file;
 	err = notify_change(dentry, &newattrs);
 	mutex_unlock(&inode->i_mutex);
 
@@ -631,7 +632,8 @@ asmlinkage long sys_chmod(const char __u
 	return sys_fchmodat(AT_FDCWD, filename, mode);
 }
 
-static int chown_common(struct dentry * dentry, uid_t user, gid_t group)
+static int chown_common(struct dentry * dentry, uid_t user, gid_t group,
+			struct file *file)
 {
 	struct inode * inode;
 	int error;
@@ -659,6 +661,10 @@ static int chown_common(struct dentry * 
 	}
 	if (!S_ISDIR(inode->i_mode))
 		newattrs.ia_valid |= ATTR_KILL_SUID|ATTR_KILL_SGID;
+	if (file) {
+		newattrs.ia_file = file;
+		newattrs.ia_valid |= ATTR_FILE;
+	}
 	mutex_lock(&inode->i_mutex);
 	error = notify_change(dentry, &newattrs);
 	mutex_unlock(&inode->i_mutex);
@@ -674,7 +680,7 @@ asmlinkage long sys_chown(const char __u
 	error = user_path_walk(filename, &nd);
 	if (error)
 		goto out;
-	error = chown_common(nd.dentry, user, group);
+	error = chown_common(nd.dentry, user, group, NULL);
 	path_release(&nd);
 out:
 	return error;
@@ -694,7 +700,7 @@ asmlinkage long sys_fchownat(int dfd, co
 	error = __user_walk_fd(dfd, filename, follow, &nd);
 	if (error)
 		goto out;
-	error = chown_common(nd.dentry, user, group);
+	error = chown_common(nd.dentry, user, group, NULL);
 	path_release(&nd);
 out:
 	return error;
@@ -708,7 +714,7 @@ asmlinkage long sys_lchown(const char __
 	error = user_path_walk_link(filename, &nd);
 	if (error)
 		goto out;
-	error = chown_common(nd.dentry, user, group);
+	error = chown_common(nd.dentry, user, group, NULL);
 	path_release(&nd);
 out:
 	return error;
@@ -727,7 +733,7 @@ asmlinkage long sys_fchown(unsigned int 
 
 	dentry = file->f_path.dentry;
 	audit_inode(NULL, dentry);
-	error = chown_common(dentry, user, group);
+	error = chown_common(dentry, user, group, file);
 	fput(file);
 out:
 	return error;
Index: linux/fs/utimes.c
===================================================================
--- linux.orig/fs/utimes.c	2007-08-09 16:47:30.000000000 +0200
+++ linux/fs/utimes.c	2007-08-09 16:48:43.000000000 +0200
@@ -130,6 +130,10 @@ long do_utimes(int dfd, char __user *fil
 			}
 		}
 	}
+	if (f) {
+		newattrs.ia_file = f;
+		newattrs.ia_valid |= ATTR_FILE;
+	}
 	mutex_lock(&inode->i_mutex);
 	error = notify_change(dentry, &newattrs);
 	mutex_unlock(&inode->i_mutex);

--

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [RFC PATCH 2/4] pass open file to ->getattr()
  2007-08-09 15:27 [RFC PATCH 0/4] VFS updates miklos
  2007-08-09 15:27 ` [RFC PATCH 1/4] pass open file to ->setattr() miklos
@ 2007-08-09 15:27 ` miklos
  2007-08-09 15:27 ` [RFC PATCH 3/4] allow filesystems to implement atomic open+truncate miklos
  2007-08-09 15:27 ` [RFC PATCH 4/4] VFS: allow filesystem to override mknod capability checks miklos
  3 siblings, 0 replies; 10+ messages in thread
From: miklos @ 2007-08-09 15:27 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: linux-kernel, Al Viro, Christoph Hellwig

[-- Attachment #1: vfs_getattr_file.patch --]
[-- Type: text/plain, Size: 20846 bytes --]

From: Miklos Szeredi <mszeredi@suse.cz>

Pass the open file into the filesystem's ->getattr() method for
fstat().

This is needed to be able to correctly implement open-unlink-fstat
semantics in some filesystem such as sshfs, without having to resort
to "silly-renaming".

Do this by adding a 'struct file *' parameter to i_op->getattr().  For
fstat() pass the open file pointer, in other cases pass NULL.

This is safe from a compatibility standpoint, out-of-tree old stuff
will continue to work, but will get a warning at compile time.

Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
---

Index: linux/fs/9p/vfs_inode.c
===================================================================
--- linux.orig/fs/9p/vfs_inode.c	2007-08-09 16:47:30.000000000 +0200
+++ linux/fs/9p/vfs_inode.c	2007-08-09 16:48:45.000000000 +0200
@@ -706,7 +706,7 @@ done:
 
 static int
 v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
-		 struct kstat *stat)
+		 struct kstat *stat, struct file *file)
 {
 	int err;
 	struct v9fs_session_info *v9ses;
Index: linux/fs/afs/inode.c
===================================================================
--- linux.orig/fs/afs/inode.c	2007-08-09 16:47:30.000000000 +0200
+++ linux/fs/afs/inode.c	2007-08-09 16:48:45.000000000 +0200
@@ -295,7 +295,7 @@ error_unlock:
  * read the attributes of an inode
  */
 int afs_getattr(struct vfsmount *mnt, struct dentry *dentry,
-		      struct kstat *stat)
+		      struct kstat *stat, struct file *file)
 {
 	struct inode *inode;
 
Index: linux/fs/afs/internal.h
===================================================================
--- linux.orig/fs/afs/internal.h	2007-08-09 16:47:30.000000000 +0200
+++ linux/fs/afs/internal.h	2007-08-09 16:48:45.000000000 +0200
@@ -548,7 +548,8 @@ extern struct inode *afs_iget(struct sup
 			      struct afs_callback *);
 extern void afs_zap_data(struct afs_vnode *);
 extern int afs_validate(struct afs_vnode *, struct key *);
-extern int afs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
+extern int afs_getattr(struct vfsmount *, struct dentry *, struct kstat *,
+		       struct file *);
 extern int afs_setattr(struct dentry *, struct iattr *);
 extern void afs_clear_inode(struct inode *);
 
Index: linux/fs/bad_inode.c
===================================================================
--- linux.orig/fs/bad_inode.c	2007-08-09 16:47:30.000000000 +0200
+++ linux/fs/bad_inode.c	2007-08-09 16:48:45.000000000 +0200
@@ -250,7 +250,7 @@ static int bad_inode_permission(struct i
 }
 
 static int bad_inode_getattr(struct vfsmount *mnt, struct dentry *dentry,
-			struct kstat *stat)
+			struct kstat *stat, struct file *file)
 {
 	return -EIO;
 }
Index: linux/fs/cifs/cifsfs.h
===================================================================
--- linux.orig/fs/cifs/cifsfs.h	2007-08-09 16:47:30.000000000 +0200
+++ linux/fs/cifs/cifsfs.h	2007-08-09 16:48:45.000000000 +0200
@@ -55,7 +55,8 @@ extern int cifs_rmdir(struct inode *, st
 extern int cifs_rename(struct inode *, struct dentry *, struct inode *,
 		       struct dentry *);
 extern int cifs_revalidate(struct dentry *);
-extern int cifs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
+extern int cifs_getattr(struct vfsmount *, struct dentry *, struct kstat *,
+			struct file *);
 extern int cifs_setattr(struct dentry *, struct iattr *);
 
 extern const struct inode_operations cifs_file_inode_ops;
Index: linux/fs/cifs/inode.c
===================================================================
--- linux.orig/fs/cifs/inode.c	2007-08-09 16:47:30.000000000 +0200
+++ linux/fs/cifs/inode.c	2007-08-09 16:48:45.000000000 +0200
@@ -1332,7 +1332,7 @@ int cifs_revalidate(struct dentry *diren
 }
 
 int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
-	struct kstat *stat)
+	struct kstat *stat, struct file *file)
 {
 	int err = cifs_revalidate(dentry);
 	if (!err) {
Index: linux/fs/coda/inode.c
===================================================================
--- linux.orig/fs/coda/inode.c	2007-08-09 16:47:30.000000000 +0200
+++ linux/fs/coda/inode.c	2007-08-09 16:48:45.000000000 +0200
@@ -220,7 +220,8 @@ static void coda_clear_inode(struct inod
 	coda_cache_clear_inode(inode);
 }
 
-int coda_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
+int coda_getattr(struct vfsmount *mnt, struct dentry *dentry,
+		 struct kstat *stat, struct file *file)
 {
 	int err = coda_revalidate_inode(dentry);
 	if (!err)
Index: linux/fs/fat/file.c
===================================================================
--- linux.orig/fs/fat/file.c	2007-08-09 16:47:30.000000000 +0200
+++ linux/fs/fat/file.c	2007-08-09 16:48:45.000000000 +0200
@@ -303,7 +303,8 @@ void fat_truncate(struct inode *inode)
 	fat_flush_inodes(inode->i_sb, inode, NULL);
 }
 
-int fat_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
+int fat_getattr(struct vfsmount *mnt, struct dentry *dentry,
+		struct kstat *stat, struct file *file)
 {
 	struct inode *inode = dentry->d_inode;
 	generic_fillattr(inode, stat);
Index: linux/fs/fuse/dir.c
===================================================================
--- linux.orig/fs/fuse/dir.c	2007-08-09 16:47:30.000000000 +0200
+++ linux/fs/fuse/dir.c	2007-08-09 16:48:45.000000000 +0200
@@ -1056,7 +1056,7 @@ static int fuse_setattr(struct dentry *e
 }
 
 static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
-			struct kstat *stat)
+			struct kstat *stat, struct file *file)
 {
 	struct inode *inode = entry->d_inode;
 	struct fuse_inode *fi = get_fuse_inode(inode);
Index: linux/fs/gfs2/ops_inode.c
===================================================================
--- linux.orig/fs/gfs2/ops_inode.c	2007-08-09 16:47:30.000000000 +0200
+++ linux/fs/gfs2/ops_inode.c	2007-08-09 16:48:45.000000000 +0200
@@ -1030,7 +1030,7 @@ out:
  */
 
 static int gfs2_getattr(struct vfsmount *mnt, struct dentry *dentry,
-			struct kstat *stat)
+			struct kstat *stat, struct file *file)
 {
 	struct inode *inode = dentry->d_inode;
 	struct gfs2_inode *ip = GFS2_I(inode);
Index: linux/fs/libfs.c
===================================================================
--- linux.orig/fs/libfs.c	2007-08-09 16:47:30.000000000 +0200
+++ linux/fs/libfs.c	2007-08-09 16:48:45.000000000 +0200
@@ -12,7 +12,7 @@
 #include <asm/uaccess.h>
 
 int simple_getattr(struct vfsmount *mnt, struct dentry *dentry,
-		   struct kstat *stat)
+		   struct kstat *stat, struct file *file)
 {
 	struct inode *inode = dentry->d_inode;
 	generic_fillattr(inode, stat);
Index: linux/fs/nfs/inode.c
===================================================================
--- linux.orig/fs/nfs/inode.c	2007-08-09 16:47:30.000000000 +0200
+++ linux/fs/nfs/inode.c	2007-08-09 16:48:45.000000000 +0200
@@ -423,7 +423,8 @@ static void nfs_wake_up_inode(struct ino
 	wake_up_bit(&nfsi->flags, NFS_INO_REVALIDATING);
 }
 
-int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
+int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
+		struct kstat *stat, struct file *file)
 {
 	struct inode *inode = dentry->d_inode;
 	int need_atime = NFS_I(inode)->cache_validity & NFS_INO_INVALID_ATIME;
Index: linux/fs/ocfs2/file.c
===================================================================
--- linux.orig/fs/ocfs2/file.c	2007-08-09 16:47:30.000000000 +0200
+++ linux/fs/ocfs2/file.c	2007-08-09 16:48:45.000000000 +0200
@@ -1086,7 +1086,8 @@ bail:
 
 int ocfs2_getattr(struct vfsmount *mnt,
 		  struct dentry *dentry,
-		  struct kstat *stat)
+		  struct kstat *stat,
+		  struct file *file)
 {
 	struct inode *inode = dentry->d_inode;
 	struct super_block *sb = dentry->d_inode->i_sb;
Index: linux/fs/ocfs2/file.h
===================================================================
--- linux.orig/fs/ocfs2/file.h	2007-08-09 16:47:30.000000000 +0200
+++ linux/fs/ocfs2/file.h	2007-08-09 16:48:45.000000000 +0200
@@ -53,7 +53,7 @@ int ocfs2_lock_allocators(struct inode *
 			  struct ocfs2_alloc_context **meta_ac);
 int ocfs2_setattr(struct dentry *dentry, struct iattr *attr);
 int ocfs2_getattr(struct vfsmount *mnt, struct dentry *dentry,
-		  struct kstat *stat);
+		  struct kstat *stat, struct file *file);
 int ocfs2_permission(struct inode *inode, int mask,
 		     struct nameidata *nd);
 
Index: linux/fs/proc/base.c
===================================================================
--- linux.orig/fs/proc/base.c	2007-08-09 16:47:30.000000000 +0200
+++ linux/fs/proc/base.c	2007-08-09 16:48:45.000000000 +0200
@@ -1028,7 +1028,8 @@ out_unlock:
 	return NULL;
 }
 
-static int pid_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
+static int pid_getattr(struct vfsmount *mnt, struct dentry *dentry,
+		       struct kstat *stat, struct file *file)
 {
 	struct inode *inode = dentry->d_inode;
 	struct task_struct *task;
@@ -2584,7 +2585,8 @@ out_no_task:
 	return retval;
 }
 
-static int proc_task_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
+static int proc_task_getattr(struct vfsmount *mnt, struct dentry *dentry,
+			     struct kstat *stat, struct file *file)
 {
 	struct inode *inode = dentry->d_inode;
 	struct task_struct *p = get_proc_task(inode);
Index: linux/fs/proc/generic.c
===================================================================
--- linux.orig/fs/proc/generic.c	2007-08-09 16:47:30.000000000 +0200
+++ linux/fs/proc/generic.c	2007-08-09 16:48:45.000000000 +0200
@@ -255,7 +255,7 @@ out:
 }
 
 static int proc_getattr(struct vfsmount *mnt, struct dentry *dentry,
-			struct kstat *stat)
+			struct kstat *stat, struct file *file)
 {
 	struct inode *inode = dentry->d_inode;
 	struct proc_dir_entry *de = PROC_I(inode)->pde;
Index: linux/fs/proc/root.c
===================================================================
--- linux.orig/fs/proc/root.c	2007-08-09 16:47:30.000000000 +0200
+++ linux/fs/proc/root.c	2007-08-09 16:48:45.000000000 +0200
@@ -82,8 +82,8 @@ void __init proc_root_init(void)
 	proc_sys_init();
 }
 
-static int proc_root_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat
-)
+static int proc_root_getattr(struct vfsmount *mnt, struct dentry *dentry,
+			     struct kstat *stat, struct file *file)
 {
 	generic_fillattr(dentry->d_inode, stat);
 	stat->nlink = proc_root.nlink + nr_processes();
Index: linux/fs/smbfs/inode.c
===================================================================
--- linux.orig/fs/smbfs/inode.c	2007-08-09 16:47:30.000000000 +0200
+++ linux/fs/smbfs/inode.c	2007-08-09 16:48:45.000000000 +0200
@@ -659,7 +659,8 @@ smb_statfs(struct dentry *dentry, struct
 	return result;
 }
 
-int smb_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
+int smb_getattr(struct vfsmount *mnt, struct dentry *dentry,
+		struct kstat *stat, struct file *file)
 {
 	int err = smb_revalidate_inode(dentry);
 	if (!err)
Index: linux/fs/smbfs/proto.h
===================================================================
--- linux.orig/fs/smbfs/proto.h	2007-08-09 16:47:30.000000000 +0200
+++ linux/fs/smbfs/proto.h	2007-08-09 16:48:45.000000000 +0200
@@ -60,7 +60,8 @@ extern void smb_get_inode_attr(struct in
 extern void smb_set_inode_attr(struct inode *inode, struct smb_fattr *fattr);
 extern void smb_invalidate_inodes(struct smb_sb_info *server);
 extern int smb_revalidate_inode(struct dentry *dentry);
-extern int smb_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat);
+extern int smb_getattr(struct vfsmount *mnt, struct dentry *dentry,
+		       struct kstat *stat, struct file *file);
 extern int smb_notify_change(struct dentry *dentry, struct iattr *attr);
 /* file.c */
 extern const struct address_space_operations smb_file_aops;
Index: linux/fs/stat.c
===================================================================
--- linux.orig/fs/stat.c	2007-08-09 16:47:30.000000000 +0200
+++ linux/fs/stat.c	2007-08-09 16:48:45.000000000 +0200
@@ -37,7 +37,8 @@ void generic_fillattr(struct inode *inod
 
 EXPORT_SYMBOL(generic_fillattr);
 
-int vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
+static int vfs_fgetattr(struct vfsmount *mnt, struct dentry *dentry,
+			struct kstat *stat, struct file *file)
 {
 	struct inode *inode = dentry->d_inode;
 	int retval;
@@ -47,12 +48,17 @@ int vfs_getattr(struct vfsmount *mnt, st
 		return retval;
 
 	if (inode->i_op->getattr)
-		return inode->i_op->getattr(mnt, dentry, stat);
+		return inode->i_op->getattr(mnt, dentry, stat, file);
 
 	generic_fillattr(inode, stat);
 	return 0;
 }
 
+int vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
+{
+	return vfs_fgetattr(mnt, dentry, stat, NULL);
+}
+
 EXPORT_SYMBOL(vfs_getattr);
 
 int vfs_stat_fd(int dfd, char __user *name, struct kstat *stat)
@@ -62,7 +68,7 @@ int vfs_stat_fd(int dfd, char __user *na
 
 	error = __user_walk_fd(dfd, name, LOOKUP_FOLLOW, &nd);
 	if (!error) {
-		error = vfs_getattr(nd.mnt, nd.dentry, stat);
+		error = vfs_fgetattr(nd.mnt, nd.dentry, stat, NULL);
 		path_release(&nd);
 	}
 	return error;
@@ -82,7 +88,7 @@ int vfs_lstat_fd(int dfd, char __user *n
 
 	error = __user_walk_fd(dfd, name, 0, &nd);
 	if (!error) {
-		error = vfs_getattr(nd.mnt, nd.dentry, stat);
+		error = vfs_fgetattr(nd.mnt, nd.dentry, stat, NULL);
 		path_release(&nd);
 	}
 	return error;
@@ -101,7 +107,7 @@ int vfs_fstat(unsigned int fd, struct ks
 	int error = -EBADF;
 
 	if (f) {
-		error = vfs_getattr(f->f_path.mnt, f->f_path.dentry, stat);
+		error = vfs_fgetattr(f->f_path.mnt, f->f_path.dentry, stat, f);
 		fput(f);
 	}
 	return error;
Index: linux/fs/sysv/itree.c
===================================================================
--- linux.orig/fs/sysv/itree.c	2007-08-09 16:47:30.000000000 +0200
+++ linux/fs/sysv/itree.c	2007-08-09 16:48:45.000000000 +0200
@@ -440,7 +440,8 @@ static unsigned sysv_nblocks(struct supe
 	return blocks;
 }
 
-int sysv_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
+int sysv_getattr(struct vfsmount *mnt, struct dentry *dentry,
+		 struct kstat *stat, struct file *file)
 {
 	struct super_block *s = mnt->mnt_sb;
 	generic_fillattr(dentry->d_inode, stat);
Index: linux/fs/sysv/sysv.h
===================================================================
--- linux.orig/fs/sysv/sysv.h	2007-08-09 16:47:30.000000000 +0200
+++ linux/fs/sysv/sysv.h	2007-08-09 16:48:45.000000000 +0200
@@ -145,7 +145,8 @@ extern int sysv_write_inode(struct inode
 extern int sysv_sync_inode(struct inode *);
 extern int sysv_sync_file(struct file *, struct dentry *, int);
 extern void sysv_set_inode(struct inode *, dev_t);
-extern int sysv_getattr(struct vfsmount *, struct dentry *, struct kstat *);
+extern int sysv_getattr(struct vfsmount *, struct dentry *, struct kstat *,
+			struct file *);
 extern int sysv_init_icache(void);
 extern void sysv_destroy_icache(void);
 
Index: linux/fs/xfs/linux-2.6/xfs_iops.c
===================================================================
--- linux.orig/fs/xfs/linux-2.6/xfs_iops.c	2007-08-09 16:47:30.000000000 +0200
+++ linux/fs/xfs/linux-2.6/xfs_iops.c	2007-08-09 16:48:45.000000000 +0200
@@ -617,7 +617,8 @@ STATIC int
 xfs_vn_getattr(
 	struct vfsmount	*mnt,
 	struct dentry	*dentry,
-	struct kstat	*stat)
+	struct kstat	*stat,
+	struct file	*file)
 {
 	struct inode	*inode = dentry->d_inode;
 	bhv_vnode_t	*vp = vn_from_inode(inode);
Index: linux/include/linux/coda_linux.h
===================================================================
--- linux.orig/include/linux/coda_linux.h	2007-08-09 16:47:30.000000000 +0200
+++ linux/include/linux/coda_linux.h	2007-08-09 16:48:45.000000000 +0200
@@ -39,7 +39,8 @@ int coda_open(struct inode *i, struct fi
 int coda_release(struct inode *i, struct file *f);
 int coda_permission(struct inode *inode, int mask, struct nameidata *nd);
 int coda_revalidate_inode(struct dentry *);
-int coda_getattr(struct vfsmount *, struct dentry *, struct kstat *);
+int coda_getattr(struct vfsmount *, struct dentry *, struct kstat *,
+		 struct file *);
 int coda_setattr(struct dentry *, struct iattr *);
 
 /* this file:  heloers */
Index: linux/include/linux/fs.h
===================================================================
--- linux.orig/include/linux/fs.h	2007-08-09 16:47:30.000000000 +0200
+++ linux/include/linux/fs.h	2007-08-09 16:48:45.000000000 +0200
@@ -1210,7 +1210,8 @@ struct inode_operations {
 	void (*truncate) (struct inode *);
 	int (*permission) (struct inode *, int, struct nameidata *);
 	int (*setattr) (struct dentry *, struct iattr *);
-	int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *);
+	int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *,
+			struct file *file);
 	int (*setxattr) (struct dentry *, const char *,const void *,size_t,int);
 	ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t);
 	ssize_t (*listxattr) (struct dentry *, char *, size_t);
@@ -1929,7 +1930,8 @@ extern int dcache_dir_open(struct inode 
 extern int dcache_dir_close(struct inode *, struct file *);
 extern loff_t dcache_dir_lseek(struct file *, loff_t, int);
 extern int dcache_readdir(struct file *, void *, filldir_t);
-extern int simple_getattr(struct vfsmount *, struct dentry *, struct kstat *);
+extern int simple_getattr(struct vfsmount *, struct dentry *, struct kstat *,
+			  struct file *);
 extern int simple_statfs(struct dentry *, struct kstatfs *);
 extern int simple_link(struct dentry *, struct inode *, struct dentry *);
 extern int simple_unlink(struct inode *, struct dentry *);
Index: linux/include/linux/msdos_fs.h
===================================================================
--- linux.orig/include/linux/msdos_fs.h	2007-08-09 16:47:30.000000000 +0200
+++ linux/include/linux/msdos_fs.h	2007-08-09 16:48:45.000000000 +0200
@@ -404,7 +404,7 @@ extern const struct inode_operations fat
 extern int fat_notify_change(struct dentry * dentry, struct iattr * attr);
 extern void fat_truncate(struct inode *inode);
 extern int fat_getattr(struct vfsmount *mnt, struct dentry *dentry,
-		       struct kstat *stat);
+		       struct kstat *stat, struct file *file);
 
 /* fat/inode.c */
 extern void fat_attach(struct inode *inode, loff_t i_pos);
Index: linux/include/linux/nfs_fs.h
===================================================================
--- linux.orig/include/linux/nfs_fs.h	2007-08-09 16:47:30.000000000 +0200
+++ linux/include/linux/nfs_fs.h	2007-08-09 16:48:45.000000000 +0200
@@ -285,7 +285,8 @@ extern struct inode *nfs_fhget(struct su
 				struct nfs_fattr *);
 extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *);
 extern int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr);
-extern int nfs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
+extern int nfs_getattr(struct vfsmount *, struct dentry *, struct kstat *,
+		       struct file *);
 extern int nfs_permission(struct inode *, int, struct nameidata *);
 extern int nfs_access_get_cached(struct inode *, struct rpc_cred *, struct nfs_access_entry *);
 extern void nfs_access_add_cache(struct inode *, struct nfs_access_entry *);
Index: linux/fs/reiser4/plugin/inode_ops.c
===================================================================
--- linux.orig/fs/reiser4/plugin/inode_ops.c	2007-08-09 16:47:30.000000000 +0200
+++ linux/fs/reiser4/plugin/inode_ops.c	2007-08-09 16:48:53.000000000 +0200
@@ -475,7 +475,8 @@ int reiser4_setattr_common(struct dentry
    inode_operations
 */
 int reiser4_getattr_common(struct vfsmount *mnt UNUSED_ARG,
-			   struct dentry *dentry, struct kstat *stat)
+			   struct dentry *dentry, struct kstat *stat,
+			   struct file *file UNUSED_ARG)
 {
 	struct inode *obj;
 
Index: linux/fs/reiser4/plugin/object.h
===================================================================
--- linux.orig/fs/reiser4/plugin/object.h	2007-08-09 16:47:30.000000000 +0200
+++ linux/fs/reiser4/plugin/object.h	2007-08-09 16:48:53.000000000 +0200
@@ -29,7 +29,7 @@ int reiser4_permission_common(struct ino
 			      struct nameidata *nameidata);
 int reiser4_setattr_common(struct dentry *, struct iattr *);
 int reiser4_getattr_common(struct vfsmount *mnt, struct dentry *,
-			   struct kstat *);
+			   struct kstat *, struct file *);
 
 /* common implementations of file operations */
 loff_t reiser4_llseek_dir_common(struct file *, loff_t off, int origin);
Index: linux/fs/revoked_inode.c
===================================================================
--- linux.orig/fs/revoked_inode.c	2007-08-09 16:47:30.000000000 +0200
+++ linux/fs/revoked_inode.c	2007-08-09 16:48:53.000000000 +0200
@@ -295,7 +295,7 @@ static int revoked_inode_permission(stru
 }
 
 static int revoked_inode_getattr(struct vfsmount *mnt, struct dentry *dentry,
-				 struct kstat *stat)
+				 struct kstat *stat, struct file *file)
 {
 	return -EBADF;
 }

--

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [RFC PATCH 3/4] allow filesystems to implement atomic open+truncate
  2007-08-09 15:27 [RFC PATCH 0/4] VFS updates miklos
  2007-08-09 15:27 ` [RFC PATCH 1/4] pass open file to ->setattr() miklos
  2007-08-09 15:27 ` [RFC PATCH 2/4] pass open file to ->getattr() miklos
@ 2007-08-09 15:27 ` miklos
  2007-08-09 15:27 ` [RFC PATCH 4/4] VFS: allow filesystem to override mknod capability checks miklos
  3 siblings, 0 replies; 10+ messages in thread
From: miklos @ 2007-08-09 15:27 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: linux-kernel, Al Viro, Christoph Hellwig

[-- Attachment #1: vfs_atomic_open_truncate.patch --]
[-- Type: text/plain, Size: 2651 bytes --]

From: Miklos Szeredi <mszeredi@suse.cz>

Add a new attribute flag ATTR_OPEN, with the meaning: "truncation was
initiated by open() due to the O_TRUNC flag".

This way filesystems wanting to implement truncation within their
->open() method can ignore such truncate requests.

This is a quick & dirty hack, but it comes for free.

When (if) we implement a proper low-level open+create+truncate inode
operation, this can go away.

Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
---

Index: linux/fs/namei.c
===================================================================
--- linux.orig/fs/namei.c	2007-08-09 16:47:30.000000000 +0200
+++ linux/fs/namei.c	2007-08-09 16:49:07.000000000 +0200
@@ -1655,8 +1655,10 @@ int may_open(struct nameidata *nd, int a
 		error = locks_verify_locked(inode);
 		if (!error) {
 			DQUOT_INIT(inode);
-			
-			error = do_truncate(dentry, 0, ATTR_MTIME|ATTR_CTIME, NULL);
+
+			error = do_truncate(dentry, 0,
+					    ATTR_MTIME|ATTR_CTIME|ATTR_OPEN,
+					    NULL);
 		}
 		put_write_access(inode);
 		if (error)
Index: linux/include/linux/fs.h
===================================================================
--- linux.orig/include/linux/fs.h	2007-08-09 16:48:45.000000000 +0200
+++ linux/include/linux/fs.h	2007-08-09 16:49:07.000000000 +0200
@@ -335,6 +335,7 @@ typedef void (dio_iodone_t)(struct kiocb
 #define ATTR_KILL_SUID	2048
 #define ATTR_KILL_SGID	4096
 #define ATTR_FILE	8192
+#define ATTR_OPEN	16384	/* Truncating from open(O_TRUNC) */
 
 /*
  * This is the Inode Attributes structure, used for notify_change().  It
@@ -1521,7 +1522,7 @@ static inline int break_lease(struct ino
 
 /* fs/open.c */
 
-extern int do_truncate(struct dentry *, loff_t start, unsigned int time_attrs,
+extern int do_truncate(struct dentry *, loff_t start, unsigned int attrs,
 		       struct file *filp);
 extern long do_sys_open(int fdf, const char __user *filename, int flags,
 			int mode);
Index: linux/fs/open.c
===================================================================
--- linux.orig/fs/open.c	2007-08-09 16:48:43.000000000 +0200
+++ linux/fs/open.c	2007-08-09 16:49:07.000000000 +0200
@@ -194,7 +194,7 @@ out:
 	return error;
 }
 
-int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs,
+int do_truncate(struct dentry *dentry, loff_t length, unsigned int attrs,
 	struct file *filp)
 {
 	int err;
@@ -205,7 +205,7 @@ int do_truncate(struct dentry *dentry, l
 		return -EINVAL;
 
 	newattrs.ia_size = length;
-	newattrs.ia_valid = ATTR_SIZE | time_attrs;
+	newattrs.ia_valid = ATTR_SIZE | attrs;
 	if (filp) {
 		newattrs.ia_file = filp;
 		newattrs.ia_valid |= ATTR_FILE;

--

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [RFC PATCH 4/4] VFS: allow filesystem to override mknod capability checks
  2007-08-09 15:27 [RFC PATCH 0/4] VFS updates miklos
                   ` (2 preceding siblings ...)
  2007-08-09 15:27 ` [RFC PATCH 3/4] allow filesystems to implement atomic open+truncate miklos
@ 2007-08-09 15:27 ` miklos
  2007-08-09 19:20   ` Serge E. Hallyn
  3 siblings, 1 reply; 10+ messages in thread
From: miklos @ 2007-08-09 15:27 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: linux-kernel, Al Viro, Christoph Hellwig

[-- Attachment #1: vfs_mknod_nocheck.patch --]
[-- Type: text/plain, Size: 2055 bytes --]

From: Miklos Szeredi <mszeredi@suse.cz>

Add a new filesystem flag, that results in the VFS not checking if the
current process has enough privileges to do an mknod().

This is needed on filesystems, where an unprivileged user may be able
to create a device node, without causing security problems.

One such example is "mountlo" a loopback mount utility implemented
with fuse and UML, which runs as an unprivileged userspace process.
In this case the user does in fact have the right to create device
nodes within the filesystem image, as long as the user has write
access to the image.  Since the filesystem is mounted with "nodev",
adding device nodes is not a security concern.

This feature is basically "fuse-only", so it does not make sense to
change the semantics of ->mknod().

Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
---

Index: linux/fs/namei.c
===================================================================
--- linux.orig/fs/namei.c	2007-08-09 16:49:07.000000000 +0200
+++ linux/fs/namei.c	2007-08-09 16:49:12.000000000 +0200
@@ -1921,7 +1921,8 @@ int vfs_mknod(struct inode *dir, struct 
 	if (error)
 		return error;
 
-	if ((S_ISCHR(mode) || S_ISBLK(mode)) && !capable(CAP_MKNOD))
+	if (!(dir->i_sb->s_type->fs_flags & FS_MKNOD_CHECKS_PERM) &&
+	    (S_ISCHR(mode) || S_ISBLK(mode)) && !capable(CAP_MKNOD))
 		return -EPERM;
 
 	if (!dir->i_op || !dir->i_op->mknod)
Index: linux/include/linux/fs.h
===================================================================
--- linux.orig/include/linux/fs.h	2007-08-09 16:49:07.000000000 +0200
+++ linux/include/linux/fs.h	2007-08-09 16:49:12.000000000 +0200
@@ -97,6 +97,7 @@ extern int dir_notify_enable;
 #define FS_BINARY_MOUNTDATA 2
 #define FS_HAS_SUBTYPE 4
 #define FS_SAFE 8		/* Safe to mount by unprivileged users */
+#define FS_MKNOD_CHECKS_PERM 16	/* FS checks if device creation is allowed */
 #define FS_REVAL_DOT	16384	/* Check the paths ".", ".." for staleness */
 #define FS_RENAME_DOES_D_MOVE	32768	/* FS will handle d_move()
 					 * during rename() internally.

--

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC PATCH 1/4] pass open file to ->setattr()
  2007-08-09 15:27 ` [RFC PATCH 1/4] pass open file to ->setattr() miklos
@ 2007-08-09 15:35   ` J. Bruce Fields
  2007-08-09 15:41     ` Miklos Szeredi
  0 siblings, 1 reply; 10+ messages in thread
From: J. Bruce Fields @ 2007-08-09 15:35 UTC (permalink / raw)
  To: miklos; +Cc: linux-fsdevel, linux-kernel, Al Viro, Christoph Hellwig

On Thu, Aug 09, 2007 at 05:27:45PM +0200, miklos@szeredi.hu wrote:
> This is needed to be able to correctly implement open-unlink-fsetattr
> semantics in some filesystem such as sshfs, without having to resort
> to "silly-renaming".

How do you plan to do that?

--b.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC PATCH 1/4] pass open file to ->setattr()
  2007-08-09 15:35   ` J. Bruce Fields
@ 2007-08-09 15:41     ` Miklos Szeredi
  0 siblings, 0 replies; 10+ messages in thread
From: Miklos Szeredi @ 2007-08-09 15:41 UTC (permalink / raw)
  To: bfields; +Cc: miklos, linux-fsdevel, linux-kernel, viro, hch

> > This is needed to be able to correctly implement open-unlink-fsetattr
> > semantics in some filesystem such as sshfs, without having to resort
> > to "silly-renaming".
> 
> How do you plan to do that?

Easy: the SFTP protocol has stateful opens and defines an FSTAT call.

Miklos

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC PATCH 4/4] VFS: allow filesystem to override mknod capability checks
  2007-08-09 15:27 ` [RFC PATCH 4/4] VFS: allow filesystem to override mknod capability checks miklos
@ 2007-08-09 19:20   ` Serge E. Hallyn
  2007-08-09 20:10     ` Miklos Szeredi
  0 siblings, 1 reply; 10+ messages in thread
From: Serge E. Hallyn @ 2007-08-09 19:20 UTC (permalink / raw)
  To: miklos; +Cc: linux-fsdevel, linux-kernel, Al Viro, Christoph Hellwig

Quoting miklos@szeredi.hu (miklos@szeredi.hu):
> From: Miklos Szeredi <mszeredi@suse.cz>
> 
> Add a new filesystem flag, that results in the VFS not checking if the
> current process has enough privileges to do an mknod().
> 
> This is needed on filesystems, where an unprivileged user may be able
> to create a device node, without causing security problems.
> 
> One such example is "mountlo" a loopback mount utility implemented
> with fuse and UML, which runs as an unprivileged userspace process.
> In this case the user does in fact have the right to create device
> nodes within the filesystem image, as long as the user has write
> access to the image.  Since the filesystem is mounted with "nodev",
> adding device nodes is not a security concern.

Could we enforce at do_new_mount() that if
type->fs_flags&FS_MKNOD_CHECKS_PERM then mnt_flags |= MS_NODEV?

> This feature is basically "fuse-only", so it does not make sense to
> change the semantics of ->mknod().
> 
> Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
> ---
> 
> Index: linux/fs/namei.c
> ===================================================================
> --- linux.orig/fs/namei.c	2007-08-09 16:49:07.000000000 +0200
> +++ linux/fs/namei.c	2007-08-09 16:49:12.000000000 +0200
> @@ -1921,7 +1921,8 @@ int vfs_mknod(struct inode *dir, struct 
>  	if (error)
>  		return error;
>  
> -	if ((S_ISCHR(mode) || S_ISBLK(mode)) && !capable(CAP_MKNOD))
> +	if (!(dir->i_sb->s_type->fs_flags & FS_MKNOD_CHECKS_PERM) &&
> +	    (S_ISCHR(mode) || S_ISBLK(mode)) && !capable(CAP_MKNOD))
>  		return -EPERM;
>  
>  	if (!dir->i_op || !dir->i_op->mknod)
> Index: linux/include/linux/fs.h
> ===================================================================
> --- linux.orig/include/linux/fs.h	2007-08-09 16:49:07.000000000 +0200
> +++ linux/include/linux/fs.h	2007-08-09 16:49:12.000000000 +0200
> @@ -97,6 +97,7 @@ extern int dir_notify_enable;
>  #define FS_BINARY_MOUNTDATA 2
>  #define FS_HAS_SUBTYPE 4
>  #define FS_SAFE 8		/* Safe to mount by unprivileged users */
> +#define FS_MKNOD_CHECKS_PERM 16	/* FS checks if device creation is allowed */
>  #define FS_REVAL_DOT	16384	/* Check the paths ".", ".." for staleness */
>  #define FS_RENAME_DOES_D_MOVE	32768	/* FS will handle d_move()
>  					 * during rename() internally.
> 
> --
> -
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC PATCH 4/4] VFS: allow filesystem to override mknod capability checks
  2007-08-09 19:20   ` Serge E. Hallyn
@ 2007-08-09 20:10     ` Miklos Szeredi
  2007-08-10 14:44       ` Serge E. Hallyn
  0 siblings, 1 reply; 10+ messages in thread
From: Miklos Szeredi @ 2007-08-09 20:10 UTC (permalink / raw)
  To: serge; +Cc: miklos, linux-fsdevel, linux-kernel, viro, hch

> > From: Miklos Szeredi <mszeredi@suse.cz>
> > 
> > Add a new filesystem flag, that results in the VFS not checking if the
> > current process has enough privileges to do an mknod().
> > 
> > This is needed on filesystems, where an unprivileged user may be able
> > to create a device node, without causing security problems.
> > 
> > One such example is "mountlo" a loopback mount utility implemented
> > with fuse and UML, which runs as an unprivileged userspace process.
> > In this case the user does in fact have the right to create device
> > nodes within the filesystem image, as long as the user has write
> > access to the image.  Since the filesystem is mounted with "nodev",
> > adding device nodes is not a security concern.
> 
> Could we enforce at do_new_mount() that if
> type->fs_flags&FS_MKNOD_CHECKS_PERM then mnt_flags |= MS_NODEV?

Well, the problem with that is, there will be fuse filesystems which
will want devices to work and for those the capability checks will be
reenabled inside ->mknod().  In fact, for backward compatibility all
filesystems will have the mknod checks, except ones which explicitly
request to turn it off.

Since unprivileged fuse mounts always have "nodev", the only way
security could be screwed up, is if a filesystem running with
privileges disabled the mknod checks.

I will probably add some safety guards against that into the fuse
library, but of course there's no way to stop a privileged user from
screwing up security anyway.

If for example there's a loop mount, where the disk image file is
writable by a user, and root mounts it without "nodev", the user can
still create device nodes (by modifying the image) even if the mknod
checks are enabled.

Miklos

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC PATCH 4/4] VFS: allow filesystem to override mknod capability checks
  2007-08-09 20:10     ` Miklos Szeredi
@ 2007-08-10 14:44       ` Serge E. Hallyn
  0 siblings, 0 replies; 10+ messages in thread
From: Serge E. Hallyn @ 2007-08-10 14:44 UTC (permalink / raw)
  To: Miklos Szeredi; +Cc: serge, linux-fsdevel, linux-kernel, viro, hch

Quoting Miklos Szeredi (miklos@szeredi.hu):
> > > From: Miklos Szeredi <mszeredi@suse.cz>
> > > 
> > > Add a new filesystem flag, that results in the VFS not checking if the
> > > current process has enough privileges to do an mknod().
> > > 
> > > This is needed on filesystems, where an unprivileged user may be able
> > > to create a device node, without causing security problems.
> > > 
> > > One such example is "mountlo" a loopback mount utility implemented
> > > with fuse and UML, which runs as an unprivileged userspace process.
> > > In this case the user does in fact have the right to create device
> > > nodes within the filesystem image, as long as the user has write
> > > access to the image.  Since the filesystem is mounted with "nodev",
> > > adding device nodes is not a security concern.
> > 
> > Could we enforce at do_new_mount() that if
> > type->fs_flags&FS_MKNOD_CHECKS_PERM then mnt_flags |= MS_NODEV?
> 
> Well, the problem with that is, there will be fuse filesystems which
> will want devices to work

Crud, sorry, I forgot all fuse filesystems will have the same fs_flags.

> and for those the capability checks will be
> reenabled inside ->mknod().  In fact, for backward compatibility all
> filesystems will have the mknod checks, except ones which explicitly
> request to turn it off.
> 
> Since unprivileged fuse mounts always have "nodev", the only way

Ah yes, I'd forgotten that we do if (!capable(mknod)) mnt_flags |= MNT_NODEV

No objections then anyway.  Thanks for indulging me :)

> security could be screwed up, is if a filesystem running with
> privileges disabled the mknod checks.
> 
> I will probably add some safety guards against that into the fuse
> library, but of course there's no way to stop a privileged user from
> screwing up security anyway.

Agreed.

> If for example there's a loop mount, where the disk image file is
> writable by a user, and root mounts it without "nodev", the user can
> still create device nodes (by modifying the image) even if the mknod
> checks are enabled.

thanks,
-serge

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2007-08-10 14:44 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-08-09 15:27 [RFC PATCH 0/4] VFS updates miklos
2007-08-09 15:27 ` [RFC PATCH 1/4] pass open file to ->setattr() miklos
2007-08-09 15:35   ` J. Bruce Fields
2007-08-09 15:41     ` Miklos Szeredi
2007-08-09 15:27 ` [RFC PATCH 2/4] pass open file to ->getattr() miklos
2007-08-09 15:27 ` [RFC PATCH 3/4] allow filesystems to implement atomic open+truncate miklos
2007-08-09 15:27 ` [RFC PATCH 4/4] VFS: allow filesystem to override mknod capability checks miklos
2007-08-09 19:20   ` Serge E. Hallyn
2007-08-09 20:10     ` Miklos Szeredi
2007-08-10 14:44       ` Serge E. Hallyn

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).