Whamcloud - gitweb
LU-3606 fallocate: Implement fallocate preallocate operation
[fs/lustre-release.git] / lustre / llite / file.c
index 4e76c47..86c5fc4 100644 (file)
@@ -43,6 +43,7 @@
 #include <linux/sched.h>
 #include <linux/user_namespace.h>
 #include <linux/uidgid.h>
+#include <linux/falloc.h>
 
 #include <uapi/linux/lustre/lustre_ioctl.h>
 #include <lustre_swab.h>
@@ -4780,6 +4781,84 @@ int ll_getattr(struct vfsmount *mnt, struct dentry *de, struct kstat *stat)
        return ll_getattr_dentry(de, stat);
 }
 
+int cl_falloc(struct inode *inode, int mode, loff_t offset, loff_t len)
+{
+       struct lu_env *env;
+       struct cl_io *io;
+       __u16 refcheck;
+       int rc; loff_t sa_falloc_end;
+       loff_t size = i_size_read(inode);
+
+       ENTRY;
+
+       env = cl_env_get(&refcheck);
+       if (IS_ERR(env))
+               RETURN(PTR_ERR(env));
+
+       io = vvp_env_thread_io(env);
+       io->ci_obj = ll_i2info(inode)->lli_clob;
+       io->ci_verify_layout = 1;
+       io->u.ci_setattr.sa_parent_fid = lu_object_fid(&io->ci_obj->co_lu);
+       io->u.ci_setattr.sa_falloc_mode = mode;
+       io->u.ci_setattr.sa_falloc_offset = offset;
+       io->u.ci_setattr.sa_falloc_len = len;
+       io->u.ci_setattr.sa_falloc_end = io->u.ci_setattr.sa_falloc_offset +
+               io->u.ci_setattr.sa_falloc_len;
+       io->u.ci_setattr.sa_subtype = CL_SETATTR_FALLOCATE;
+       sa_falloc_end = io->u.ci_setattr.sa_falloc_end;
+       if (sa_falloc_end > size) {
+               /* Check new size against VFS/VM file size limit and rlimit */
+               rc = inode_newsize_ok(inode, sa_falloc_end);
+               if (rc)
+                       goto out;
+               if (sa_falloc_end > ll_file_maxbytes(inode)) {
+                       CDEBUG(D_INODE, "file size too large %llu > %llu\n",
+                              (unsigned long long)(sa_falloc_end),
+                              ll_file_maxbytes(inode));
+                       rc = -EFBIG;
+                       goto out;
+               }
+               io->u.ci_setattr.sa_attr.lvb_size = sa_falloc_end;
+               if (!(mode & FALLOC_FL_KEEP_SIZE))
+                       io->u.ci_setattr.sa_avalid |= ATTR_SIZE;
+       } else {
+               io->u.ci_setattr.sa_attr.lvb_size = size;
+       }
+
+again:
+       if (cl_io_init(env, io, CIT_SETATTR, io->ci_obj) == 0)
+               rc = cl_io_loop(env, io);
+       else
+               rc = io->ci_result;
+
+       cl_io_fini(env, io);
+       if (unlikely(io->ci_need_restart))
+               goto again;
+
+out:
+       cl_env_put(env, &refcheck);
+       RETURN(rc);
+}
+
+long ll_fallocate(struct file *filp, int mode, loff_t offset, loff_t len)
+{
+       struct inode *inode = filp->f_path.dentry->d_inode;
+       int rc;
+
+       /*
+        * Only mode == 0 (which is standard prealloc) is supported now.
+        * Punch is not supported yet.
+        */
+       if (mode & ~FALLOC_FL_KEEP_SIZE)
+               RETURN(-EOPNOTSUPP);
+
+       ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_FALLOCATE, 1);
+
+       rc = cl_falloc(inode, mode, offset, len);
+
+       RETURN(rc);
+}
+
 static int ll_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
                     __u64 start, __u64 len)
 {
@@ -4902,19 +4981,22 @@ int ll_inode_permission(struct inode *inode, int mask)
        cfs_cap_t cap;
        bool squash_id = false;
        ktime_t kstart = ktime_get();
+
        ENTRY;
 
        if (mask & MAY_NOT_BLOCK)
                return -ECHILD;
 
-       /* as root inode are NOT getting validated in lookup operation,
-        * need to do it before permission check. */
+       /*
+        * as root inode are NOT getting validated in lookup operation,
+        * need to do it before permission check.
+        */
 
-        if (inode == inode->i_sb->s_root->d_inode) {
+       if (inode == inode->i_sb->s_root->d_inode) {
                rc = ll_inode_revalidate(inode->i_sb->s_root, IT_LOOKUP);
-                if (rc)
-                        RETURN(rc);
-        }
+               if (rc)
+                       RETURN(rc);
+       }
 
        CDEBUG(D_VFSTRACE, "VFS Op:inode="DFID"(%p), inode mode %x mask %o\n",
               PFID(ll_inode2fid(inode)), inode, inode->i_mode, mask);
@@ -4983,7 +5065,8 @@ struct file_operations ll_file_operations = {
        .llseek         = ll_file_seek,
        .splice_read    = ll_file_splice_read,
        .fsync          = ll_fsync,
-       .flush          = ll_flush
+       .flush          = ll_flush,
+       .fallocate      = ll_fallocate,
 };
 
 struct file_operations ll_file_operations_flock = {
@@ -5009,7 +5092,8 @@ struct file_operations ll_file_operations_flock = {
        .fsync          = ll_fsync,
        .flush          = ll_flush,
        .flock          = ll_file_flock,
-       .lock           = ll_file_flock
+       .lock           = ll_file_flock,
+       .fallocate      = ll_fallocate,
 };
 
 /* These are for -o noflock - to return ENOSYS on flock calls */
@@ -5036,7 +5120,8 @@ struct file_operations ll_file_operations_noflock = {
        .fsync          = ll_fsync,
        .flush          = ll_flush,
        .flock          = ll_file_noflock,
-       .lock           = ll_file_noflock
+       .lock           = ll_file_noflock,
+       .fallocate      = ll_fallocate,
 };
 
 struct inode_operations ll_file_inode_operations = {