• 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 	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 	}
56 out_err:
57 	return err;
58 }
59 
hmdfs_file_release_local(struct inode * inode,struct file * file)60 int 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 
hmdfs_file_accessed(struct file * file)73 static 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 
hmdfs_do_read_iter(struct file * file,struct iov_iter * iter,loff_t * ppos)85 ssize_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 
hmdfs_local_read_iter(struct kiocb * iocb,struct iov_iter * iter)107 static 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 
hmdfs_file_modified(struct file * file)112 static 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 
hmdfs_do_write_iter(struct file * file,struct iov_iter * iter,loff_t * ppos)128 ssize_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 
150 out_unlock:
151 	inode_unlock(inode);
152 	return ret;
153 }
154 
hmdfs_local_write_iter(struct kiocb * iocb,struct iov_iter * iter)155 ssize_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 
hmdfs_fsync_local(struct file * file,loff_t start,loff_t end,int datasync)160 int 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);
170 out:
171 	return err;
172 }
173 
hmdfs_file_llseek_local(struct file * file,loff_t offset,int whence)174 loff_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 
hmdfs_file_mmap_local(struct file * file,struct vm_area_struct * vma)187 int 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 
218 const 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 = generic_file_splice_read,
228 	.splice_write = iter_file_splice_write,
229 };
230 
hmdfs_iterate_local(struct file * file,struct dir_context * ctx)231 static 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 
hmdfs_dir_open_local(struct inode * inode,struct file * file)252 int 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 
281 out_err:
282 	kfree(gfi);
283 	return err;
284 }
285 
hmdfs_dir_release_local(struct inode * inode,struct file * file)286 static 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 
296 const struct file_operations hmdfs_dir_ops_local = {
297 	.owner = THIS_MODULE,
298 	.iterate = hmdfs_iterate_local,
299 	.open = hmdfs_dir_open_local,
300 	.release = hmdfs_dir_release_local,
301 	.fsync = hmdfs_fsync_local,
302 };
303 
__hmdfs_ioc_set_share_path(struct file * file,struct hmdfs_share_control * sc)304 static 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 
365 unlock:
366 	spin_unlock(&sbi->share_table.item_list_lock);
367 	kfree(full_path);
368 free_dir:
369 	kfree(dir_path);
370 err_out:
371 	fdput(src);
372 	return err;
373 }
374 
hmdfs_ioc_set_share_path(struct file * file,unsigned long arg)375 static 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 
hmdfs_dir_ioctl_local(struct file * file,unsigned int cmd,unsigned long arg)386 static 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 
397 const struct file_operations hmdfs_dir_ops_share = {
398 	.owner = THIS_MODULE,
399 	.iterate = 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