>From a876d30dd06dfa772ca2a2184416762843fc3708 Mon Sep 17 00:00:00 2001 From: Dmitry Monakhov Date: Mon, 22 Feb 2010 16:15:57 +0300 Subject: [PATCH] vfs: inode_change_ok have to perform all necessery checks Usually this is the only function which called before inode attributes manipulation. In fact inode_change_ok performs only posix checks. But it new_size check is also important. Otherwise we mail fail in very late stage. Signed-off-by: Dmitry Monakhov --- fs/attr.c | 20 ++++++++++++++++++-- fs/libfs.c | 26 +++++++++++++++++++------- include/linux/fs.h | 5 +++-- 3 files changed, 40 insertions(+), 11 deletions(-) diff --git a/fs/attr.c b/fs/attr.c index 1bca479..007c706 100644 --- a/fs/attr.c +++ b/fs/attr.c @@ -18,7 +18,7 @@ /* Taken over from the old code... */ /* POSIX UID/GID verification for setting inode attributes. */ -int inode_change_ok(const struct inode *inode, struct iattr *attr) +int inode_change_posix_ok(const struct inode *inode, struct iattr *attr) { int retval = -EPERM; unsigned int ia_valid = attr->ia_valid; @@ -60,7 +60,7 @@ fine: error: return retval; } -EXPORT_SYMBOL(inode_change_ok); +EXPORT_SYMBOL(inode_change_posix_ok); /** * inode_newsize_ok - may this inode be truncated to a given size @@ -105,6 +105,22 @@ out_big: } EXPORT_SYMBOL(inode_newsize_ok); +/* + * General verification for setting inode attributes. + */ +int inode_change_ok(const struct inode *inode, struct iattr *attr) +{ + int ret; + ret = inode_change_posix_ok(inode, attr); + if (ret) + return ret; + if (attr->ia_valid & ATTR_SIZE) + ret = inode_newsize_ok(inode, attr->ia_size); + return ret; +} +EXPORT_SYMBOL(inode_change_ok); + + /** * generic_setattr - copy simple metadata updates into the generic inode * @inode: the inode to be updated diff --git a/fs/libfs.c b/fs/libfs.c index 338575b..2aa89d7 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -329,6 +329,23 @@ int simple_rename(struct inode *old_dir, struct dentry *old_dentry, return 0; } +/** + * simple_setsize_nocheck - handle core mm and vfs requirements for file + * size change + * @inode: inode + * @newsize: new file size + * simple_setsize_nocheck must be called with inode_mutex held. + * + * Caller is responsible for all appropriate checks + */ +void simple_setsize_nocheck(struct inode *inode, loff_t newsize) +{ + loff_t oldsize; + oldsize = inode->i_size; + i_size_write(inode, newsize); + truncate_pagecache(inode, oldsize, newsize); +} +EXPORT_SYMBOL(simple_setsize_nocheck); /** * simple_setsize - handle core mm and vfs requirements for file size change @@ -358,18 +375,13 @@ int simple_rename(struct inode *old_dir, struct dentry *old_dentry, */ int simple_setsize(struct inode *inode, loff_t newsize) { - loff_t oldsize; int error; error = inode_newsize_ok(inode, newsize); if (error) return error; - - oldsize = inode->i_size; - i_size_write(inode, newsize); - truncate_pagecache(inode, oldsize, newsize); - - return error; + simple_setsize_nocheck(inode, newsize); + return 0; } EXPORT_SYMBOL(simple_setsize); diff --git a/include/linux/fs.h b/include/linux/fs.h index f5638e5..1097e28 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2361,6 +2361,7 @@ extern int simple_unlink(struct inode *, struct dentry *); extern int simple_rmdir(struct inode *, struct dentry *); extern int simple_rename(struct inode *, struct dentry *, struct inode *, struct dentry *); extern int simple_setsize(struct inode *inode, loff_t newsize); +extern void simple_setsize_nocheck(struct inode *inode, loff_t newsize); extern int simple_sync_file(struct file *, struct dentry *, int); extern int simple_empty(struct dentry *); extern int simple_readpage(struct file *file, struct page *page); @@ -2395,11 +2396,11 @@ extern int buffer_migrate_page(struct address_space *, #define buffer_migrate_page NULL #endif -extern int inode_change_ok(const struct inode *, struct iattr *); +extern int inode_change_posix_ok(const struct inode *, struct iattr *); extern int inode_newsize_ok(const struct inode *, loff_t offset); +extern int inode_change_ok(const struct inode *, struct iattr *); extern int __must_check inode_setattr(struct inode *, const struct iattr *); extern void generic_setattr(struct inode *inode, const struct iattr *attr); - extern void file_update_time(struct file *file); extern int generic_show_options(struct seq_file *m, struct vfsmount *mnt); -- 1.6.6