OSDN Git Service

ANDROID: sdcardfs: Directly pass lower file for mmap
[android-x86/kernel.git] / fs / sdcardfs / file.c
index 0592fac..1f6921e 100644 (file)
@@ -65,7 +65,7 @@ static ssize_t sdcardfs_write(struct file *file, const char __user *buf,
 
        /* check disk space */
        if (!check_min_free_space(dentry, count, 0)) {
-               printk(KERN_INFO "No minimum free space.\n");
+               pr_err("No minimum free space.\n");
                return -ENOSPC;
        }
 
@@ -113,6 +113,10 @@ static long sdcardfs_unlocked_ioctl(struct file *file, unsigned int cmd,
        if (lower_file->f_op->unlocked_ioctl)
                err = lower_file->f_op->unlocked_ioctl(lower_file, cmd, arg);
 
+       /* some ioctls can change inode attributes (EXT2_IOC_SETFLAGS) */
+       if (!err)
+               sdcardfs_copy_and_fix_attrs(file_inode(file),
+                                     file_inode(lower_file));
 out:
        return err;
 }
@@ -160,8 +164,7 @@ static int sdcardfs_mmap(struct file *file, struct vm_area_struct *vma)
        lower_file = sdcardfs_lower_file(file);
        if (willwrite && !lower_file->f_mapping->a_ops->writepage) {
                err = -EINVAL;
-               printk(KERN_ERR "sdcardfs: lower file system does not "
-                      "support writeable mmap\n");
+               pr_err("sdcardfs: lower file system does not support writeable mmap\n");
                goto out;
        }
 
@@ -173,16 +176,10 @@ static int sdcardfs_mmap(struct file *file, struct vm_area_struct *vma)
        if (!SDCARDFS_F(file)->lower_vm_ops) {
                err = lower_file->f_op->mmap(lower_file, vma);
                if (err) {
-                       printk(KERN_ERR "sdcardfs: lower mmap failed %d\n", err);
+                       pr_err("sdcardfs: lower mmap failed %d\n", err);
                        goto out;
                }
                saved_vm_ops = vma->vm_ops; /* save: came from lower ->mmap */
-               err = do_munmap(current->mm, vma->vm_start,
-                               vma->vm_end - vma->vm_start);
-               if (err) {
-                       printk(KERN_ERR "sdcardfs: do_munmap failed %d\n", err);
-                       goto out;
-               }
        }
 
        /*
@@ -195,6 +192,9 @@ static int sdcardfs_mmap(struct file *file, struct vm_area_struct *vma)
        file->f_mapping->a_ops = &sdcardfs_aops; /* set our aops */
        if (!SDCARDFS_F(file)->lower_vm_ops) /* save for our ->fault */
                SDCARDFS_F(file)->lower_vm_ops = saved_vm_ops;
+       vma->vm_private_data = file;
+       get_file(lower_file);
+       vma->vm_file = lower_file;
 
 out:
        return err;
@@ -216,7 +216,7 @@ static int sdcardfs_open(struct inode *inode, struct file *file)
                goto out_err;
        }
 
-       if(!check_caller_access_to_name(d_inode(parent), &dentry->d_name)) {
+       if (!check_caller_access_to_name(d_inode(parent), &dentry->d_name)) {
                err = -EACCES;
                goto out_err;
        }
@@ -248,9 +248,8 @@ static int sdcardfs_open(struct inode *inode, struct file *file)
 
        if (err)
                kfree(SDCARDFS_F(file));
-       else {
+       else
                sdcardfs_copy_and_fix_attrs(inode, sdcardfs_lower_inode(inode));
-       }
 
 out_revert_cred:
        REVERT_CRED(saved_cred);
@@ -320,6 +319,75 @@ static int sdcardfs_fasync(int fd, struct file *file, int flag)
        return err;
 }
 
+/*
+ * Sdcardfs cannot use generic_file_llseek as ->llseek, because it would
+ * only set the offset of the upper file.  So we have to implement our
+ * own method to set both the upper and lower file offsets
+ * consistently.
+ */
+static loff_t sdcardfs_file_llseek(struct file *file, loff_t offset, int whence)
+{
+       int err;
+       struct file *lower_file;
+
+       err = generic_file_llseek(file, offset, whence);
+       if (err < 0)
+               goto out;
+
+       lower_file = sdcardfs_lower_file(file);
+       err = generic_file_llseek(lower_file, offset, whence);
+
+out:
+       return err;
+}
+
+/*
+ * Sdcardfs read_iter, redirect modified iocb to lower read_iter
+ */
+ssize_t sdcardfs_read_iter(struct kiocb *iocb, struct iov_iter *iter)
+{
+       int err;
+       struct file *file = iocb->ki_filp, *lower_file;
+
+       lower_file = sdcardfs_lower_file(file);
+       if (!lower_file->f_op->read_iter) {
+               err = -EINVAL;
+               goto out;
+       }
+
+       get_file(lower_file); /* prevent lower_file from being released */
+       iocb->ki_filp = lower_file;
+       err = lower_file->f_op->read_iter(iocb, iter);
+       /* ? wait IO finish to update atime as ecryptfs ? */
+       iocb->ki_filp = file;
+       fput(lower_file);
+out:
+       return err;
+}
+
+/*
+ * Sdcardfs write_iter, redirect modified iocb to lower write_iter
+ */
+ssize_t sdcardfs_write_iter(struct kiocb *iocb, struct iov_iter *iter)
+{
+       int err;
+       struct file *file = iocb->ki_filp, *lower_file;
+
+       lower_file = sdcardfs_lower_file(file);
+       if (!lower_file->f_op->write_iter) {
+               err = -EINVAL;
+               goto out;
+       }
+
+       get_file(lower_file); /* prevent lower_file from being released */
+       iocb->ki_filp = lower_file;
+       err = lower_file->f_op->write_iter(iocb, iter);
+       iocb->ki_filp = file;
+       fput(lower_file);
+out:
+       return err;
+}
+
 const struct file_operations sdcardfs_main_fops = {
        .llseek         = generic_file_llseek,
        .read           = sdcardfs_read,
@@ -334,11 +402,13 @@ const struct file_operations sdcardfs_main_fops = {
        .release        = sdcardfs_file_release,
        .fsync          = sdcardfs_fsync,
        .fasync         = sdcardfs_fasync,
+       .read_iter      = sdcardfs_read_iter,
+       .write_iter     = sdcardfs_write_iter,
 };
 
 /* trimmed directory options */
 const struct file_operations sdcardfs_dir_fops = {
-       .llseek         = generic_file_llseek,
+       .llseek         = sdcardfs_file_llseek,
        .read           = generic_read_dir,
        .iterate        = sdcardfs_readdir,
        .unlocked_ioctl = sdcardfs_unlocked_ioctl,