xref: /openbmc/linux/fs/9p/vfs_file.c (revision 1d769cd1)
1 /*
2  *  linux/fs/9p/vfs_file.c
3  *
4  * This file contians vfs file ops for 9P2000.
5  *
6  *  Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
7  *  Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
8  *
9  *  This program is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License version 2
11  *  as published by the Free Software Foundation.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to:
20  *  Free Software Foundation
21  *  51 Franklin Street, Fifth Floor
22  *  Boston, MA  02111-1301  USA
23  *
24  */
25 
26 #include <linux/module.h>
27 #include <linux/errno.h>
28 #include <linux/fs.h>
29 #include <linux/sched.h>
30 #include <linux/file.h>
31 #include <linux/stat.h>
32 #include <linux/string.h>
33 #include <linux/inet.h>
34 #include <linux/list.h>
35 #include <linux/pagemap.h>
36 #include <linux/utsname.h>
37 #include <asm/uaccess.h>
38 #include <linux/idr.h>
39 #include <net/9p/9p.h>
40 #include <net/9p/client.h>
41 
42 #include "v9fs.h"
43 #include "v9fs_vfs.h"
44 #include "fid.h"
45 #include "cache.h"
46 
47 static const struct file_operations v9fs_cached_file_operations;
48 static const struct file_operations v9fs_cached_file_operations_dotl;
49 
50 /**
51  * v9fs_file_open - open a file (or directory)
52  * @inode: inode to be opened
53  * @file: file being opened
54  *
55  */
56 
57 int v9fs_file_open(struct inode *inode, struct file *file)
58 {
59 	int err;
60 	struct v9fs_session_info *v9ses;
61 	struct p9_fid *fid;
62 	int omode;
63 
64 	P9_DPRINTK(P9_DEBUG_VFS, "inode: %p file: %p\n", inode, file);
65 	v9ses = v9fs_inode2v9ses(inode);
66 	if (v9fs_proto_dotl(v9ses))
67 		omode = file->f_flags;
68 	else
69 		omode = v9fs_uflags2omode(file->f_flags,
70 					v9fs_proto_dotu(v9ses));
71 	fid = file->private_data;
72 	if (!fid) {
73 		fid = v9fs_fid_clone(file->f_path.dentry);
74 		if (IS_ERR(fid))
75 			return PTR_ERR(fid);
76 
77 		err = p9_client_open(fid, omode);
78 		if (err < 0) {
79 			p9_client_clunk(fid);
80 			return err;
81 		}
82 		if (file->f_flags & O_TRUNC) {
83 			i_size_write(inode, 0);
84 			inode->i_blocks = 0;
85 		}
86 		if ((file->f_flags & O_APPEND) &&
87 			(!v9fs_proto_dotu(v9ses) && !v9fs_proto_dotl(v9ses)))
88 			generic_file_llseek(file, 0, SEEK_END);
89 	}
90 
91 	file->private_data = fid;
92 	if ((fid->qid.version) && (v9ses->cache)) {
93 		P9_DPRINTK(P9_DEBUG_VFS, "cached");
94 		/* enable cached file options */
95 		if(file->f_op == &v9fs_file_operations)
96 			file->f_op = &v9fs_cached_file_operations;
97 		else if (file->f_op == &v9fs_file_operations_dotl)
98 			file->f_op = &v9fs_cached_file_operations_dotl;
99 
100 #ifdef CONFIG_9P_FSCACHE
101 		v9fs_cache_inode_set_cookie(inode, file);
102 #endif
103 	}
104 
105 	return 0;
106 }
107 
108 /**
109  * v9fs_file_lock - lock a file (or directory)
110  * @filp: file to be locked
111  * @cmd: lock command
112  * @fl: file lock structure
113  *
114  * Bugs: this looks like a local only lock, we should extend into 9P
115  *       by using open exclusive
116  */
117 
118 static int v9fs_file_lock(struct file *filp, int cmd, struct file_lock *fl)
119 {
120 	int res = 0;
121 	struct inode *inode = filp->f_path.dentry->d_inode;
122 
123 	P9_DPRINTK(P9_DEBUG_VFS, "filp: %p lock: %p\n", filp, fl);
124 
125 	/* No mandatory locks */
126 	if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK)
127 		return -ENOLCK;
128 
129 	if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) {
130 		filemap_write_and_wait(inode->i_mapping);
131 		invalidate_mapping_pages(&inode->i_data, 0, -1);
132 	}
133 
134 	return res;
135 }
136 
137 static int v9fs_file_do_lock(struct file *filp, int cmd, struct file_lock *fl)
138 {
139 	struct p9_flock flock;
140 	struct p9_fid *fid;
141 	uint8_t status;
142 	int res = 0;
143 	unsigned char fl_type;
144 
145 	fid = filp->private_data;
146 	BUG_ON(fid == NULL);
147 
148 	if ((fl->fl_flags & FL_POSIX) != FL_POSIX)
149 		BUG();
150 
151 	res = posix_lock_file_wait(filp, fl);
152 	if (res < 0)
153 		goto out;
154 
155 	/* convert posix lock to p9 tlock args */
156 	memset(&flock, 0, sizeof(flock));
157 	flock.type = fl->fl_type;
158 	flock.start = fl->fl_start;
159 	if (fl->fl_end == OFFSET_MAX)
160 		flock.length = 0;
161 	else
162 		flock.length = fl->fl_end - fl->fl_start + 1;
163 	flock.proc_id = fl->fl_pid;
164 	flock.client_id = utsname()->nodename;
165 	if (IS_SETLKW(cmd))
166 		flock.flags = P9_LOCK_FLAGS_BLOCK;
167 
168 	/*
169 	 * if its a blocked request and we get P9_LOCK_BLOCKED as the status
170 	 * for lock request, keep on trying
171 	 */
172 	for (;;) {
173 		res = p9_client_lock_dotl(fid, &flock, &status);
174 		if (res < 0)
175 			break;
176 
177 		if (status != P9_LOCK_BLOCKED)
178 			break;
179 		if (status == P9_LOCK_BLOCKED && !IS_SETLKW(cmd))
180 			break;
181 		schedule_timeout_interruptible(P9_LOCK_TIMEOUT);
182 	}
183 
184 	/* map 9p status to VFS status */
185 	switch (status) {
186 	case P9_LOCK_SUCCESS:
187 		res = 0;
188 		break;
189 	case P9_LOCK_BLOCKED:
190 		res = -EAGAIN;
191 		break;
192 	case P9_LOCK_ERROR:
193 	case P9_LOCK_GRACE:
194 		res = -ENOLCK;
195 		break;
196 	default:
197 		BUG();
198 	}
199 
200 	/*
201 	 * incase server returned error for lock request, revert
202 	 * it locally
203 	 */
204 	if (res < 0 && fl->fl_type != F_UNLCK) {
205 		fl_type = fl->fl_type;
206 		fl->fl_type = F_UNLCK;
207 		res = posix_lock_file_wait(filp, fl);
208 		fl->fl_type = fl_type;
209 	}
210 out:
211 	return res;
212 }
213 
214 static int v9fs_file_getlock(struct file *filp, struct file_lock *fl)
215 {
216 	struct p9_getlock glock;
217 	struct p9_fid *fid;
218 	int res = 0;
219 
220 	fid = filp->private_data;
221 	BUG_ON(fid == NULL);
222 
223 	posix_test_lock(filp, fl);
224 	/*
225 	 * if we have a conflicting lock locally, no need to validate
226 	 * with server
227 	 */
228 	if (fl->fl_type != F_UNLCK)
229 		return res;
230 
231 	/* convert posix lock to p9 tgetlock args */
232 	memset(&glock, 0, sizeof(glock));
233 	glock.type = fl->fl_type;
234 	glock.start = fl->fl_start;
235 	if (fl->fl_end == OFFSET_MAX)
236 		glock.length = 0;
237 	else
238 		glock.length = fl->fl_end - fl->fl_start + 1;
239 	glock.proc_id = fl->fl_pid;
240 	glock.client_id = utsname()->nodename;
241 
242 	res = p9_client_getlock_dotl(fid, &glock);
243 	if (res < 0)
244 		return res;
245 	if (glock.type != F_UNLCK) {
246 		fl->fl_type = glock.type;
247 		fl->fl_start = glock.start;
248 		if (glock.length == 0)
249 			fl->fl_end = OFFSET_MAX;
250 		else
251 			fl->fl_end = glock.start + glock.length - 1;
252 		fl->fl_pid = glock.proc_id;
253 	} else
254 		fl->fl_type = F_UNLCK;
255 
256 	return res;
257 }
258 
259 /**
260  * v9fs_file_lock_dotl - lock a file (or directory)
261  * @filp: file to be locked
262  * @cmd: lock command
263  * @fl: file lock structure
264  *
265  */
266 
267 static int v9fs_file_lock_dotl(struct file *filp, int cmd, struct file_lock *fl)
268 {
269 	struct inode *inode = filp->f_path.dentry->d_inode;
270 	int ret = -ENOLCK;
271 
272 	P9_DPRINTK(P9_DEBUG_VFS, "filp: %p cmd:%d lock: %p name: %s\n", filp,
273 				cmd, fl, filp->f_path.dentry->d_name.name);
274 
275 	/* No mandatory locks */
276 	if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK)
277 		goto out_err;
278 
279 	if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) {
280 		filemap_write_and_wait(inode->i_mapping);
281 		invalidate_mapping_pages(&inode->i_data, 0, -1);
282 	}
283 
284 	if (IS_SETLK(cmd) || IS_SETLKW(cmd))
285 		ret = v9fs_file_do_lock(filp, cmd, fl);
286 	else if (IS_GETLK(cmd))
287 		ret = v9fs_file_getlock(filp, fl);
288 	else
289 		ret = -EINVAL;
290 out_err:
291 	return ret;
292 }
293 
294 /**
295  * v9fs_file_flock_dotl - lock a file
296  * @filp: file to be locked
297  * @cmd: lock command
298  * @fl: file lock structure
299  *
300  */
301 
302 static int v9fs_file_flock_dotl(struct file *filp, int cmd,
303 	struct file_lock *fl)
304 {
305 	struct inode *inode = filp->f_path.dentry->d_inode;
306 	int ret = -ENOLCK;
307 
308 	P9_DPRINTK(P9_DEBUG_VFS, "filp: %p cmd:%d lock: %p name: %s\n", filp,
309 				cmd, fl, filp->f_path.dentry->d_name.name);
310 
311 	/* No mandatory locks */
312 	if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK)
313 		goto out_err;
314 
315 	if (!(fl->fl_flags & FL_FLOCK))
316 		goto out_err;
317 
318 	if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) {
319 		filemap_write_and_wait(inode->i_mapping);
320 		invalidate_mapping_pages(&inode->i_data, 0, -1);
321 	}
322 	/* Convert flock to posix lock */
323 	fl->fl_owner = (fl_owner_t)filp;
324 	fl->fl_start = 0;
325 	fl->fl_end = OFFSET_MAX;
326 	fl->fl_flags |= FL_POSIX;
327 	fl->fl_flags ^= FL_FLOCK;
328 
329 	if (IS_SETLK(cmd) | IS_SETLKW(cmd))
330 		ret = v9fs_file_do_lock(filp, cmd, fl);
331 	else
332 		ret = -EINVAL;
333 out_err:
334 	return ret;
335 }
336 
337 /**
338  * v9fs_file_readn - read from a file
339  * @filp: file pointer to read
340  * @data: data buffer to read data into
341  * @udata: user data buffer to read data into
342  * @count: size of buffer
343  * @offset: offset at which to read data
344  *
345  */
346 
347 ssize_t
348 v9fs_file_readn(struct file *filp, char *data, char __user *udata, u32 count,
349 	       u64 offset)
350 {
351 	int n, total, size;
352 	struct p9_fid *fid = filp->private_data;
353 
354 	P9_DPRINTK(P9_DEBUG_VFS, "fid %d offset %llu count %d\n", fid->fid,
355 					(long long unsigned) offset, count);
356 
357 	n = 0;
358 	total = 0;
359 	size = fid->iounit ? fid->iounit : fid->clnt->msize - P9_IOHDRSZ;
360 	do {
361 		n = p9_client_read(fid, data, udata, offset, count);
362 		if (n <= 0)
363 			break;
364 
365 		if (data)
366 			data += n;
367 		if (udata)
368 			udata += n;
369 
370 		offset += n;
371 		count -= n;
372 		total += n;
373 	} while (count > 0 && n == size);
374 
375 	if (n < 0)
376 		total = n;
377 
378 	return total;
379 }
380 
381 /**
382  * v9fs_file_read - read from a file
383  * @filp: file pointer to read
384  * @udata: user data buffer to read data into
385  * @count: size of buffer
386  * @offset: offset at which to read data
387  *
388  */
389 
390 static ssize_t
391 v9fs_file_read(struct file *filp, char __user *udata, size_t count,
392 	       loff_t * offset)
393 {
394 	int ret;
395 	struct p9_fid *fid;
396 	size_t size;
397 
398 	P9_DPRINTK(P9_DEBUG_VFS, "count %zu offset %lld\n", count, *offset);
399 	fid = filp->private_data;
400 
401 	size = fid->iounit ? fid->iounit : fid->clnt->msize - P9_IOHDRSZ;
402 	if (count > size)
403 		ret = v9fs_file_readn(filp, NULL, udata, count, *offset);
404 	else
405 		ret = p9_client_read(fid, NULL, udata, *offset, count);
406 
407 	if (ret > 0)
408 		*offset += ret;
409 
410 	return ret;
411 }
412 
413 /**
414  * v9fs_file_write - write to a file
415  * @filp: file pointer to write
416  * @data: data buffer to write data from
417  * @count: size of buffer
418  * @offset: offset at which to write data
419  *
420  */
421 
422 static ssize_t
423 v9fs_file_write(struct file *filp, const char __user * data,
424 		size_t count, loff_t * offset)
425 {
426 	ssize_t retval;
427 	size_t total = 0;
428 	int n;
429 	struct p9_fid *fid;
430 	struct p9_client *clnt;
431 	struct inode *inode = filp->f_path.dentry->d_inode;
432 	loff_t origin = *offset;
433 	unsigned long pg_start, pg_end;
434 
435 	P9_DPRINTK(P9_DEBUG_VFS, "data %p count %d offset %x\n", data,
436 		(int)count, (int)*offset);
437 
438 	fid = filp->private_data;
439 	clnt = fid->clnt;
440 
441 	retval = generic_write_checks(filp, &origin, &count, 0);
442 	if (retval)
443 		goto out;
444 
445 	retval = -EINVAL;
446 	if ((ssize_t) count < 0)
447 		goto out;
448 	retval = 0;
449 	if (!count)
450 		goto out;
451 
452 	do {
453 		n = p9_client_write(fid, NULL, data+total, origin+total, count);
454 		if (n <= 0)
455 			break;
456 		count -= n;
457 		total += n;
458 	} while (count > 0);
459 
460 	if (total > 0) {
461 		pg_start = origin >> PAGE_CACHE_SHIFT;
462 		pg_end = (origin + total - 1) >> PAGE_CACHE_SHIFT;
463 		if (inode->i_mapping && inode->i_mapping->nrpages)
464 			invalidate_inode_pages2_range(inode->i_mapping,
465 						      pg_start, pg_end);
466 		*offset += total;
467 		i_size_write(inode, i_size_read(inode) + total);
468 		inode->i_blocks = (i_size_read(inode) + 512 - 1) >> 9;
469 	}
470 
471 	if (n < 0)
472 		retval = n;
473 	else
474 		retval = total;
475 out:
476 	return retval;
477 }
478 
479 static int v9fs_file_fsync(struct file *filp, int datasync)
480 {
481 	struct p9_fid *fid;
482 	struct p9_wstat wstat;
483 	int retval;
484 
485 	P9_DPRINTK(P9_DEBUG_VFS, "filp %p datasync %x\n", filp, datasync);
486 
487 	fid = filp->private_data;
488 	v9fs_blank_wstat(&wstat);
489 
490 	retval = p9_client_wstat(fid, &wstat);
491 	return retval;
492 }
493 
494 static int v9fs_file_fsync_dotl(struct file *filp, int datasync)
495 {
496 	struct p9_fid *fid;
497 	int retval;
498 
499 	P9_DPRINTK(P9_DEBUG_VFS, "v9fs_file_fsync_dotl: filp %p datasync %x\n",
500 			filp, datasync);
501 
502 	fid = filp->private_data;
503 
504 	retval = p9_client_fsync(fid);
505 	return retval;
506 }
507 
508 static const struct file_operations v9fs_cached_file_operations = {
509 	.llseek = generic_file_llseek,
510 	.read = do_sync_read,
511 	.aio_read = generic_file_aio_read,
512 	.write = v9fs_file_write,
513 	.open = v9fs_file_open,
514 	.release = v9fs_dir_release,
515 	.lock = v9fs_file_lock,
516 	.mmap = generic_file_readonly_mmap,
517 	.fsync = v9fs_file_fsync,
518 };
519 
520 static const struct file_operations v9fs_cached_file_operations_dotl = {
521 	.llseek = generic_file_llseek,
522 	.read = do_sync_read,
523 	.aio_read = generic_file_aio_read,
524 	.write = v9fs_file_write,
525 	.open = v9fs_file_open,
526 	.release = v9fs_dir_release,
527 	.lock = v9fs_file_lock_dotl,
528 	.flock = v9fs_file_flock_dotl,
529 	.mmap = generic_file_readonly_mmap,
530 	.fsync = v9fs_file_fsync_dotl,
531 };
532 
533 const struct file_operations v9fs_file_operations = {
534 	.llseek = generic_file_llseek,
535 	.read = v9fs_file_read,
536 	.write = v9fs_file_write,
537 	.open = v9fs_file_open,
538 	.release = v9fs_dir_release,
539 	.lock = v9fs_file_lock,
540 	.mmap = generic_file_readonly_mmap,
541 	.fsync = v9fs_file_fsync,
542 };
543 
544 const struct file_operations v9fs_file_operations_dotl = {
545 	.llseek = generic_file_llseek,
546 	.read = v9fs_file_read,
547 	.write = v9fs_file_write,
548 	.open = v9fs_file_open,
549 	.release = v9fs_dir_release,
550 	.lock = v9fs_file_lock_dotl,
551 	.flock = v9fs_file_flock_dotl,
552 	.mmap = generic_file_readonly_mmap,
553 	.fsync = v9fs_file_fsync_dotl,
554 };
555