static int sdcardfs_mmap(struct file *file, struct vm_area_struct *vma) { int err = 0; bool willwrite; struct file *lower_file; const struct vm_operations_struct *saved_vm_ops = NULL; /* this might be deferred to mmap's writepage */ willwrite = ((vma->vm_flags | VM_SHARED | VM_WRITE) == vma->vm_flags); /* * File systems which do not implement ->writepage may use * generic_file_readonly_mmap as their ->mmap op. If you call * generic_file_readonly_mmap with VM_WRITE, you'd get an -EINVAL. * But we cannot call the lower ->mmap op, so we can't tell that * writeable mappings won't work. Therefore, our only choice is to * check if the lower file system supports the ->writepage, and if * not, return EINVAL (the same error that * generic_file_readonly_mmap returns in that case). */ 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"); goto out; } /* BEGIN PN:DTS2014082500731 , Modified by d00168349, 2014/08/25 */ /* * find and save lower vm_ops. * * XXX: the VFS should have a cleaner way of finding the lower vm_ops */ 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); goto out; } } /* * Next 3 lines are all I need from generic_file_mmap. I definitely * don't want its test for ->readpage which returns -ENOEXEC. */ file_accessed(file); fput(file); get_file(lower_file); vma->vm_file = lower_file; /* DTS2014061002949 for sdcardfs file mmap problem end */ /* END PN:DTS2014082500731 , Modified by d00168349, 2014/08/25 */ 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; out: return err; }
static int sdcardfs_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { int err; struct file *file, *lower_file; const struct vm_operations_struct *lower_vm_ops; struct vm_area_struct lower_vma; memcpy(&lower_vma, vma, sizeof(struct vm_area_struct)); file = lower_vma.vm_file; lower_vm_ops = SDCARDFS_F(file)->lower_vm_ops; BUG_ON(!lower_vm_ops); lower_file = sdcardfs_lower_file(file); /* * XXX: vm_ops->fault may be called in parallel. Because we have to * resort to temporarily changing the vma->vm_file to point to the * lower file, a concurrent invocation of sdcardfs_fault could see a * different value. In this workaround, we keep a different copy of * the vma structure in our stack, so we never expose a different * value of the vma->vm_file called to us, even temporarily. A * better fix would be to change the calling semantics of ->fault to * take an explicit file pointer. */ lower_vma.vm_file = lower_file; err = lower_vm_ops->fault(&lower_vma, vmf); return err; }
// 2014.10.11 merge vm_operations_struct->page_mkwrite from latest wrapfs to fix kernel panic, // when using filemap in lenovo gallery apk static int sdcardfs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) { int err = 0; struct file *file, *lower_file; const struct vm_operations_struct *lower_vm_ops; struct vm_area_struct lower_vma; SDFS_DBG(" Just DBG: sdcardfs page_mkwrite ! \n"); memcpy(&lower_vma, vma, sizeof(struct vm_area_struct)); file = lower_vma.vm_file; lower_vm_ops = SDCARDFS_F(file)->lower_vm_ops; BUG_ON(!lower_vm_ops); if (!lower_vm_ops->page_mkwrite) goto out; lower_file = sdcardfs_lower_file(file); /* * XXX: vm_ops->page_mkwrite may be called in parallel. * Because we have to resort to temporarily changing the * vma->vm_file to point to the lower file, a concurrent * invocation of sdcardfs_page_mkwrite could see a different * value. In this workaround, we keep a different copy of the * vma structure in our stack, so we never expose a different * value of the vma->vm_file called to us, even temporarily. * A better fix would be to change the calling semantics of * ->page_mkwrite to take an explicit file pointer. */ lower_vma.vm_file = lower_file; err = lower_vm_ops->page_mkwrite(&lower_vma, vmf); out: return err; }
/* release all lower object references & free the file info structure */ static int sdcardfs_file_release(struct inode *inode, struct file *file) { struct file *lower_file; lower_file = sdcardfs_lower_file(file); if (lower_file) { sdcardfs_set_lower_file(file, NULL); fput(lower_file); } kfree(SDCARDFS_F(file)); return 0; }
static int sdcardfs_open(struct inode *inode, struct file *file) { int err = 0; struct file *lower_file = NULL; struct path lower_path; struct dentry *dentry = file->f_path.dentry; struct dentry *parent = dget_parent(dentry); struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); const struct cred *saved_cred = NULL; int has_rw; /* don't open unhashed/deleted files */ if (d_unhashed(dentry)) { err = -ENOENT; goto out_err; } has_rw = get_caller_has_rw_locked(sbi->pkgl_id, sbi->options.derive); if(!check_caller_access_to_name(parent->d_inode, dentry->d_name.name, sbi->options.derive, open_flags_to_access_mode(file->f_flags), has_rw)) { printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" " dentry: %s, task:%s\n", __func__, dentry->d_name.name, current->comm); err = -EACCES; goto out_err; } /* save current_cred and override it */ OVERRIDE_CRED(sbi, saved_cred); file->private_data = kzalloc(sizeof(struct sdcardfs_file_info), GFP_KERNEL); if (!SDCARDFS_F(file)) { err = -ENOMEM; goto out_revert_cred; } /* open lower object and link sdcardfs's file struct to lower's */ sdcardfs_get_lower_path(file->f_path.dentry, &lower_path); lower_file = dentry_open(lower_path.dentry, lower_path.mnt, file->f_flags, current_cred()); if (IS_ERR(lower_file)) { err = PTR_ERR(lower_file); lower_file = sdcardfs_lower_file(file); if (lower_file) { sdcardfs_set_lower_file(file, NULL); fput(lower_file); /* fput calls dput for lower_dentry */ } } else { sdcardfs_set_lower_file(file, lower_file); } if (err) kfree(SDCARDFS_F(file)); else { fsstack_copy_attr_all(inode, sdcardfs_lower_inode(inode)); fix_derived_permission(inode); } out_revert_cred: REVERT_CRED(saved_cred); out_err: dput(parent); return err; }
static int sdcardfs_mmap(struct file *file, struct vm_area_struct *vma) { int err = 0; bool willwrite; struct file *lower_file; const struct vm_operations_struct *saved_vm_ops = NULL; #ifdef CONFIG_TIMA_IOMMU_OPT if (vma->vm_end - vma->vm_start) { /* iommu optimization- needs to be turned ON from * the tz side. */ cpu_v7_tima_iommu_opt(vma->vm_start, vma->vm_end, (unsigned long)vma->vm_mm->pgd); } #endif /* CONFIG_TIMA_IOMMU_OPT */ /* this might be deferred to mmap's writepage */ willwrite = ((vma->vm_flags | VM_SHARED | VM_WRITE) == vma->vm_flags); /* * File systems which do not implement ->writepage may use * generic_file_readonly_mmap as their ->mmap op. If you call * generic_file_readonly_mmap with VM_WRITE, you'd get an -EINVAL. * But we cannot call the lower ->mmap op, so we can't tell that * writeable mappings won't work. Therefore, our only choice is to * check if the lower file system supports the ->writepage, and if * not, return EINVAL (the same error that * generic_file_readonly_mmap returns in that case). */ 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"); goto out; } /* * find and save lower vm_ops. * * XXX: the VFS should have a cleaner way of finding the lower vm_ops */ 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); 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; } } /* * Next 3 lines are all I need from generic_file_mmap. I definitely * don't want its test for ->readpage which returns -ENOEXEC. */ file_accessed(file); vma->vm_ops = &sdcardfs_vm_ops; 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; out: return err; }