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