VFS: Make more complete truncate operation available to CacheFiles
authorDavid Howells <dhowells@redhat.com>
Thu, 20 Dec 2012 21:52:36 +0000 (21:52 +0000)
committerDavid Howells <dhowells@redhat.com>
Thu, 20 Dec 2012 22:05:41 +0000 (22:05 +0000)
Make a more complete truncate operation available to CacheFiles (including
security checks and suchlike) so that it can use this to clear invalidated
cache files.

Signed-off-by: David Howells <dhowells@redhat.com>
Acked-by: Al Viro <viro@zeniv.linux.org.uk>
fs/open.c
include/linux/fs.h

index 182d8667b7bd57f5c3c6f738dcdeed0b18c0cbe6..c819bbdab47f6c358838eb276dd902b3cb262780 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -61,33 +61,22 @@ int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs,
        return ret;
 }
 
-static long do_sys_truncate(const char __user *pathname, loff_t length)
+long vfs_truncate(struct path *path, loff_t length)
 {
-       struct path path;
        struct inode *inode;
-       int error;
-
-       error = -EINVAL;
-       if (length < 0) /* sorry, but loff_t says... */
-               goto out;
+       long error;
 
-       error = user_path(pathname, &path);
-       if (error)
-               goto out;
-       inode = path.dentry->d_inode;
+       inode = path->dentry->d_inode;
 
        /* For directories it's -EISDIR, for other non-regulars - -EINVAL */
-       error = -EISDIR;
        if (S_ISDIR(inode->i_mode))
-               goto dput_and_out;
-
-       error = -EINVAL;
+               return -EISDIR;
        if (!S_ISREG(inode->i_mode))
-               goto dput_and_out;
+               return -EINVAL;
 
-       error = mnt_want_write(path.mnt);
+       error = mnt_want_write(path->mnt);
        if (error)
-               goto dput_and_out;
+               goto out;
 
        error = inode_permission(inode, MAY_WRITE);
        if (error)
@@ -111,19 +100,34 @@ static long do_sys_truncate(const char __user *pathname, loff_t length)
 
        error = locks_verify_truncate(inode, NULL, length);
        if (!error)
-               error = security_path_truncate(&path);
+               error = security_path_truncate(path);
        if (!error)
-               error = do_truncate(path.dentry, length, 0, NULL);
+               error = do_truncate(path->dentry, length, 0, NULL);
 
 put_write_and_out:
        put_write_access(inode);
 mnt_drop_write_and_out:
-       mnt_drop_write(path.mnt);
-dput_and_out:
-       path_put(&path);
+       mnt_drop_write(path->mnt);
 out:
        return error;
 }
+EXPORT_SYMBOL_GPL(vfs_truncate);
+
+static long do_sys_truncate(const char __user *pathname, loff_t length)
+{
+       struct path path;
+       int error;
+
+       if (length < 0) /* sorry, but loff_t says... */
+               return -EINVAL;
+
+       error = user_path(pathname, &path);
+       if (!error) {
+               error = vfs_truncate(&path, length);
+               path_put(&path);
+       }
+       return error;
+}
 
 SYSCALL_DEFINE2(truncate, const char __user *, path, long, length)
 {
index a823d4be38e7590275be303d40840bf6bd9117e6..017a15b707e275ff2b73bdc6d48b4b7f204a09f9 100644 (file)
@@ -1999,6 +1999,7 @@ struct filename {
        bool                    separate; /* should "name" be freed? */
 };
 
+extern long vfs_truncate(struct path *, loff_t);
 extern int do_truncate(struct dentry *, loff_t start, unsigned int time_attrs,
                       struct file *filp);
 extern int do_fallocate(struct file *file, int mode, loff_t offset,