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