Commit | Line | Data |
---|---|---|
1f327613 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
147b31cf | 2 | /* |
147b31cf EVH |
3 | * This file contians vfs address (mmap) ops for 9P2000. |
4 | * | |
5 | * Copyright (C) 2005 by Eric Van Hensbergen <ericvh@gmail.com> | |
6 | * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov> | |
147b31cf EVH |
7 | */ |
8 | ||
9 | #include <linux/module.h> | |
10 | #include <linux/errno.h> | |
11 | #include <linux/fs.h> | |
12 | #include <linux/file.h> | |
13 | #include <linux/stat.h> | |
14 | #include <linux/string.h> | |
147b31cf | 15 | #include <linux/pagemap.h> |
e8edc6e0 | 16 | #include <linux/sched.h> |
d7bdba1c | 17 | #include <linux/swap.h> |
e2e40f2c | 18 | #include <linux/uio.h> |
eb497943 | 19 | #include <linux/netfs.h> |
bd238fb4 LI |
20 | #include <net/9p/9p.h> |
21 | #include <net/9p/client.h> | |
80105ed2 | 22 | #include <trace/events/netfs.h> |
147b31cf | 23 | |
147b31cf | 24 | #include "v9fs.h" |
147b31cf | 25 | #include "v9fs_vfs.h" |
60e78d2c | 26 | #include "cache.h" |
7263cebe | 27 | #include "fid.h" |
147b31cf | 28 | |
5fb70e72 DH |
29 | /* |
30 | * Writeback calls this when it finds a folio that needs uploading. This isn't | |
31 | * called if writeback only has copy-to-cache to deal with. | |
32 | */ | |
33 | static void v9fs_begin_writeback(struct netfs_io_request *wreq) | |
34 | { | |
35 | struct p9_fid *fid; | |
36 | ||
37 | fid = v9fs_fid_find_inode(wreq->inode, true, INVALID_UID, true); | |
38 | if (!fid) { | |
39 | WARN_ONCE(1, "folio expected an open fid inode->i_ino=%lx\n", | |
40 | wreq->inode->i_ino); | |
41 | return; | |
42 | } | |
43 | ||
44 | wreq->wsize = fid->clnt->msize - P9_IOHDRSZ; | |
45 | if (fid->iounit) | |
46 | wreq->wsize = min(wreq->wsize, fid->iounit); | |
47 | wreq->netfs_priv = fid; | |
48 | wreq->io_streams[0].avail = true; | |
49 | } | |
50 | ||
51 | /* | |
52 | * Issue a subrequest to write to the server. | |
53 | */ | |
54 | static void v9fs_issue_write(struct netfs_io_subrequest *subreq) | |
55 | { | |
56 | struct p9_fid *fid = subreq->rreq->netfs_priv; | |
57 | int err, len; | |
58 | ||
59 | len = p9_client_write(fid, subreq->start, &subreq->io_iter, &err); | |
60 | netfs_write_subrequest_terminated(subreq, len ?: err, false); | |
61 | } | |
62 | ||
2df86547 | 63 | #if 0 // TODO: Remove |
80105ed2 DH |
64 | static void v9fs_upload_to_server(struct netfs_io_subrequest *subreq) |
65 | { | |
80105ed2 | 66 | struct p9_fid *fid = subreq->rreq->netfs_priv; |
252cf7b2 | 67 | int err, len; |
80105ed2 DH |
68 | |
69 | trace_netfs_sreq(subreq, netfs_sreq_trace_submit); | |
252cf7b2 DH |
70 | len = p9_client_write(fid, subreq->start, &subreq->io_iter, &err); |
71 | netfs_write_subrequest_terminated(subreq, len ?: err, false); | |
80105ed2 DH |
72 | } |
73 | ||
74 | static void v9fs_upload_to_server_worker(struct work_struct *work) | |
75 | { | |
76 | struct netfs_io_subrequest *subreq = | |
77 | container_of(work, struct netfs_io_subrequest, work); | |
78 | ||
79 | v9fs_upload_to_server(subreq); | |
80 | } | |
81 | ||
82 | /* | |
83 | * Set up write requests for a writeback slice. We need to add a write request | |
84 | * for each write we want to make. | |
85 | */ | |
86 | static void v9fs_create_write_requests(struct netfs_io_request *wreq, loff_t start, size_t len) | |
87 | { | |
88 | struct netfs_io_subrequest *subreq; | |
89 | ||
90 | subreq = netfs_create_write_request(wreq, NETFS_UPLOAD_TO_SERVER, | |
91 | start, len, v9fs_upload_to_server_worker); | |
92 | if (subreq) | |
93 | netfs_queue_write_request(subreq); | |
94 | } | |
2df86547 | 95 | #endif |
80105ed2 | 96 | |
147b31cf | 97 | /** |
f18a3785 | 98 | * v9fs_issue_read - Issue a read from 9P |
eb497943 | 99 | * @subreq: The read to make |
147b31cf | 100 | */ |
f18a3785 | 101 | static void v9fs_issue_read(struct netfs_io_subrequest *subreq) |
147b31cf | 102 | { |
6a19114b | 103 | struct netfs_io_request *rreq = subreq->rreq; |
eb497943 | 104 | struct p9_fid *fid = rreq->netfs_priv; |
eb497943 | 105 | int total, err; |
e03abc0c | 106 | |
80105ed2 DH |
107 | total = p9_client_read(fid, subreq->start + subreq->transferred, |
108 | &subreq->io_iter, &err); | |
19d1c326 DM |
109 | |
110 | /* if we just extended the file size, any portion not in | |
111 | * cache won't be on server and is zeroes */ | |
112 | __set_bit(NETFS_SREQ_CLEAR_TAIL, &subreq->flags); | |
113 | ||
eb497943 DH |
114 | netfs_subreq_terminated(subreq, err ?: total, false); |
115 | } | |
60e78d2c | 116 | |
eb497943 | 117 | /** |
80105ed2 | 118 | * v9fs_init_request - Initialise a request |
eb497943 DH |
119 | * @rreq: The read request |
120 | * @file: The file being read from | |
121 | */ | |
2de16041 | 122 | static int v9fs_init_request(struct netfs_io_request *rreq, struct file *file) |
eb497943 | 123 | { |
80105ed2 DH |
124 | struct p9_fid *fid; |
125 | bool writing = (rreq->origin == NETFS_READ_FOR_WRITE || | |
80105ed2 | 126 | rreq->origin == NETFS_WRITETHROUGH || |
80105ed2 DH |
127 | rreq->origin == NETFS_UNBUFFERED_WRITE || |
128 | rreq->origin == NETFS_DIO_WRITE); | |
129 | ||
5fb70e72 DH |
130 | if (rreq->origin == NETFS_WRITEBACK) |
131 | return 0; /* We don't get the write handle until we find we | |
132 | * have actually dirty data and not just | |
133 | * copy-to-cache data. | |
134 | */ | |
5fb70e72 | 135 | |
80105ed2 DH |
136 | if (file) { |
137 | fid = file->private_data; | |
6c2c1e00 DH |
138 | if (!fid) |
139 | goto no_fid; | |
80105ed2 DH |
140 | p9_fid_get(fid); |
141 | } else { | |
142 | fid = v9fs_fid_find_inode(rreq->inode, writing, INVALID_UID, true); | |
6c2c1e00 DH |
143 | if (!fid) |
144 | goto no_fid; | |
80105ed2 | 145 | } |
b0017602 | 146 | |
5fb70e72 DH |
147 | rreq->wsize = fid->clnt->msize - P9_IOHDRSZ; |
148 | if (fid->iounit) | |
149 | rreq->wsize = min(rreq->wsize, fid->iounit); | |
150 | ||
b0017602 DM |
151 | /* we might need to read from a fid that was opened write-only |
152 | * for read-modify-write of page cache, use the writeback fid | |
153 | * for that */ | |
80105ed2 | 154 | WARN_ON(rreq->origin == NETFS_READ_FOR_WRITE && !(fid->mode & P9_ORDWR)); |
eb497943 | 155 | rreq->netfs_priv = fid; |
2de16041 | 156 | return 0; |
6c2c1e00 DH |
157 | |
158 | no_fid: | |
159 | WARN_ONCE(1, "folio expected an open fid inode->i_ino=%lx\n", | |
160 | rreq->inode->i_ino); | |
161 | return -EINVAL; | |
eb497943 | 162 | } |
147b31cf | 163 | |
eb497943 | 164 | /** |
40a81101 DH |
165 | * v9fs_free_request - Cleanup request initialized by v9fs_init_rreq |
166 | * @rreq: The I/O request to clean up | |
eb497943 | 167 | */ |
40a81101 | 168 | static void v9fs_free_request(struct netfs_io_request *rreq) |
eb497943 | 169 | { |
40a81101 | 170 | struct p9_fid *fid = rreq->netfs_priv; |
147b31cf | 171 | |
b48dbb99 | 172 | p9_fid_put(fid); |
eb497943 | 173 | } |
60e78d2c | 174 | |
bc899ee1 | 175 | const struct netfs_request_ops v9fs_req_ops = { |
6a19114b | 176 | .init_request = v9fs_init_request, |
40a81101 | 177 | .free_request = v9fs_free_request, |
f18a3785 | 178 | .issue_read = v9fs_issue_read, |
5fb70e72 DH |
179 | .begin_writeback = v9fs_begin_writeback, |
180 | .issue_write = v9fs_issue_write, | |
eb497943 DH |
181 | }; |
182 | ||
f5e54d6e | 183 | const struct address_space_operations v9fs_addr_operations = { |
80105ed2 DH |
184 | .read_folio = netfs_read_folio, |
185 | .readahead = netfs_readahead, | |
186 | .dirty_folio = netfs_dirty_folio, | |
187 | .release_folio = netfs_release_folio, | |
188 | .invalidate_folio = netfs_invalidate_folio, | |
80105ed2 DH |
189 | .direct_IO = noop_direct_IO, |
190 | .writepages = netfs_writepages, | |
147b31cf | 191 | }; |