[GFS2] Clean up duplicate includes in fs/gfs2/
[cascardo/linux.git] / fs / open.c
index be6a457..1d9e5e9 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -26,6 +26,7 @@
 #include <linux/syscalls.h>
 #include <linux/rcupdate.h>
 #include <linux/audit.h>
+#include <linux/falloc.h>
 
 int vfs_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
@@ -255,24 +256,26 @@ static long do_sys_truncate(const char __user * path, loff_t length)
        if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
                goto dput_and_out;
 
-       /*
-        * Make sure that there are no leases.
-        */
-       error = break_lease(inode, FMODE_WRITE);
+       error = get_write_access(inode);
        if (error)
                goto dput_and_out;
 
-       error = get_write_access(inode);
+       /*
+        * Make sure that there are no leases.  get_write_access() protects
+        * against the truncate racing with a lease-granting setlease().
+        */
+       error = break_lease(inode, FMODE_WRITE);
        if (error)
-               goto dput_and_out;
+               goto put_write_and_out;
 
        error = locks_verify_truncate(inode, NULL, length);
        if (!error) {
                DQUOT_INIT(inode);
                error = do_truncate(nd.dentry, length, 0, NULL);
        }
-       put_write_access(inode);
 
+put_write_and_out:
+       put_write_access(inode);
 dput_and_out:
        path_release(&nd);
 out:
@@ -352,6 +355,64 @@ asmlinkage long sys_ftruncate64(unsigned int fd, loff_t length)
 }
 #endif
 
+asmlinkage long sys_fallocate(int fd, int mode, loff_t offset, loff_t len)
+{
+       struct file *file;
+       struct inode *inode;
+       long ret = -EINVAL;
+
+       if (offset < 0 || len <= 0)
+               goto out;
+
+       /* Return error if mode is not supported */
+       ret = -EOPNOTSUPP;
+       if (mode && !(mode & FALLOC_FL_KEEP_SIZE))
+               goto out;
+
+       ret = -EBADF;
+       file = fget(fd);
+       if (!file)
+               goto out;
+       if (!(file->f_mode & FMODE_WRITE))
+               goto out_fput;
+       /*
+        * Revalidate the write permissions, in case security policy has
+        * changed since the files were opened.
+        */
+       ret = security_file_permission(file, MAY_WRITE);
+       if (ret)
+               goto out_fput;
+
+       inode = file->f_path.dentry->d_inode;
+
+       ret = -ESPIPE;
+       if (S_ISFIFO(inode->i_mode))
+               goto out_fput;
+
+       ret = -ENODEV;
+       /*
+        * Let individual file system decide if it supports preallocation
+        * for directories or not.
+        */
+       if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode))
+               goto out_fput;
+
+       ret = -EFBIG;
+       /* Check for wrap through zero too */
+       if (((offset + len) > inode->i_sb->s_maxbytes) || ((offset + len) < 0))
+               goto out_fput;
+
+       if (inode->i_op && inode->i_op->fallocate)
+               ret = inode->i_op->fallocate(inode, mode, offset, len);
+       else
+               ret = -EOPNOTSUPP;
+
+out_fput:
+       fput(file);
+out:
+       return ret;
+}
+
 /*
  * access() needs to use the real uid/gid, not the effective uid/gid.
  * We do this by temporarily clearing all FS-related capabilities and