From 0abbb609ac511fc226b8b1082613193c8ecf8324 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 28 May 2010 19:06:15 -0400 Subject: [PATCH 1/7] mqueue doesn't need make_bad_inode() It never hashes them anyway and does final iput() immediately afterwards. With ->drop_inode() being generic_delete_inode()... Signed-off-by: Al Viro --- ipc/mqueue.c | 1 - 1 file changed, 1 deletion(-) diff --git a/ipc/mqueue.c b/ipc/mqueue.c index 5108232f93d4..c93fd3faac2d 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -176,7 +176,6 @@ static struct inode *mqueue_get_inode(struct super_block *sb, } return inode; out_inode: - make_bad_inode(inode); iput(inode); return NULL; } From 971b2e8a3f5dc0cbef19ec1a77b6d20237aa751e Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 28 May 2010 21:32:44 -0400 Subject: [PATCH 2/7] fix the deadlock in qib_fs get_sb_single() calls fill_super with superblock locked; calling deactivate_super() will deadlock immedately. Moreover, if fill_super callback returns an error, get_sb_single() will release the reference to superblock itself just fine. Signed-off-by: Al Viro --- drivers/infiniband/hw/qib/qib_fs.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/infiniband/hw/qib/qib_fs.c b/drivers/infiniband/hw/qib/qib_fs.c index edef8527eb34..844954bf417b 100644 --- a/drivers/infiniband/hw/qib/qib_fs.c +++ b/drivers/infiniband/hw/qib/qib_fs.c @@ -542,10 +542,8 @@ static int qibfs_fill_super(struct super_block *sb, void *data, int silent) list_for_each_entry_safe(dd, tmp, &qib_dev_list, list) { spin_unlock_irqrestore(&qib_devs_lock, flags); ret = add_cntr_files(sb, dd); - if (ret) { - deactivate_super(sb); + if (ret) goto bail; - } spin_lock_irqsave(&qib_devs_lock, flags); } From 7d683a09990ff095a91b6e724ecee0ff8733274a Mon Sep 17 00:00:00 2001 From: Roberto Sassu Date: Thu, 3 Jun 2010 11:58:28 +0200 Subject: [PATCH 3/7] wrong type for 'magic' argument in simple_fill_super() It's used to superblock ->s_magic, which is unsigned long. Signed-off-by: Roberto Sassu Reviewed-by: Mimi Zohar Signed-off-by: Eric Paris CC: stable@kernel.org Signed-off-by: Al Viro --- fs/libfs.c | 3 ++- include/linux/fs.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/fs/libfs.c b/fs/libfs.c index 09e1016eb774..dcaf972cbf1b 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -489,7 +489,8 @@ int simple_write_end(struct file *file, struct address_space *mapping, * unique inode values later for this filesystem, then you must take care * to pass it an appropriate max_reserved value to avoid collisions. */ -int simple_fill_super(struct super_block *s, int magic, struct tree_descr *files) +int simple_fill_super(struct super_block *s, unsigned long magic, + struct tree_descr *files) { struct inode *inode; struct dentry *root; diff --git a/include/linux/fs.h b/include/linux/fs.h index 3428393942a6..471e1ff5079a 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2388,7 +2388,7 @@ extern const struct file_operations simple_dir_operations; extern const struct inode_operations simple_dir_inode_operations; struct tree_descr { char *name; const struct file_operations *ops; int mode; }; struct dentry *d_alloc_name(struct dentry *, const char *); -extern int simple_fill_super(struct super_block *, int, struct tree_descr *); +extern int simple_fill_super(struct super_block *, unsigned long, struct tree_descr *); extern int simple_pin_fs(struct file_system_type *, struct vfsmount **mount, int *count); extern void simple_release_fs(struct vfsmount **mount, int *count); From 5b54470daded19d83ea2bbf5f6bc12662942cd63 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 3 Jun 2010 12:35:42 +0200 Subject: [PATCH 4/7] fcntl: return -EFAULT if copy_to_user fails copy_to_user() returns the number of bytes remaining, but we want to return -EFAULT. ret = fcntl(fd, F_SETOWN_EX, NULL); With the original code ret would be 8 here. V2: Takuya Yoshikawa pointed out a similar issue in f_getown_ex() Signed-off-by: Dan Carpenter Signed-off-by: Al Viro --- fs/fcntl.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/fs/fcntl.c b/fs/fcntl.c index f74d270ba155..51e11bf5708f 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c @@ -274,7 +274,7 @@ static int f_setown_ex(struct file *filp, unsigned long arg) ret = copy_from_user(&owner, owner_p, sizeof(owner)); if (ret) - return ret; + return -EFAULT; switch (owner.type) { case F_OWNER_TID: @@ -332,8 +332,11 @@ static int f_getown_ex(struct file *filp, unsigned long arg) } read_unlock(&filp->f_owner.lock); - if (!ret) + if (!ret) { ret = copy_to_user(owner_p, &owner, sizeof(owner)); + if (ret) + ret = -EFAULT; + } return ret; } From 8718d36cf99f5acf0f37487557ec25aee54b930b Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Mon, 31 May 2010 17:58:02 +1000 Subject: [PATCH 5/7] fix setattr error handling in sysfs, configfs sysfs and configfs setattr functions have error cases after the generic inode's attributes have been changed. Fix consistency by changing the generic inode attributes only when it is guaranteed to succeed. Signed-off-by: Nick Piggin Signed-off-by: Al Viro --- fs/configfs/inode.c | 9 ++++----- fs/sysfs/inode.c | 6 ++++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/fs/configfs/inode.c b/fs/configfs/inode.c index 41645142b88b..cf78d44a8d6a 100644 --- a/fs/configfs/inode.c +++ b/fs/configfs/inode.c @@ -72,10 +72,6 @@ int configfs_setattr(struct dentry * dentry, struct iattr * iattr) if (!sd) return -EINVAL; - error = simple_setattr(dentry, iattr); - if (error) - return error; - sd_iattr = sd->s_iattr; if (!sd_iattr) { /* setting attributes for the first time, allocate now */ @@ -89,9 +85,12 @@ int configfs_setattr(struct dentry * dentry, struct iattr * iattr) sd_iattr->ia_atime = sd_iattr->ia_mtime = sd_iattr->ia_ctime = CURRENT_TIME; sd->s_iattr = sd_iattr; } - /* attributes were changed atleast once in past */ + error = simple_setattr(dentry, iattr); + if (error) + return error; + if (ia_valid & ATTR_UID) sd_iattr->ia_uid = iattr->ia_uid; if (ia_valid & ATTR_GID) diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index bde1a4c3679a..0835a3b70e03 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -117,11 +117,13 @@ int sysfs_setattr(struct dentry *dentry, struct iattr *iattr) if (error) goto out; + error = sysfs_sd_setattr(sd, iattr); + if (error) + goto out; + /* this ignores size changes */ generic_setattr(inode, iattr); - error = sysfs_sd_setattr(sd, iattr); - out: mutex_unlock(&sysfs_mutex); return error; From af5a30d8cfcfc561336f982b06345d6b815e0bb3 Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Thu, 3 Jun 2010 22:01:46 +1000 Subject: [PATCH 6/7] fix truncate inode time modification breakage mtime and ctime should be changed only if the file size has actually changed. Patches changing ext2 and tmpfs from vmtruncate to new truncate sequence has caused regressions where they always update timestamps. There is some strange cases in POSIX where truncate(2) must not update times unless the size has acutally changed, see 6e656be89. This area is all still rather buggy in different ways in a lot of filesystems and needs a cleanup and audit (ideally the vfs will provide a simple attribute or call to direct all filesystems exactly which attributes to change). But coming up with the best solution will take a while and is not appropriate for rc anyway. So fix recent regression for now. Signed-off-by: Nick Piggin Signed-off-by: Al Viro --- fs/ext2/inode.c | 2 +- mm/shmem.c | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index 19214435b752..3675088cb88c 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -1552,7 +1552,7 @@ int ext2_setattr(struct dentry *dentry, struct iattr *iattr) if (error) return error; } - if (iattr->ia_valid & ATTR_SIZE) { + if (iattr->ia_valid & ATTR_SIZE && iattr->ia_size != inode->i_size) { error = ext2_setsize(inode, iattr->ia_size); if (error) return error; diff --git a/mm/shmem.c b/mm/shmem.c index 7e5030ae18ff..f65f84062db5 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -764,10 +764,11 @@ done2: static int shmem_notify_change(struct dentry *dentry, struct iattr *attr) { struct inode *inode = dentry->d_inode; + loff_t newsize = attr->ia_size; int error; - if (S_ISREG(inode->i_mode) && (attr->ia_valid & ATTR_SIZE)) { - loff_t newsize = attr->ia_size; + if (S_ISREG(inode->i_mode) && (attr->ia_valid & ATTR_SIZE) + && newsize != inode->i_size) { struct page *page = NULL; if (newsize < inode->i_size) { From 01afaf61983d08ed1c9e5e8f2fcf4f40e9008033 Mon Sep 17 00:00:00 2001 From: Andrew Hendry Date: Fri, 4 Jun 2010 22:51:24 +1000 Subject: [PATCH 7/7] Minix: Clean up left over label Remove a left over fail label. Signed-off-by: Andrew Hendry Signed-off-by: Al Viro --- fs/minix/dir.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/fs/minix/dir.c b/fs/minix/dir.c index 91969589131c..1dbf921ca44b 100644 --- a/fs/minix/dir.c +++ b/fs/minix/dir.c @@ -75,10 +75,6 @@ static struct page * dir_get_page(struct inode *dir, unsigned long n) if (!IS_ERR(page)) kmap(page); return page; - -fail: - dir_put_page(page); - return ERR_PTR(-EIO); } static inline void *minix_next_entry(void *de, struct minix_sb_info *sbi)