1// SPDX-License-Identifier: GPL-2.0 2/* 3 * fs/epfs/file.c 4 * 5 * Copyright (c) 2022 Huawei Technologies Co., Ltd. 6 * Author: weilongping@huawei.com 7 * Create: 2022-06-10 8 */ 9#include <linux/file.h> 10#include <linux/fs.h> 11#include <linux/fs_stack.h> 12#include <linux/slab.h> 13#include <linux/uaccess.h> 14 15#include "internal.h" 16 17long epfs_set_origin_fd(struct file *file, unsigned long arg) 18{ 19 int fd = -1; 20 struct file *origin_file; 21 struct inode *inode = file->f_inode; 22 struct epfs_inode_info *info = epfs_inode_to_private(inode); 23 int ret = 0; 24 25 if (copy_from_user(&fd, (int *)arg, sizeof(fd))) 26 return -EFAULT; 27 if (IS_ENABLED(CONFIG_EPFS_DEBUG)) 28 epfs_debug("original fd: %d", fd); 29 origin_file = fget(fd); 30 if (!origin_file) { 31 epfs_err("Original file not exist!"); 32 return -EBADF; 33 } 34 35 mutex_lock(&info->lock); 36 if (info->origin_file) { 37 // origin_file had been set. 38 ret = -EEXIST; 39 fput(origin_file); 40 } else if (file_inode(origin_file) == inode) { 41 epfs_err("Could not set itself as origin_file!"); 42 fput(origin_file); 43 ret = -EINVAL; 44 } else { 45 info->origin_file = origin_file; 46 fsstack_copy_attr_all(inode, file_inode(origin_file)); 47 fsstack_copy_inode_size(inode, file_inode(origin_file)); 48 } 49 mutex_unlock(&info->lock); 50 return ret; 51} 52 53int epfs_check_range(struct epfs_range *range) 54{ 55 __u64 index; 56 57 if (range->range[0].begin >= range->range[0].end) { 58 epfs_err("Invalid range: [%llu, %llu)", range->range[0].begin, 59 range->range[0].end); 60 return -EINVAL; 61 } 62 63 for (index = 1; index < range->num; index++) { 64 if ((range->range[index].begin >= range->range[index].end) || 65 (range->range[index].begin < range->range[index - 1].end)) { 66 epfs_err("Invalid range: [%llu, %llu), [%llu, %llu)", 67 range->range[index - 1].begin, 68 range->range[index - 1].end, 69 range->range[index].begin, 70 range->range[index].end); 71 return -EINVAL; 72 } 73 } 74 if (IS_ENABLED(CONFIG_EPFS_DEBUG)) { 75 epfs_debug("epfs_range recv %llu ranges:", range->num); 76 for (index = 0; index < range->num; index++) { 77 epfs_debug("range:[%llu %llu)", 78 range->range[index].begin, 79 range->range[index].end); 80 } 81 epfs_debug("\n"); 82 } 83 return 0; 84} 85 86long epfs_set_range(struct file *file, unsigned long arg) 87{ 88 struct inode *inode = file->f_inode; 89 struct inode *origin_inode; 90 struct epfs_inode_info *info = epfs_inode_to_private(inode); 91 int ret = 0; 92 __u64 num = 0; 93 struct epfs_range *range; 94 struct epfs_range header; 95 96 mutex_lock(&info->lock); 97 if (!info->origin_file) { 98 epfs_err("origin file not exist!"); 99 ret = -EBADF; 100 goto out_set_range; 101 } 102 origin_inode = info->origin_file->f_inode; 103 if (!in_group_p(origin_inode->i_gid)) { 104 epfs_err("Only group member can set range: %u", 105 i_gid_read(origin_inode)); 106 ret = -EACCES; 107 goto out_set_range; 108 } 109 110 if (copy_from_user(&header, (struct epfs_range *)arg, 111 sizeof(header))) { 112 ret = -EFAULT; 113 epfs_err("get header failed!"); 114 goto out_set_range; 115 } 116 num = header.num; 117 118 if (num > EPFS_MAX_RANGES || num <= 0) { 119 ret = -EINVAL; 120 epfs_err("illegal num: %llu", num); 121 goto out_set_range; 122 } 123 124 range = kzalloc(sizeof(header) + sizeof(header.range[0]) * num, 125 GFP_KERNEL); 126 if (!range) { 127 ret = -ENOMEM; 128 goto out_set_range; 129 } 130 131 if (copy_from_user(range, (struct epfs_range *)arg, 132 sizeof(header) + sizeof(header.range[0]) * num)) { 133 ret = -EFAULT; 134 epfs_err("Failed to get range! num: %llu", num); 135 kfree(range); 136 goto out_set_range; 137 } 138 range->num = num; 139 140 ret = epfs_check_range(range); 141 if (ret) { 142 kfree(range); 143 goto out_set_range; 144 } 145 146 info->range = range; 147out_set_range: 148 mutex_unlock(&info->lock); 149 return ret; 150} 151 152static long __epfs_ioctl(struct file *file, unsigned int cmd, 153 unsigned long arg) 154{ 155 long rc = -ENOTTY; 156 157 if (unlikely(_IOC_TYPE(cmd) != EPFS_IOCTL_MAGIC)) { 158 epfs_err("Failed to check epfs magic: %u", _IOC_TYPE(cmd)); 159 return -ENOTTY; 160 } 161 if (unlikely(_IOC_NR(cmd) >= EPFS_IOCTL_MAXNR)) { 162 epfs_err("Failed to check ioctl number: %u", _IOC_NR(cmd)); 163 return -ENOTTY; 164 } 165 if (unlikely(!access_ok((void __user *)arg, _IOC_SIZE(cmd)))) { 166 epfs_err("Failed to check user address space range!"); 167 return -EFAULT; 168 } 169 170 switch (cmd) { 171 case IOC_SET_ORIGIN_FD: 172 return epfs_set_origin_fd(file, arg); 173 case IOC_SET_EPFS_RANGE: 174 return epfs_set_range(file, arg); 175 default: 176 epfs_info("Exit epfs unsupported ioctl, ret: %ld", rc); 177 return rc; 178 } 179} 180 181static long epfs_compat_ioctl(struct file *file, unsigned int cmd, 182 unsigned long arg) 183{ 184 return __epfs_ioctl(file, cmd, arg); 185} 186 187static long epfs_unlocked_ioctl(struct file *file, unsigned int cmd, 188 unsigned long arg) 189{ 190 return __epfs_ioctl(file, cmd, arg); 191} 192 193static ssize_t epfs_read(struct file *file, char __user *buf, size_t count, 194 loff_t *ppos) 195{ 196 struct inode *inode = file_inode(file); 197 struct epfs_inode_info *info = epfs_inode_to_private(inode); 198 struct file *origin_file; 199 struct epfs_range *range; 200 ssize_t ret = 0; 201 loff_t pos = *ppos; 202 loff_t file_size; 203 int current_range_index = 0; 204 205 mutex_lock(&info->lock); 206 range = info->range; 207 if (!range) { 208 ret = -EINVAL; 209 epfs_err("Invalid inode range!"); 210 goto out_read; 211 } 212 213 origin_file = info->origin_file; 214 215 if (!origin_file) { 216 ret = -ENOENT; 217 epfs_err("origin file not exist!"); 218 goto out_read; 219 } 220 221 // Reduce count when it will read over file size. 222 file_size = i_size_read(file_inode(origin_file)); 223 if (IS_ENABLED(CONFIG_EPFS_DEBUG)) 224 if (count > (file_size - pos)) 225 epfs_debug( 226 "count will be truncated to %llu, as file_size=%llu, pos=%llu", 227 file_size - pos, file_size, pos); 228 count = count <= (file_size - pos) ? count : (file_size - pos); 229 230 // Skip ranges before pos. 231 while ((range->range[current_range_index].end <= pos) && 232 (current_range_index < range->num)) 233 current_range_index++; 234 235 while (count > 0) { 236 __u64 current_begin, current_end; 237 238 if (current_range_index >= range->num) { 239 // read directly when epfs range gone; 240 if (IS_ENABLED(CONFIG_EPFS_DEBUG)) 241 epfs_debug( 242 "read from %llu with len %zu at the end.", 243 pos, count); 244 ret = vfs_read(origin_file, buf, count, &pos); 245 break; 246 } 247 current_begin = range->range[current_range_index].begin; 248 current_end = range->range[current_range_index].end; 249 if (current_begin <= pos) { 250 // Clear user memory 251 unsigned long clear_len = current_end - pos; 252 253 clear_len = clear_len < count ? clear_len : count; 254 if (IS_ENABLED(CONFIG_EPFS_DEBUG)) 255 epfs_debug( 256 "clear user memory from %llu with len %lu", 257 pos, clear_len); 258 if (clear_user(buf, clear_len)) { 259 ret = EFAULT; 260 break; 261 } 262 buf += clear_len; 263 pos += clear_len; 264 count -= clear_len; 265 current_range_index++; 266 } else { 267 // Read from pos to (next)current_begin 268 unsigned long read_len = current_begin - pos; 269 270 read_len = read_len < count ? read_len : count; 271 if (IS_ENABLED(CONFIG_EPFS_DEBUG)) 272 epfs_debug( 273 "read from %llu with len %lu", 274 pos, read_len); 275 ret = vfs_read(origin_file, buf, read_len, &pos); 276 if (ret < 0 || ret < read_len) { 277 // Could not read enough bytes; 278 break; 279 } 280 buf += ret; 281 count -= ret; 282 } 283 } 284 285 if (ret >= 0) { 286 ret = pos - *ppos; 287 *ppos = pos; 288 } 289out_read: 290 mutex_unlock(&info->lock); 291 return ret; 292} 293 294const struct file_operations epfs_file_fops = { 295 .unlocked_ioctl = epfs_unlocked_ioctl, 296 .compat_ioctl = epfs_compat_ioctl, 297 .read = epfs_read, 298 .llseek = generic_file_llseek, 299}; 300