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