From 385e3ed4f0b81dd0b0b214050a30d352a71b95f7 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Wed, 16 Dec 2009 12:48:44 -0800 Subject: [PATCH 1/8] alloc_file(): simplify handling of mnt_clone_write() errors When alloc_file() and init_file() were combined, the error handling of mnt_clone_write() was taken into alloc_file() in a somewhat obfuscated way. Since we don't use the error code for anything except warning, we might as well warn directly without an extra variable. Signed-off-by: Roland Dreier Signed-off-by: Al Viro --- fs/file_table.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/fs/file_table.c b/fs/file_table.c index 0afacf65439..69652c5bd5f 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -186,10 +186,8 @@ struct file *alloc_file(struct path *path, fmode_t mode, * that we can do debugging checks at __fput() */ if ((mode & FMODE_WRITE) && !special_file(path->dentry->d_inode->i_mode)) { - int error = 0; file_take_write(file); - error = mnt_clone_write(path->mnt); - WARN_ON(error); + WARN_ON(mnt_clone_write(path->mnt)); } ima_counts_get(file); return file; From 05f94c9b74b0bed5469d97edffae350ec9c1f205 Mon Sep 17 00:00:00 2001 From: Evgeniy Polyakov Date: Fri, 18 Dec 2009 15:40:44 +0300 Subject: [PATCH 2/8] pohmelfs needs I_LOCK Kill debugging printk in question Signed-off-by: Evgeniy Polyakov Signed-off-by: Al Viro --- drivers/staging/pohmelfs/dir.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/staging/pohmelfs/dir.c b/drivers/staging/pohmelfs/dir.c index 6c5b261e9f0..aacd25bfb0c 100644 --- a/drivers/staging/pohmelfs/dir.c +++ b/drivers/staging/pohmelfs/dir.c @@ -722,8 +722,6 @@ static int pohmelfs_remove_entry(struct inode *dir, struct dentry *dentry) if (inode->i_nlink) inode_dec_link_count(inode); } - dprintk("%s: inode: %p, lock: %ld, unhashed: %d.\n", - __func__, pi, inode->i_state & I_LOCK, hlist_unhashed(&inode->i_hash)); return err; } From ed2617585f39dd12fae38c657bba68b9779ea10d Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 21 Dec 2009 17:53:53 +0100 Subject: [PATCH 3/8] fs/compat_ioctl.c: fix build error when !BLOCK No driver uses SG_SET_TRANSFORM any more in Linux, since the ide-scsi driver was removed in 2.6.29. The compat-ioctl cleanup series moved the handling for this around, which broke building without CONFIG_BLOCK. Just remove the code handling it for compat mode. Signed-off-by: Al Viro --- fs/compat_ioctl.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index 14cbc831422..332dd00f089 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -1600,8 +1600,6 @@ static long do_ioctl_trans(int fd, unsigned int cmd, case KDSKBMETA: case KDSKBLED: case KDSETLED: - /* SG stuff */ - case SG_SET_TRANSFORM: /* AUTOFS */ case AUTOFS_IOC_READY: case AUTOFS_IOC_FAIL: From 628ff7c1d8d8466a5ad8078bd0206a130f8b8a51 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Fri, 18 Dec 2009 09:41:24 -0800 Subject: [PATCH 4/8] anonfd: Allow making anon files read-only It seems a couple places such as arch/ia64/kernel/perfmon.c and drivers/infiniband/core/uverbs_main.c could use anon_inode_getfile() instead of a private pseudo-fs + alloc_file(), if only there were a way to get a read-only file. So provide this by having anon_inode_getfile() create a read-only file if we pass O_RDONLY in flags. Signed-off-by: Roland Dreier Signed-off-by: Al Viro --- fs/anon_inodes.c | 12 ++++++++++-- fs/eventfd.c | 2 +- fs/eventpoll.c | 2 +- fs/signalfd.c | 2 +- fs/timerfd.c | 2 +- kernel/perf_event.c | 2 +- virt/kvm/kvm_main.c | 4 ++-- 7 files changed, 17 insertions(+), 9 deletions(-) diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c index 2c994591f4d..598237e9722 100644 --- a/fs/anon_inodes.c +++ b/fs/anon_inodes.c @@ -89,11 +89,19 @@ struct file *anon_inode_getfile(const char *name, struct qstr this; struct path path; struct file *file; + fmode_t mode; int error; if (IS_ERR(anon_inode_inode)) return ERR_PTR(-ENODEV); + switch (flags & O_ACCMODE) { + case O_RDONLY: mode = FMODE_READ; break; + case O_WRONLY: mode = FMODE_WRITE; break; + case O_RDWR: mode = FMODE_READ | FMODE_WRITE; break; + default: return ERR_PTR(-EINVAL); + } + if (fops->owner && !try_module_get(fops->owner)) return ERR_PTR(-ENOENT); @@ -121,13 +129,13 @@ struct file *anon_inode_getfile(const char *name, d_instantiate(path.dentry, anon_inode_inode); error = -ENFILE; - file = alloc_file(&path, FMODE_READ | FMODE_WRITE, fops); + file = alloc_file(&path, mode, fops); if (!file) goto err_dput; file->f_mapping = anon_inode_inode->i_mapping; file->f_pos = 0; - file->f_flags = O_RDWR | (flags & O_NONBLOCK); + file->f_flags = flags & (O_ACCMODE | O_NONBLOCK); file->f_version = 0; file->private_data = priv; diff --git a/fs/eventfd.c b/fs/eventfd.c index 8b47e4200e6..d26402ff06e 100644 --- a/fs/eventfd.c +++ b/fs/eventfd.c @@ -339,7 +339,7 @@ struct file *eventfd_file_create(unsigned int count, int flags) ctx->flags = flags; file = anon_inode_getfile("[eventfd]", &eventfd_fops, ctx, - flags & EFD_SHARED_FCNTL_FLAGS); + O_RDWR | (flags & EFD_SHARED_FCNTL_FLAGS)); if (IS_ERR(file)) eventfd_free_ctx(ctx); diff --git a/fs/eventpoll.c b/fs/eventpoll.c index 366c503f965..bd056a5b4ef 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c @@ -1206,7 +1206,7 @@ SYSCALL_DEFINE1(epoll_create1, int, flags) * a file structure and a free file descriptor. */ error = anon_inode_getfd("[eventpoll]", &eventpoll_fops, ep, - flags & O_CLOEXEC); + O_RDWR | (flags & O_CLOEXEC)); if (error < 0) ep_free(ep); diff --git a/fs/signalfd.c b/fs/signalfd.c index b07565c9438..1dabe4ee02f 100644 --- a/fs/signalfd.c +++ b/fs/signalfd.c @@ -236,7 +236,7 @@ SYSCALL_DEFINE4(signalfd4, int, ufd, sigset_t __user *, user_mask, * anon_inode_getfd() will install the fd. */ ufd = anon_inode_getfd("[signalfd]", &signalfd_fops, ctx, - flags & (O_CLOEXEC | O_NONBLOCK)); + O_RDWR | (flags & (O_CLOEXEC | O_NONBLOCK))); if (ufd < 0) kfree(ctx); } else { diff --git a/fs/timerfd.c b/fs/timerfd.c index b042bd7034b..1bfc95ad5f7 100644 --- a/fs/timerfd.c +++ b/fs/timerfd.c @@ -200,7 +200,7 @@ SYSCALL_DEFINE2(timerfd_create, int, clockid, int, flags) hrtimer_init(&ctx->tmr, clockid, HRTIMER_MODE_ABS); ufd = anon_inode_getfd("[timerfd]", &timerfd_fops, ctx, - flags & TFD_SHARED_FCNTL_FLAGS); + O_RDWR | (flags & TFD_SHARED_FCNTL_FLAGS)); if (ufd < 0) kfree(ctx); diff --git a/kernel/perf_event.c b/kernel/perf_event.c index e0eb4a2fe18..1f38270f08c 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c @@ -4724,7 +4724,7 @@ SYSCALL_DEFINE5(perf_event_open, if (IS_ERR(event)) goto err_put_context; - err = anon_inode_getfd("[perf_event]", &perf_fops, event, 0); + err = anon_inode_getfd("[perf_event]", &perf_fops, event, O_RDWR); if (err < 0) goto err_free_put_context; diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index e1f2bf8d7b1..b5af8816761 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -1177,7 +1177,7 @@ static struct file_operations kvm_vcpu_fops = { */ static int create_vcpu_fd(struct kvm_vcpu *vcpu) { - return anon_inode_getfd("kvm-vcpu", &kvm_vcpu_fops, vcpu, 0); + return anon_inode_getfd("kvm-vcpu", &kvm_vcpu_fops, vcpu, O_RDWR); } /* @@ -1638,7 +1638,7 @@ static int kvm_dev_ioctl_create_vm(void) kvm = kvm_create_vm(); if (IS_ERR(kvm)) return PTR_ERR(kvm); - fd = anon_inode_getfd("kvm-vm", &kvm_vm_fops, kvm, 0); + fd = anon_inode_getfd("kvm-vm", &kvm_vm_fops, kvm, O_RDWR); if (fd < 0) kvm_put_kvm(kvm); From 482928d59db668b8d82a48717f78986d8cea72e9 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 19 Dec 2009 10:10:39 -0500 Subject: [PATCH 5/8] Fix f_flags/f_mode in case of lookup_instantiate_filp() from open(pathname, 3) Just set f_flags when shoving struct file into nameidata; don't postpone that until __dentry_open(). do_filp_open() has correct value; lookup_instantiate_filp() doesn't - we lose the difference between O_RDWR and 3 by that point. We still set .intent.open.flags, so no fs code needs to be changed. Signed-off-by: Al Viro --- fs/internal.h | 7 +++++++ fs/namei.c | 6 ++++-- fs/open.c | 13 ++++++------- include/linux/namei.h | 2 -- 4 files changed, 17 insertions(+), 11 deletions(-) diff --git a/fs/internal.h b/fs/internal.h index f67cd141d9a..e96a1667d74 100644 --- a/fs/internal.h +++ b/fs/internal.h @@ -85,3 +85,10 @@ extern struct file *get_empty_filp(void); * super.c */ extern int do_remount_sb(struct super_block *, int, void *, int); + +/* + * open.c + */ +struct nameidata; +extern struct file *nameidata_to_filp(struct nameidata *); +extern void release_open_intent(struct nameidata *); diff --git a/fs/namei.c b/fs/namei.c index dad4b80257d..d517f73aa36 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1640,6 +1640,7 @@ struct file *do_filp_open(int dfd, const char *pathname, if (filp == NULL) return ERR_PTR(-ENFILE); nd.intent.open.file = filp; + filp->f_flags = open_flag; nd.intent.open.flags = flag; nd.intent.open.create_mode = 0; error = do_path_lookup(dfd, pathname, @@ -1685,6 +1686,7 @@ struct file *do_filp_open(int dfd, const char *pathname, if (filp == NULL) goto exit_parent; nd.intent.open.file = filp; + filp->f_flags = open_flag; nd.intent.open.flags = flag; nd.intent.open.create_mode = mode; dir = nd.path.dentry; @@ -1725,7 +1727,7 @@ do_last: mnt_drop_write(nd.path.mnt); goto exit; } - filp = nameidata_to_filp(&nd, open_flag); + filp = nameidata_to_filp(&nd); mnt_drop_write(nd.path.mnt); if (nd.root.mnt) path_put(&nd.root); @@ -1789,7 +1791,7 @@ ok: mnt_drop_write(nd.path.mnt); goto exit; } - filp = nameidata_to_filp(&nd, open_flag); + filp = nameidata_to_filp(&nd); if (!IS_ERR(filp)) { error = ima_path_check(&filp->f_path, filp->f_mode & (MAY_READ | MAY_WRITE | MAY_EXEC)); diff --git a/fs/open.c b/fs/open.c index ca69241796b..6daee28f6e8 100644 --- a/fs/open.c +++ b/fs/open.c @@ -821,15 +821,14 @@ static inline int __get_file_write_access(struct inode *inode, } static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt, - int flags, struct file *f, + struct file *f, int (*open)(struct inode *, struct file *), const struct cred *cred) { struct inode *inode; int error; - f->f_flags = flags; - f->f_mode = (__force fmode_t)((flags+1) & O_ACCMODE) | FMODE_LSEEK | + f->f_mode = (__force fmode_t)((f->f_flags+1) & O_ACCMODE) | FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE; inode = dentry->d_inode; if (f->f_mode & FMODE_WRITE) { @@ -930,7 +929,6 @@ struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry *dentry if (IS_ERR(dentry)) goto out_err; nd->intent.open.file = __dentry_open(dget(dentry), mntget(nd->path.mnt), - nd->intent.open.flags - 1, nd->intent.open.file, open, cred); out: @@ -949,7 +947,7 @@ EXPORT_SYMBOL_GPL(lookup_instantiate_filp); * * Note that this function destroys the original nameidata */ -struct file *nameidata_to_filp(struct nameidata *nd, int flags) +struct file *nameidata_to_filp(struct nameidata *nd) { const struct cred *cred = current_cred(); struct file *filp; @@ -958,7 +956,7 @@ struct file *nameidata_to_filp(struct nameidata *nd, int flags) filp = nd->intent.open.file; /* Has the filesystem initialised the file for us? */ if (filp->f_path.dentry == NULL) - filp = __dentry_open(nd->path.dentry, nd->path.mnt, flags, filp, + filp = __dentry_open(nd->path.dentry, nd->path.mnt, filp, NULL, cred); else path_put(&nd->path); @@ -997,7 +995,8 @@ struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags, return ERR_PTR(error); } - return __dentry_open(dentry, mnt, flags, f, NULL, cred); + f->f_flags = flags; + return __dentry_open(dentry, mnt, f, NULL, cred); } EXPORT_SYMBOL(dentry_open); diff --git a/include/linux/namei.h b/include/linux/namei.h index 02894675028..05b441d9364 100644 --- a/include/linux/namei.h +++ b/include/linux/namei.h @@ -72,8 +72,6 @@ extern int vfs_path_lookup(struct dentry *, struct vfsmount *, extern struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry *dentry, int (*open)(struct inode *, struct file *)); -extern struct file *nameidata_to_filp(struct nameidata *nd, int flags); -extern void release_open_intent(struct nameidata *); extern struct dentry *lookup_one_len(const char *, struct dentry *, int); From 5300990c0370e804e49d9a59d928c5d53fb73487 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 19 Dec 2009 10:15:07 -0500 Subject: [PATCH 6/8] Sanitize f_flags helpers * pull ACC_MODE to fs.h; we have several copies all over the place * nightmarish expression calculating f_mode by f_flags deserves a helper too (OPEN_FMODE(flags)) Signed-off-by: Al Viro --- fs/anon_inodes.c | 10 +--------- fs/namei.c | 2 -- fs/open.c | 2 +- include/linux/fs.h | 3 +++ kernel/auditsc.c | 1 - security/tomoyo/file.c | 1 - 6 files changed, 5 insertions(+), 14 deletions(-) diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c index 598237e9722..9f0bf13291e 100644 --- a/fs/anon_inodes.c +++ b/fs/anon_inodes.c @@ -89,19 +89,11 @@ struct file *anon_inode_getfile(const char *name, struct qstr this; struct path path; struct file *file; - fmode_t mode; int error; if (IS_ERR(anon_inode_inode)) return ERR_PTR(-ENODEV); - switch (flags & O_ACCMODE) { - case O_RDONLY: mode = FMODE_READ; break; - case O_WRONLY: mode = FMODE_WRITE; break; - case O_RDWR: mode = FMODE_READ | FMODE_WRITE; break; - default: return ERR_PTR(-EINVAL); - } - if (fops->owner && !try_module_get(fops->owner)) return ERR_PTR(-ENOENT); @@ -129,7 +121,7 @@ struct file *anon_inode_getfile(const char *name, d_instantiate(path.dentry, anon_inode_inode); error = -ENFILE; - file = alloc_file(&path, mode, fops); + file = alloc_file(&path, OPEN_FMODE(flags), fops); if (!file) goto err_dput; file->f_mapping = anon_inode_inode->i_mapping; diff --git a/fs/namei.c b/fs/namei.c index d517f73aa36..68921d9b530 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -37,8 +37,6 @@ #include "internal.h" -#define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE]) - /* [Feb-1997 T. Schoebel-Theuer] * Fundamental changes in the pathname lookup mechanisms (namei) * were necessary because of omirr. The reason is that omirr needs diff --git a/fs/open.c b/fs/open.c index 6daee28f6e8..040cef72bc0 100644 --- a/fs/open.c +++ b/fs/open.c @@ -828,7 +828,7 @@ static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt, struct inode *inode; int error; - f->f_mode = (__force fmode_t)((f->f_flags+1) & O_ACCMODE) | FMODE_LSEEK | + f->f_mode = OPEN_FMODE(f->f_flags) | FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE; inode = dentry->d_inode; if (f->f_mode & FMODE_WRITE) { diff --git a/include/linux/fs.h b/include/linux/fs.h index cca191933ff..9e13b533aae 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2464,5 +2464,8 @@ int proc_nr_files(struct ctl_table *table, int write, int __init get_filesystem_list(char *buf); +#define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE]) +#define OPEN_FMODE(flag) ((__force fmode_t)((flag + 1) & O_ACCMODE)) + #endif /* __KERNEL__ */ #endif /* _LINUX_FS_H */ diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 267e484f019..fc0f928167e 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -250,7 +250,6 @@ struct audit_context { #endif }; -#define ACC_MODE(x) ("\004\002\006\006"[(x)&O_ACCMODE]) static inline int open_arg(int flags, int mask) { int n = ACC_MODE(flags); diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c index 8346938809b..9a6c58881c0 100644 --- a/security/tomoyo/file.c +++ b/security/tomoyo/file.c @@ -12,7 +12,6 @@ #include "common.h" #include "tomoyo.h" #include "realpath.h" -#define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE]) /* * tomoyo_globally_readable_file_entry is a structure which is used for holding From 95ebc3a7930d5965b00bbedbf36bfd3eb9124d65 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Wed, 28 Oct 2009 01:46:33 +0100 Subject: [PATCH 7/8] Remove obsolete comment in fs.h This question was determined to be a bug which was fixed in commit 4a3b0a49. Signed-off-by: Andreas Gruenbacher Cc: Jan Blunck Signed-off-by: Al Viro --- include/linux/fs.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/linux/fs.h b/include/linux/fs.h index 9e13b533aae..7e3012e0ac0 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1624,8 +1624,6 @@ struct super_operations { * on the bit address once it is done. * * Q: What is the difference between I_WILL_FREE and I_FREEING? - * Q: igrab() only checks on (I_FREEING|I_WILL_FREE). Should it also check on - * I_CLEAR? If not, why? */ #define I_DIRTY_SYNC 1 #define I_DIRTY_DATASYNC 2 From 28ba0ec64ca0f6ad2b0338ccec0b00a4e64e7a69 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 6 Nov 2009 11:31:06 +0000 Subject: [PATCH 8/8] jfs: Fix 32bit build warning loff_t is a type that isn't entirely dependant upon 32 v 64bit choice Signed-off-by: Alan Cox Signed-off-by: Al Viro --- fs/jfs/super.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/jfs/super.c b/fs/jfs/super.c index 2234c73fc57..d929a822a74 100644 --- a/fs/jfs/super.c +++ b/fs/jfs/super.c @@ -524,7 +524,7 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent) * Page cache is indexed by long. * I would use MAX_LFS_FILESIZE, but it's only half as big */ - sb->s_maxbytes = min(((u64) PAGE_CACHE_SIZE << 32) - 1, sb->s_maxbytes); + sb->s_maxbytes = min(((u64) PAGE_CACHE_SIZE << 32) - 1, (u64)sb->s_maxbytes); #endif sb->s_time_gran = 1; return 0;