• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * fs/hmdfs/file_local.c
4  *
5  * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
6  */
7 
8 #include <linux/file.h>
9 #include <linux/fs.h>
10 #include <linux/namei.h>
11 #include <linux/page-flags.h>
12 #include <linux/pagemap.h>
13 #include <linux/sched/signal.h>
14 #include <linux/slab.h>
15 
16 #include "hmdfs_client.h"
17 #include "hmdfs_dentryfile.h"
18 #include "hmdfs_device_view.h"
19 #include "hmdfs_merge_view.h"
20 #include "hmdfs_share.h"
21 #include "hmdfs_trace.h"
22 
update_upper_file(struct file * upper_file,struct file * lower_file)23 static inline void update_upper_file(struct file *upper_file, struct file *lower_file)
24 {
25 	loff_t upper_size = i_size_read(upper_file->f_inode);
26 	loff_t lower_size = i_size_read(lower_file->f_inode);
27 
28 	if (upper_file->f_inode->i_mapping && upper_size != lower_size) {
29 		i_size_write(upper_file->f_inode, lower_size);
30 		truncate_inode_pages(upper_file->f_inode->i_mapping, 0);
31 	}
32 }
33 
hmdfs_file_open_local(struct inode * inode,struct file * file)34 int hmdfs_file_open_local(struct inode *inode, struct file *file)
35 {
36 	int err = 0;
37 	struct file *lower_file = NULL;
38 	struct path lower_path;
39 	struct super_block *sb = inode->i_sb;
40 	const struct cred *cred = hmdfs_sb(sb)->cred;
41 	struct hmdfs_file_info *gfi = kzalloc(sizeof(*gfi), GFP_KERNEL);
42 	struct hmdfs_inode_info *info = hmdfs_i(inode);
43 
44 	if (!gfi) {
45 		err = -ENOMEM;
46 		goto out_err;
47 	}
48 
49 	hmdfs_get_lower_path(file->f_path.dentry, &lower_path);
50 	if (inode->i_mapping != NULL &&
51 	    inode->i_mapping->a_ops == &hmdfs_aops_cloud)
52 		lower_file = dentry_open(&lower_path, file->f_flags | O_DIRECT,
53 					 cred);
54 	else
55 		lower_file = dentry_open(&lower_path, file->f_flags, cred);
56 	hmdfs_put_lower_path(&lower_path);
57 	if (IS_ERR(lower_file)) {
58 		err = PTR_ERR(lower_file);
59 		kfree(gfi);
60 	} else {
61 		gfi->lower_file = lower_file;
62 		file->private_data = gfi;
63 		update_upper_file(file, lower_file);
64 		if (file->f_flags & (O_RDWR | O_WRONLY))
65 			atomic_inc(&info->write_opened);
66 	}
67 out_err:
68 	return err;
69 }
70 
hmdfs_file_release_local(struct inode * inode,struct file * file)71 int hmdfs_file_release_local(struct inode *inode, struct file *file)
72 {
73 	struct hmdfs_file_info *gfi = hmdfs_f(file);
74 	struct hmdfs_inode_info *info = hmdfs_i(inode);
75 
76 	if (file->f_flags & (O_RDWR | O_WRONLY))
77 		atomic_dec(&info->write_opened);
78 	file->private_data = NULL;
79 	fput(gfi->lower_file);
80 	kfree(gfi);
81 	return 0;
82 }
83 
hmdfs_file_accessed(struct file * file)84 static void hmdfs_file_accessed(struct file *file)
85 {
86 	struct file *lower_file = hmdfs_f(file)->lower_file;
87 	struct inode *inode = file_inode(file);
88 	struct inode *lower_inode = file_inode(lower_file);
89 
90 	if (file->f_flags & O_NOATIME)
91 		return;
92 
93 	inode->i_atime = lower_inode->i_atime;
94 }
95 
hmdfs_do_read_iter(struct file * file,struct iov_iter * iter,loff_t * ppos)96 ssize_t hmdfs_do_read_iter(struct file *file, struct iov_iter *iter,
97 	loff_t *ppos)
98 {
99 	ssize_t ret;
100 	struct file *lower_file = hmdfs_f(file)->lower_file;
101 	struct kiocb *iocb;
102 
103 	if (!iov_iter_count(iter))
104 		return 0;
105 
106 	if (file->f_inode->i_mapping != NULL &&
107 	    file->f_inode->i_mapping->a_ops == &hmdfs_aops_cloud) {
108 		iocb = container_of(ppos, struct kiocb, ki_pos);
109 		ret = generic_file_read_iter(iocb, iter);
110 	} else {
111 		ret = vfs_iter_read(lower_file, iter, ppos, 0);
112 	}
113 	hmdfs_file_accessed(file);
114 
115 	return ret;
116 }
117 
hmdfs_local_read_iter(struct kiocb * iocb,struct iov_iter * iter)118 static ssize_t hmdfs_local_read_iter(struct kiocb *iocb, struct iov_iter *iter)
119 {
120 	return hmdfs_do_read_iter(iocb->ki_filp, iter, &iocb->ki_pos);
121 }
122 
hmdfs_file_modified(struct file * file)123 static void hmdfs_file_modified(struct file *file)
124 {
125 	struct inode *inode = file_inode(file);
126 	struct dentry *dentry = file_dentry(file);
127 	struct file *lower_file = hmdfs_f(file)->lower_file;
128 	struct inode *lower_inode = file_inode(lower_file);
129 
130 	inode->i_atime = lower_inode->i_atime;
131 	inode->i_ctime = lower_inode->i_ctime;
132 	inode->i_mtime = lower_inode->i_mtime;
133 	i_size_write(inode, i_size_read(lower_inode));
134 
135 	if (!hmdfs_i_merge(hmdfs_i(inode)))
136 		update_inode_to_dentry(dentry, inode);
137 }
138 
hmdfs_do_write_iter(struct file * file,struct iov_iter * iter,loff_t * ppos)139 ssize_t hmdfs_do_write_iter(struct file *file, struct iov_iter *iter,
140 	loff_t *ppos)
141 {
142 	ssize_t ret;
143 	struct file *lower_file = hmdfs_f(file)->lower_file;
144 	struct inode *inode = file_inode(file);
145 
146 	if (!iov_iter_count(iter))
147 		return 0;
148 
149 	inode_lock(inode);
150 
151 	ret = file_remove_privs(file);
152 	if (ret)
153 		goto out_unlock;
154 
155 	file_start_write(lower_file);
156 	ret = vfs_iter_write(lower_file, iter, ppos, 0);
157 	file_end_write(lower_file);
158 
159 	hmdfs_file_modified(file);
160 
161 out_unlock:
162 	inode_unlock(inode);
163 	return ret;
164 }
165 
hmdfs_local_write_iter(struct kiocb * iocb,struct iov_iter * iter)166 ssize_t hmdfs_local_write_iter(struct kiocb *iocb, struct iov_iter *iter)
167 {
168 	return hmdfs_do_write_iter(iocb->ki_filp, iter, &iocb->ki_pos);
169 }
170 
hmdfs_fsync_local(struct file * file,loff_t start,loff_t end,int datasync)171 int hmdfs_fsync_local(struct file *file, loff_t start, loff_t end, int datasync)
172 {
173 	int err;
174 	struct file *lower_file = hmdfs_f(file)->lower_file;
175 
176 	err = __generic_file_fsync(file, start, end, datasync);
177 	if (err)
178 		goto out;
179 
180 	err = vfs_fsync_range(lower_file, start, end, datasync);
181 out:
182 	return err;
183 }
184 
hmdfs_file_llseek_local(struct file * file,loff_t offset,int whence)185 loff_t hmdfs_file_llseek_local(struct file *file, loff_t offset, int whence)
186 {
187 	loff_t ret;
188 	struct file *lower_file;
189 
190 	lower_file = hmdfs_f(file)->lower_file;
191 	lower_file->f_pos = file->f_pos;
192 	ret = vfs_llseek(lower_file, offset, whence);
193 	file->f_pos = lower_file->f_pos;
194 
195 	return ret;
196 }
197 
hmdfs_file_mmap_local(struct file * file,struct vm_area_struct * vma)198 int hmdfs_file_mmap_local(struct file *file, struct vm_area_struct *vma)
199 {
200 	struct hmdfs_file_info *private_data = file->private_data;
201 	struct file *realfile = NULL;
202 	int ret;
203 
204 	if (!private_data)
205 		return -EINVAL;
206 
207 	realfile = private_data->lower_file;
208 	if (!realfile)
209 		return -EINVAL;
210 
211 	if (!realfile->f_op->mmap)
212 		return -ENODEV;
213 
214 	if (WARN_ON(file != vma->vm_file))
215 		return -EIO;
216 
217 	vma->vm_file = get_file(realfile);
218 	ret = call_mmap(vma->vm_file, vma);
219 	if (ret)
220 		fput(realfile);
221 	else
222 		fput(file);
223 
224 	file_accessed(file);
225 
226 	return ret;
227 }
228 
229 const struct file_operations hmdfs_file_fops_local = {
230 	.owner = THIS_MODULE,
231 	.llseek = hmdfs_file_llseek_local,
232 	.read_iter = hmdfs_local_read_iter,
233 	.write_iter = hmdfs_local_write_iter,
234 	.mmap = hmdfs_file_mmap_local,
235 	.open = hmdfs_file_open_local,
236 	.release = hmdfs_file_release_local,
237 	.fsync = hmdfs_fsync_local,
238 	.splice_read = generic_file_splice_read,
239 	.splice_write = iter_file_splice_write,
240 };
241 
hmdfs_iterate_local(struct file * file,struct dir_context * ctx)242 static int hmdfs_iterate_local(struct file *file, struct dir_context *ctx)
243 {
244 	int err = 0;
245 	loff_t start_pos = ctx->pos;
246 	struct file *lower_file = hmdfs_f(file)->lower_file;
247 
248 	if (ctx->pos == -1)
249 		return 0;
250 
251 	lower_file->f_pos = file->f_pos;
252 	err = iterate_dir(lower_file, ctx);
253 	file->f_pos = lower_file->f_pos;
254 
255 	if (err < 0)
256 		ctx->pos = -1;
257 
258 	trace_hmdfs_iterate_local(file->f_path.dentry, start_pos, ctx->pos,
259 				  err);
260 	return err;
261 }
262 
hmdfs_dir_open_local(struct inode * inode,struct file * file)263 int hmdfs_dir_open_local(struct inode *inode, struct file *file)
264 {
265 	int err = 0;
266 	struct file *lower_file = NULL;
267 	struct dentry *dentry = file->f_path.dentry;
268 	struct path lower_path;
269 	struct super_block *sb = inode->i_sb;
270 	const struct cred *cred = hmdfs_sb(sb)->cred;
271 	struct hmdfs_file_info *gfi = kzalloc(sizeof(*gfi), GFP_KERNEL);
272 
273 	if (!gfi)
274 		return -ENOMEM;
275 
276 	if (IS_ERR_OR_NULL(cred)) {
277 		err = -EPERM;
278 		goto out_err;
279 	}
280 	hmdfs_get_lower_path(dentry, &lower_path);
281 	lower_file = dentry_open(&lower_path, file->f_flags, cred);
282 	hmdfs_put_lower_path(&lower_path);
283 	if (IS_ERR(lower_file)) {
284 		err = PTR_ERR(lower_file);
285 		goto out_err;
286 	} else {
287 		gfi->lower_file = lower_file;
288 		file->private_data = gfi;
289 	}
290 	return err;
291 
292 out_err:
293 	kfree(gfi);
294 	return err;
295 }
296 
hmdfs_dir_release_local(struct inode * inode,struct file * file)297 static int hmdfs_dir_release_local(struct inode *inode, struct file *file)
298 {
299 	struct hmdfs_file_info *gfi = hmdfs_f(file);
300 
301 	file->private_data = NULL;
302 	fput(gfi->lower_file);
303 	kfree(gfi);
304 	return 0;
305 }
306 
307 const struct file_operations hmdfs_dir_ops_local = {
308 	.owner = THIS_MODULE,
309 	.iterate = hmdfs_iterate_local,
310 	.open = hmdfs_dir_open_local,
311 	.release = hmdfs_dir_release_local,
312 	.fsync = hmdfs_fsync_local,
313 };
314 
__hmdfs_ioc_set_share_path(struct file * file,struct hmdfs_share_control * sc)315 static int __hmdfs_ioc_set_share_path(struct file *file,
316 					struct hmdfs_share_control *sc)
317 {
318 	struct super_block *sb = file->f_inode->i_sb;
319 	struct hmdfs_sb_info *sbi = hmdfs_sb(sb);
320 	struct hmdfs_share_table *st = &sbi->share_table;
321 	struct hmdfs_share_item *item;
322 	struct dentry *dentry;
323 	const char *dir_path, *full_path;
324 	struct qstr relative_path;
325 	struct fd src;
326 	int err = 0;
327 
328 	src = fdget(sc->src_fd);
329 	if (!src.file)
330 		return -EBADF;
331 
332 	/* only reg file can be shared */
333 	if (!S_ISREG(src.file->f_inode->i_mode)) {
334 		err = -EPERM;
335 		goto err_out;
336 	}
337 
338 	/* share file is not allowed to be shared */
339 	if (hmdfs_is_share_file(src.file)) {
340 		err = -EPERM;
341 		goto err_out;
342 	}
343 
344 	dentry = src.file->f_path.dentry;
345 	if (dentry->d_name.len > NAME_MAX) {
346 		err = -ENAMETOOLONG;
347 		goto err_out;
348 	}
349 
350 	dir_path = hmdfs_get_dentry_relative_path(file->f_path.dentry);
351 	if (unlikely(!dir_path)) {
352 		err = -ENOMEM;
353 		goto err_out;
354 	}
355 
356 	full_path = hmdfs_connect_path(dir_path, dentry->d_name.name);
357 	if (unlikely(!full_path)) {
358 		err = -ENOMEM;
359 		goto free_dir;
360 	}
361 	relative_path.name = full_path;
362 	relative_path.len = strlen(full_path);
363 
364 	spin_lock(&sbi->share_table.item_list_lock);
365 	item = hmdfs_lookup_share_item(st, &relative_path);
366 	if (!item) {
367 		err = insert_share_item(st, &relative_path, src.file, sc->cid);
368 		goto unlock;
369 	}
370 
371 	if (item->opened)
372 		err = -EEXIST;
373 	else
374 		update_share_item(item, src.file, sc->cid);
375 
376 unlock:
377 	spin_unlock(&sbi->share_table.item_list_lock);
378 	kfree(full_path);
379 free_dir:
380 	kfree(dir_path);
381 err_out:
382 	fdput(src);
383 	return err;
384 }
385 
hmdfs_ioc_set_share_path(struct file * file,unsigned long arg)386 static int hmdfs_ioc_set_share_path(struct file *file, unsigned long arg)
387 {
388 	struct hmdfs_share_control sc;
389 
390 	if (copy_from_user(&sc, (struct hmdfs_share_control __user *)arg,
391 			sizeof(sc)))
392 		return -EFAULT;
393 
394 	return __hmdfs_ioc_set_share_path(file, &sc);
395 }
396 
hmdfs_dir_ioctl_local(struct file * file,unsigned int cmd,unsigned long arg)397 static long hmdfs_dir_ioctl_local(struct file *file, unsigned int cmd,
398 				unsigned long arg)
399 {
400 	switch (cmd) {
401 	case HMDFS_IOC_SET_SHARE_PATH:
402 		return hmdfs_ioc_set_share_path(file, arg);
403 	default:
404 		return -ENOTTY;
405 	}
406 }
407 
408 const struct file_operations hmdfs_dir_ops_share = {
409 	.owner = THIS_MODULE,
410 	.iterate = hmdfs_iterate_local,
411 	.open = hmdfs_dir_open_local,
412 	.release = hmdfs_dir_release_local,
413 	.fsync = hmdfs_fsync_local,
414 	.unlocked_ioctl = hmdfs_dir_ioctl_local,
415 	.compat_ioctl = hmdfs_dir_ioctl_local,
416 };
417