Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/fs/9p/vfs_file.c
15109 views
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 <[email protected]>
7
* Copyright (C) 2002 by Ron Minnich <[email protected]>
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 vm_operations_struct v9fs_file_vm_ops;
48
49
/**
50
* v9fs_file_open - open a file (or directory)
51
* @inode: inode to be opened
52
* @file: file being opened
53
*
54
*/
55
56
int v9fs_file_open(struct inode *inode, struct file *file)
57
{
58
int err;
59
struct v9fs_inode *v9inode;
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
v9inode = V9FS_I(inode);
66
v9ses = v9fs_inode2v9ses(inode);
67
if (v9fs_proto_dotl(v9ses))
68
omode = file->f_flags;
69
else
70
omode = v9fs_uflags2omode(file->f_flags,
71
v9fs_proto_dotu(v9ses));
72
fid = file->private_data;
73
if (!fid) {
74
fid = v9fs_fid_clone(file->f_path.dentry);
75
if (IS_ERR(fid))
76
return PTR_ERR(fid);
77
78
err = p9_client_open(fid, omode);
79
if (err < 0) {
80
p9_client_clunk(fid);
81
return err;
82
}
83
if (file->f_flags & O_TRUNC) {
84
i_size_write(inode, 0);
85
inode->i_blocks = 0;
86
}
87
if ((file->f_flags & O_APPEND) &&
88
(!v9fs_proto_dotu(v9ses) && !v9fs_proto_dotl(v9ses)))
89
generic_file_llseek(file, 0, SEEK_END);
90
}
91
92
file->private_data = fid;
93
mutex_lock(&v9inode->v_mutex);
94
if (v9ses->cache && !v9inode->writeback_fid &&
95
((file->f_flags & O_ACCMODE) != O_RDONLY)) {
96
/*
97
* clone a fid and add it to writeback_fid
98
* we do it during open time instead of
99
* page dirty time via write_begin/page_mkwrite
100
* because we want write after unlink usecase
101
* to work.
102
*/
103
fid = v9fs_writeback_fid(file->f_path.dentry);
104
if (IS_ERR(fid)) {
105
err = PTR_ERR(fid);
106
mutex_unlock(&v9inode->v_mutex);
107
goto out_error;
108
}
109
v9inode->writeback_fid = (void *) fid;
110
}
111
mutex_unlock(&v9inode->v_mutex);
112
#ifdef CONFIG_9P_FSCACHE
113
if (v9ses->cache)
114
v9fs_cache_inode_set_cookie(inode, file);
115
#endif
116
return 0;
117
out_error:
118
p9_client_clunk(file->private_data);
119
file->private_data = NULL;
120
return err;
121
}
122
123
/**
124
* v9fs_file_lock - lock a file (or directory)
125
* @filp: file to be locked
126
* @cmd: lock command
127
* @fl: file lock structure
128
*
129
* Bugs: this looks like a local only lock, we should extend into 9P
130
* by using open exclusive
131
*/
132
133
static int v9fs_file_lock(struct file *filp, int cmd, struct file_lock *fl)
134
{
135
int res = 0;
136
struct inode *inode = filp->f_path.dentry->d_inode;
137
138
P9_DPRINTK(P9_DEBUG_VFS, "filp: %p lock: %p\n", filp, fl);
139
140
/* No mandatory locks */
141
if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK)
142
return -ENOLCK;
143
144
if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) {
145
filemap_write_and_wait(inode->i_mapping);
146
invalidate_mapping_pages(&inode->i_data, 0, -1);
147
}
148
149
return res;
150
}
151
152
static int v9fs_file_do_lock(struct file *filp, int cmd, struct file_lock *fl)
153
{
154
struct p9_flock flock;
155
struct p9_fid *fid;
156
uint8_t status;
157
int res = 0;
158
unsigned char fl_type;
159
160
fid = filp->private_data;
161
BUG_ON(fid == NULL);
162
163
if ((fl->fl_flags & FL_POSIX) != FL_POSIX)
164
BUG();
165
166
res = posix_lock_file_wait(filp, fl);
167
if (res < 0)
168
goto out;
169
170
/* convert posix lock to p9 tlock args */
171
memset(&flock, 0, sizeof(flock));
172
flock.type = fl->fl_type;
173
flock.start = fl->fl_start;
174
if (fl->fl_end == OFFSET_MAX)
175
flock.length = 0;
176
else
177
flock.length = fl->fl_end - fl->fl_start + 1;
178
flock.proc_id = fl->fl_pid;
179
flock.client_id = utsname()->nodename;
180
if (IS_SETLKW(cmd))
181
flock.flags = P9_LOCK_FLAGS_BLOCK;
182
183
/*
184
* if its a blocked request and we get P9_LOCK_BLOCKED as the status
185
* for lock request, keep on trying
186
*/
187
for (;;) {
188
res = p9_client_lock_dotl(fid, &flock, &status);
189
if (res < 0)
190
break;
191
192
if (status != P9_LOCK_BLOCKED)
193
break;
194
if (status == P9_LOCK_BLOCKED && !IS_SETLKW(cmd))
195
break;
196
schedule_timeout_interruptible(P9_LOCK_TIMEOUT);
197
}
198
199
/* map 9p status to VFS status */
200
switch (status) {
201
case P9_LOCK_SUCCESS:
202
res = 0;
203
break;
204
case P9_LOCK_BLOCKED:
205
res = -EAGAIN;
206
break;
207
case P9_LOCK_ERROR:
208
case P9_LOCK_GRACE:
209
res = -ENOLCK;
210
break;
211
default:
212
BUG();
213
}
214
215
/*
216
* incase server returned error for lock request, revert
217
* it locally
218
*/
219
if (res < 0 && fl->fl_type != F_UNLCK) {
220
fl_type = fl->fl_type;
221
fl->fl_type = F_UNLCK;
222
res = posix_lock_file_wait(filp, fl);
223
fl->fl_type = fl_type;
224
}
225
out:
226
return res;
227
}
228
229
static int v9fs_file_getlock(struct file *filp, struct file_lock *fl)
230
{
231
struct p9_getlock glock;
232
struct p9_fid *fid;
233
int res = 0;
234
235
fid = filp->private_data;
236
BUG_ON(fid == NULL);
237
238
posix_test_lock(filp, fl);
239
/*
240
* if we have a conflicting lock locally, no need to validate
241
* with server
242
*/
243
if (fl->fl_type != F_UNLCK)
244
return res;
245
246
/* convert posix lock to p9 tgetlock args */
247
memset(&glock, 0, sizeof(glock));
248
glock.type = fl->fl_type;
249
glock.start = fl->fl_start;
250
if (fl->fl_end == OFFSET_MAX)
251
glock.length = 0;
252
else
253
glock.length = fl->fl_end - fl->fl_start + 1;
254
glock.proc_id = fl->fl_pid;
255
glock.client_id = utsname()->nodename;
256
257
res = p9_client_getlock_dotl(fid, &glock);
258
if (res < 0)
259
return res;
260
if (glock.type != F_UNLCK) {
261
fl->fl_type = glock.type;
262
fl->fl_start = glock.start;
263
if (glock.length == 0)
264
fl->fl_end = OFFSET_MAX;
265
else
266
fl->fl_end = glock.start + glock.length - 1;
267
fl->fl_pid = glock.proc_id;
268
} else
269
fl->fl_type = F_UNLCK;
270
271
return res;
272
}
273
274
/**
275
* v9fs_file_lock_dotl - lock a file (or directory)
276
* @filp: file to be locked
277
* @cmd: lock command
278
* @fl: file lock structure
279
*
280
*/
281
282
static int v9fs_file_lock_dotl(struct file *filp, int cmd, struct file_lock *fl)
283
{
284
struct inode *inode = filp->f_path.dentry->d_inode;
285
int ret = -ENOLCK;
286
287
P9_DPRINTK(P9_DEBUG_VFS, "filp: %p cmd:%d lock: %p name: %s\n", filp,
288
cmd, fl, filp->f_path.dentry->d_name.name);
289
290
/* No mandatory locks */
291
if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK)
292
goto out_err;
293
294
if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) {
295
filemap_write_and_wait(inode->i_mapping);
296
invalidate_mapping_pages(&inode->i_data, 0, -1);
297
}
298
299
if (IS_SETLK(cmd) || IS_SETLKW(cmd))
300
ret = v9fs_file_do_lock(filp, cmd, fl);
301
else if (IS_GETLK(cmd))
302
ret = v9fs_file_getlock(filp, fl);
303
else
304
ret = -EINVAL;
305
out_err:
306
return ret;
307
}
308
309
/**
310
* v9fs_file_flock_dotl - lock a file
311
* @filp: file to be locked
312
* @cmd: lock command
313
* @fl: file lock structure
314
*
315
*/
316
317
static int v9fs_file_flock_dotl(struct file *filp, int cmd,
318
struct file_lock *fl)
319
{
320
struct inode *inode = filp->f_path.dentry->d_inode;
321
int ret = -ENOLCK;
322
323
P9_DPRINTK(P9_DEBUG_VFS, "filp: %p cmd:%d lock: %p name: %s\n", filp,
324
cmd, fl, filp->f_path.dentry->d_name.name);
325
326
/* No mandatory locks */
327
if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK)
328
goto out_err;
329
330
if (!(fl->fl_flags & FL_FLOCK))
331
goto out_err;
332
333
if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) {
334
filemap_write_and_wait(inode->i_mapping);
335
invalidate_mapping_pages(&inode->i_data, 0, -1);
336
}
337
/* Convert flock to posix lock */
338
fl->fl_owner = (fl_owner_t)filp;
339
fl->fl_start = 0;
340
fl->fl_end = OFFSET_MAX;
341
fl->fl_flags |= FL_POSIX;
342
fl->fl_flags ^= FL_FLOCK;
343
344
if (IS_SETLK(cmd) | IS_SETLKW(cmd))
345
ret = v9fs_file_do_lock(filp, cmd, fl);
346
else
347
ret = -EINVAL;
348
out_err:
349
return ret;
350
}
351
352
/**
353
* v9fs_fid_readn - read from a fid
354
* @fid: fid to read
355
* @data: data buffer to read data into
356
* @udata: user data buffer to read data into
357
* @count: size of buffer
358
* @offset: offset at which to read data
359
*
360
*/
361
ssize_t
362
v9fs_fid_readn(struct p9_fid *fid, char *data, char __user *udata, u32 count,
363
u64 offset)
364
{
365
int n, total, size;
366
367
P9_DPRINTK(P9_DEBUG_VFS, "fid %d offset %llu count %d\n", fid->fid,
368
(long long unsigned) offset, count);
369
n = 0;
370
total = 0;
371
size = fid->iounit ? fid->iounit : fid->clnt->msize - P9_IOHDRSZ;
372
do {
373
n = p9_client_read(fid, data, udata, offset, count);
374
if (n <= 0)
375
break;
376
377
if (data)
378
data += n;
379
if (udata)
380
udata += n;
381
382
offset += n;
383
count -= n;
384
total += n;
385
} while (count > 0 && n == size);
386
387
if (n < 0)
388
total = n;
389
390
return total;
391
}
392
393
/**
394
* v9fs_file_readn - read from a file
395
* @filp: file pointer to read
396
* @data: data buffer to read data into
397
* @udata: user data buffer to read data into
398
* @count: size of buffer
399
* @offset: offset at which to read data
400
*
401
*/
402
ssize_t
403
v9fs_file_readn(struct file *filp, char *data, char __user *udata, u32 count,
404
u64 offset)
405
{
406
return v9fs_fid_readn(filp->private_data, data, udata, count, offset);
407
}
408
409
/**
410
* v9fs_file_read - read from a file
411
* @filp: file pointer to read
412
* @udata: user data buffer to read data into
413
* @count: size of buffer
414
* @offset: offset at which to read data
415
*
416
*/
417
418
static ssize_t
419
v9fs_file_read(struct file *filp, char __user *udata, size_t count,
420
loff_t * offset)
421
{
422
int ret;
423
struct p9_fid *fid;
424
size_t size;
425
426
P9_DPRINTK(P9_DEBUG_VFS, "count %zu offset %lld\n", count, *offset);
427
fid = filp->private_data;
428
429
size = fid->iounit ? fid->iounit : fid->clnt->msize - P9_IOHDRSZ;
430
if (count > size)
431
ret = v9fs_file_readn(filp, NULL, udata, count, *offset);
432
else
433
ret = p9_client_read(fid, NULL, udata, *offset, count);
434
435
if (ret > 0)
436
*offset += ret;
437
438
return ret;
439
}
440
441
ssize_t
442
v9fs_file_write_internal(struct inode *inode, struct p9_fid *fid,
443
const char __user *data, size_t count,
444
loff_t *offset, int invalidate)
445
{
446
int n;
447
loff_t i_size;
448
size_t total = 0;
449
struct p9_client *clnt;
450
loff_t origin = *offset;
451
unsigned long pg_start, pg_end;
452
453
P9_DPRINTK(P9_DEBUG_VFS, "data %p count %d offset %x\n", data,
454
(int)count, (int)*offset);
455
456
clnt = fid->clnt;
457
do {
458
n = p9_client_write(fid, NULL, data+total, origin+total, count);
459
if (n <= 0)
460
break;
461
count -= n;
462
total += n;
463
} while (count > 0);
464
465
if (invalidate && (total > 0)) {
466
pg_start = origin >> PAGE_CACHE_SHIFT;
467
pg_end = (origin + total - 1) >> PAGE_CACHE_SHIFT;
468
if (inode->i_mapping && inode->i_mapping->nrpages)
469
invalidate_inode_pages2_range(inode->i_mapping,
470
pg_start, pg_end);
471
*offset += total;
472
i_size = i_size_read(inode);
473
if (*offset > i_size) {
474
inode_add_bytes(inode, *offset - i_size);
475
i_size_write(inode, *offset);
476
}
477
}
478
if (n < 0)
479
return n;
480
481
return total;
482
}
483
484
/**
485
* v9fs_file_write - write to a file
486
* @filp: file pointer to write
487
* @data: data buffer to write data from
488
* @count: size of buffer
489
* @offset: offset at which to write data
490
*
491
*/
492
static ssize_t
493
v9fs_file_write(struct file *filp, const char __user * data,
494
size_t count, loff_t *offset)
495
{
496
ssize_t retval = 0;
497
loff_t origin = *offset;
498
499
500
retval = generic_write_checks(filp, &origin, &count, 0);
501
if (retval)
502
goto out;
503
504
retval = -EINVAL;
505
if ((ssize_t) count < 0)
506
goto out;
507
retval = 0;
508
if (!count)
509
goto out;
510
511
retval = v9fs_file_write_internal(filp->f_path.dentry->d_inode,
512
filp->private_data,
513
data, count, &origin, 1);
514
/* update offset on successful write */
515
if (retval > 0)
516
*offset = origin;
517
out:
518
return retval;
519
}
520
521
522
static int v9fs_file_fsync(struct file *filp, int datasync)
523
{
524
struct p9_fid *fid;
525
struct p9_wstat wstat;
526
int retval;
527
528
P9_DPRINTK(P9_DEBUG_VFS, "filp %p datasync %x\n", filp, datasync);
529
530
fid = filp->private_data;
531
v9fs_blank_wstat(&wstat);
532
533
retval = p9_client_wstat(fid, &wstat);
534
return retval;
535
}
536
537
int v9fs_file_fsync_dotl(struct file *filp, int datasync)
538
{
539
struct p9_fid *fid;
540
int retval;
541
542
P9_DPRINTK(P9_DEBUG_VFS, "v9fs_file_fsync_dotl: filp %p datasync %x\n",
543
filp, datasync);
544
545
fid = filp->private_data;
546
547
retval = p9_client_fsync(fid, datasync);
548
return retval;
549
}
550
551
static int
552
v9fs_file_mmap(struct file *file, struct vm_area_struct *vma)
553
{
554
int retval;
555
556
retval = generic_file_mmap(file, vma);
557
if (!retval)
558
vma->vm_ops = &v9fs_file_vm_ops;
559
560
return retval;
561
}
562
563
static int
564
v9fs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
565
{
566
struct v9fs_inode *v9inode;
567
struct page *page = vmf->page;
568
struct file *filp = vma->vm_file;
569
struct inode *inode = filp->f_path.dentry->d_inode;
570
571
572
P9_DPRINTK(P9_DEBUG_VFS, "page %p fid %lx\n",
573
page, (unsigned long)filp->private_data);
574
575
v9inode = V9FS_I(inode);
576
/* make sure the cache has finished storing the page */
577
v9fs_fscache_wait_on_page_write(inode, page);
578
BUG_ON(!v9inode->writeback_fid);
579
lock_page(page);
580
if (page->mapping != inode->i_mapping)
581
goto out_unlock;
582
583
return VM_FAULT_LOCKED;
584
out_unlock:
585
unlock_page(page);
586
return VM_FAULT_NOPAGE;
587
}
588
589
static ssize_t
590
v9fs_direct_read(struct file *filp, char __user *udata, size_t count,
591
loff_t *offsetp)
592
{
593
loff_t size, offset;
594
struct inode *inode;
595
struct address_space *mapping;
596
597
offset = *offsetp;
598
mapping = filp->f_mapping;
599
inode = mapping->host;
600
if (!count)
601
return 0;
602
size = i_size_read(inode);
603
if (offset < size)
604
filemap_write_and_wait_range(mapping, offset,
605
offset + count - 1);
606
607
return v9fs_file_read(filp, udata, count, offsetp);
608
}
609
610
/**
611
* v9fs_cached_file_read - read from a file
612
* @filp: file pointer to read
613
* @udata: user data buffer to read data into
614
* @count: size of buffer
615
* @offset: offset at which to read data
616
*
617
*/
618
static ssize_t
619
v9fs_cached_file_read(struct file *filp, char __user *data, size_t count,
620
loff_t *offset)
621
{
622
if (filp->f_flags & O_DIRECT)
623
return v9fs_direct_read(filp, data, count, offset);
624
return do_sync_read(filp, data, count, offset);
625
}
626
627
static ssize_t
628
v9fs_direct_write(struct file *filp, const char __user * data,
629
size_t count, loff_t *offsetp)
630
{
631
loff_t offset;
632
ssize_t retval;
633
struct inode *inode;
634
struct address_space *mapping;
635
636
offset = *offsetp;
637
mapping = filp->f_mapping;
638
inode = mapping->host;
639
if (!count)
640
return 0;
641
642
mutex_lock(&inode->i_mutex);
643
retval = filemap_write_and_wait_range(mapping, offset,
644
offset + count - 1);
645
if (retval)
646
goto err_out;
647
/*
648
* After a write we want buffered reads to be sure to go to disk to get
649
* the new data. We invalidate clean cached page from the region we're
650
* about to write. We do this *before* the write so that if we fail
651
* here we fall back to buffered write
652
*/
653
if (mapping->nrpages) {
654
pgoff_t pg_start = offset >> PAGE_CACHE_SHIFT;
655
pgoff_t pg_end = (offset + count - 1) >> PAGE_CACHE_SHIFT;
656
657
retval = invalidate_inode_pages2_range(mapping,
658
pg_start, pg_end);
659
/*
660
* If a page can not be invalidated, fall back
661
* to buffered write.
662
*/
663
if (retval) {
664
if (retval == -EBUSY)
665
goto buff_write;
666
goto err_out;
667
}
668
}
669
retval = v9fs_file_write(filp, data, count, offsetp);
670
err_out:
671
mutex_unlock(&inode->i_mutex);
672
return retval;
673
674
buff_write:
675
mutex_unlock(&inode->i_mutex);
676
return do_sync_write(filp, data, count, offsetp);
677
}
678
679
/**
680
* v9fs_cached_file_write - write to a file
681
* @filp: file pointer to write
682
* @data: data buffer to write data from
683
* @count: size of buffer
684
* @offset: offset at which to write data
685
*
686
*/
687
static ssize_t
688
v9fs_cached_file_write(struct file *filp, const char __user * data,
689
size_t count, loff_t *offset)
690
{
691
692
if (filp->f_flags & O_DIRECT)
693
return v9fs_direct_write(filp, data, count, offset);
694
return do_sync_write(filp, data, count, offset);
695
}
696
697
static const struct vm_operations_struct v9fs_file_vm_ops = {
698
.fault = filemap_fault,
699
.page_mkwrite = v9fs_vm_page_mkwrite,
700
};
701
702
703
const struct file_operations v9fs_cached_file_operations = {
704
.llseek = generic_file_llseek,
705
.read = v9fs_cached_file_read,
706
.write = v9fs_cached_file_write,
707
.aio_read = generic_file_aio_read,
708
.aio_write = generic_file_aio_write,
709
.open = v9fs_file_open,
710
.release = v9fs_dir_release,
711
.lock = v9fs_file_lock,
712
.mmap = v9fs_file_mmap,
713
.fsync = v9fs_file_fsync,
714
};
715
716
const struct file_operations v9fs_cached_file_operations_dotl = {
717
.llseek = generic_file_llseek,
718
.read = v9fs_cached_file_read,
719
.write = v9fs_cached_file_write,
720
.aio_read = generic_file_aio_read,
721
.aio_write = generic_file_aio_write,
722
.open = v9fs_file_open,
723
.release = v9fs_dir_release,
724
.lock = v9fs_file_lock_dotl,
725
.flock = v9fs_file_flock_dotl,
726
.mmap = v9fs_file_mmap,
727
.fsync = v9fs_file_fsync_dotl,
728
};
729
730
const struct file_operations v9fs_file_operations = {
731
.llseek = generic_file_llseek,
732
.read = v9fs_file_read,
733
.write = v9fs_file_write,
734
.open = v9fs_file_open,
735
.release = v9fs_dir_release,
736
.lock = v9fs_file_lock,
737
.mmap = generic_file_readonly_mmap,
738
.fsync = v9fs_file_fsync,
739
};
740
741
const struct file_operations v9fs_file_operations_dotl = {
742
.llseek = generic_file_llseek,
743
.read = v9fs_file_read,
744
.write = v9fs_file_write,
745
.open = v9fs_file_open,
746
.release = v9fs_dir_release,
747
.lock = v9fs_file_lock_dotl,
748
.flock = v9fs_file_flock_dotl,
749
.mmap = generic_file_readonly_mmap,
750
.fsync = v9fs_file_fsync_dotl,
751
};
752
753