Commit | Line | Data |
---|---|---|
2874c5fd | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
31143d5d DH |
2 | /* handling of writes to regular files and writing back to the server |
3 | * | |
4 | * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. | |
5 | * Written by David Howells (dhowells@redhat.com) | |
31143d5d | 6 | */ |
4343d008 | 7 | |
4af3c9cc | 8 | #include <linux/backing-dev.h> |
31143d5d DH |
9 | #include <linux/slab.h> |
10 | #include <linux/fs.h> | |
11 | #include <linux/pagemap.h> | |
12 | #include <linux/writeback.h> | |
13 | #include <linux/pagevec.h> | |
3003bbd0 | 14 | #include <linux/netfs.h> |
3560358a | 15 | #include <trace/events/netfs.h> |
31143d5d DH |
16 | #include "internal.h" |
17 | ||
a58823ac DH |
18 | /* |
19 | * completion of write to server | |
20 | */ | |
e87b03f5 | 21 | static void afs_pages_written_back(struct afs_vnode *vnode, loff_t start, unsigned int len) |
a58823ac | 22 | { |
e87b03f5 DH |
23 | _enter("{%llx:%llu},{%x @%llx}", |
24 | vnode->fid.vid, vnode->fid.vnode, len, start); | |
a58823ac | 25 | |
a58823ac DH |
26 | afs_prune_wb_keys(vnode); |
27 | _leave(""); | |
28 | } | |
29 | ||
d2ddc776 | 30 | /* |
e49c7b2f | 31 | * Find a key to use for the writeback. We cached the keys used to author the |
1ecb146f DH |
32 | * writes on the vnode. wreq->netfs_priv2 will contain the last writeback key |
33 | * record used or NULL and we need to start from there if it's set. | |
34 | * wreq->netfs_priv will be set to the key itself or NULL. | |
d2ddc776 | 35 | */ |
1ecb146f | 36 | static void afs_get_writeback_key(struct netfs_io_request *wreq) |
d2ddc776 | 37 | { |
1ecb146f DH |
38 | struct afs_wb_key *wbk, *old = wreq->netfs_priv2; |
39 | struct afs_vnode *vnode = AFS_FS_I(wreq->inode); | |
40 | ||
41 | key_put(wreq->netfs_priv); | |
42 | wreq->netfs_priv = NULL; | |
43 | wreq->netfs_priv2 = NULL; | |
d2ddc776 | 44 | |
4343d008 | 45 | spin_lock(&vnode->wb_lock); |
1ecb146f DH |
46 | if (old) |
47 | wbk = list_next_entry(old, vnode_link); | |
e49c7b2f | 48 | else |
1ecb146f | 49 | wbk = list_first_entry(&vnode->wb_keys, struct afs_wb_key, vnode_link); |
4343d008 | 50 | |
1ecb146f | 51 | list_for_each_entry_from(wbk, &vnode->wb_keys, vnode_link) { |
4343d008 | 52 | _debug("wbk %u", key_serial(wbk->key)); |
1ecb146f | 53 | if (key_validate(wbk->key) == 0) { |
e49c7b2f | 54 | refcount_inc(&wbk->usage); |
1ecb146f DH |
55 | wreq->netfs_priv = key_get(wbk->key); |
56 | wreq->netfs_priv2 = wbk; | |
e49c7b2f DH |
57 | _debug("USE WB KEY %u", key_serial(wbk->key)); |
58 | break; | |
59 | } | |
4343d008 DH |
60 | } |
61 | ||
62 | spin_unlock(&vnode->wb_lock); | |
1ecb146f DH |
63 | |
64 | afs_put_wb_key(old); | |
e49c7b2f | 65 | } |
4343d008 | 66 | |
e49c7b2f DH |
67 | static void afs_store_data_success(struct afs_operation *op) |
68 | { | |
69 | struct afs_vnode *vnode = op->file[0].vnode; | |
4343d008 | 70 | |
da8d0755 | 71 | op->ctime = op->file[0].scb.status.mtime_client; |
e49c7b2f | 72 | afs_vnode_commit_status(op, &op->file[0]); |
2de5599f | 73 | if (!afs_op_error(op)) { |
d73065e6 | 74 | afs_pages_written_back(vnode, op->store.pos, op->store.size); |
e49c7b2f | 75 | afs_stat_v(vnode, n_stores); |
bd80d8a8 | 76 | atomic_long_add(op->store.size, &afs_v2net(vnode)->n_store_bytes); |
e49c7b2f DH |
77 | } |
78 | } | |
4343d008 | 79 | |
e49c7b2f DH |
80 | static const struct afs_operation_ops afs_store_data_operation = { |
81 | .issue_afs_rpc = afs_fs_store_data, | |
82 | .issue_yfs_rpc = yfs_fs_store_data, | |
83 | .success = afs_store_data_success, | |
84 | }; | |
a58823ac | 85 | |
e49c7b2f | 86 | /* |
1ecb146f DH |
87 | * Prepare a subrequest to write to the server. This sets the max_len |
88 | * parameter. | |
89 | */ | |
90 | void afs_prepare_write(struct netfs_io_subrequest *subreq) | |
91 | { | |
52d55922 DH |
92 | struct netfs_io_stream *stream = &subreq->rreq->io_streams[subreq->stream_nr]; |
93 | ||
1ecb146f DH |
94 | //if (test_bit(NETFS_SREQ_RETRYING, &subreq->flags)) |
95 | // subreq->max_len = 512 * 1024; | |
96 | //else | |
52d55922 | 97 | stream->sreq_max_len = 256 * 1024 * 1024; |
1ecb146f DH |
98 | } |
99 | ||
100 | /* | |
101 | * Issue a subrequest to write to the server. | |
e49c7b2f | 102 | */ |
1ecb146f | 103 | static void afs_issue_write_worker(struct work_struct *work) |
e49c7b2f | 104 | { |
1ecb146f DH |
105 | struct netfs_io_subrequest *subreq = container_of(work, struct netfs_io_subrequest, work); |
106 | struct netfs_io_request *wreq = subreq->rreq; | |
e49c7b2f | 107 | struct afs_operation *op; |
1ecb146f DH |
108 | struct afs_vnode *vnode = AFS_FS_I(wreq->inode); |
109 | unsigned long long pos = subreq->start + subreq->transferred; | |
110 | size_t len = subreq->len - subreq->transferred; | |
bd80d8a8 | 111 | int ret = -ENOKEY; |
e49c7b2f | 112 | |
1ecb146f DH |
113 | _enter("R=%x[%x],%s{%llx:%llu.%u},%llx,%zx", |
114 | wreq->debug_id, subreq->debug_index, | |
e49c7b2f DH |
115 | vnode->volume->name, |
116 | vnode->fid.vid, | |
117 | vnode->fid.vnode, | |
118 | vnode->fid.unique, | |
1ecb146f | 119 | pos, len); |
d2ddc776 | 120 | |
1ecb146f DH |
121 | #if 0 // Error injection |
122 | if (subreq->debug_index == 3) | |
20d72b00 | 123 | return netfs_write_subrequest_terminated(subreq, -ENOANO); |
d2ddc776 | 124 | |
4acb665c | 125 | if (!subreq->retry_count) { |
1ecb146f | 126 | set_bit(NETFS_SREQ_NEED_RETRY, &subreq->flags); |
20d72b00 | 127 | return netfs_write_subrequest_terminated(subreq, -EAGAIN); |
e49c7b2f | 128 | } |
1ecb146f DH |
129 | #endif |
130 | ||
131 | op = afs_alloc_operation(wreq->netfs_priv, vnode->volume); | |
132 | if (IS_ERR(op)) | |
20d72b00 | 133 | return netfs_write_subrequest_terminated(subreq, -EAGAIN); |
e49c7b2f DH |
134 | |
135 | afs_op_set_vnode(op, 0, vnode); | |
1ecb146f | 136 | op->file[0].dv_delta = 1; |
22650f14 | 137 | op->file[0].modification = true; |
1ecb146f DH |
138 | op->store.pos = pos; |
139 | op->store.size = len; | |
140 | op->flags |= AFS_OPERATION_UNINTR; | |
141 | op->ops = &afs_store_data_operation; | |
e49c7b2f | 142 | |
e49c7b2f | 143 | afs_begin_vnode_operation(op); |
03275585 | 144 | |
1ecb146f DH |
145 | op->store.write_iter = &subreq->io_iter; |
146 | op->store.i_size = umax(pos + len, vnode->netfs.remote_i_size); | |
147 | op->mtime = inode_get_mtime(&vnode->netfs.inode); | |
03275585 | 148 | |
e49c7b2f | 149 | afs_wait_for_operation(op); |
1ecb146f DH |
150 | ret = afs_put_operation(op); |
151 | switch (ret) { | |
4acb665c DH |
152 | case 0: |
153 | __set_bit(NETFS_SREQ_MADE_PROGRESS, &subreq->flags); | |
154 | break; | |
4343d008 DH |
155 | case -EACCES: |
156 | case -EPERM: | |
157 | case -ENOKEY: | |
158 | case -EKEYEXPIRED: | |
159 | case -EKEYREJECTED: | |
160 | case -EKEYREVOKED: | |
1ecb146f DH |
161 | /* If there are more keys we can try, use the retry algorithm |
162 | * to rotate the keys. | |
163 | */ | |
164 | if (wreq->netfs_priv2) | |
165 | set_bit(NETFS_SREQ_NEED_RETRY, &subreq->flags); | |
e49c7b2f | 166 | break; |
4343d008 DH |
167 | } |
168 | ||
20d72b00 | 169 | netfs_write_subrequest_terminated(subreq, ret < 0 ? ret : subreq->len); |
1ecb146f DH |
170 | } |
171 | ||
172 | void afs_issue_write(struct netfs_io_subrequest *subreq) | |
173 | { | |
174 | subreq->work.func = afs_issue_write_worker; | |
175 | if (!queue_work(system_unbound_wq, &subreq->work)) | |
176 | WARN_ON_ONCE(1); | |
d2ddc776 DH |
177 | } |
178 | ||
ed22e1db DH |
179 | /* |
180 | * Writeback calls this when it finds a folio that needs uploading. This isn't | |
181 | * called if writeback only has copy-to-cache to deal with. | |
182 | */ | |
183 | void afs_begin_writeback(struct netfs_io_request *wreq) | |
184 | { | |
6dd80936 DH |
185 | if (S_ISREG(wreq->inode->i_mode)) |
186 | afs_get_writeback_key(wreq); | |
ed22e1db DH |
187 | } |
188 | ||
189 | /* | |
1ecb146f DH |
190 | * Prepare to retry the writes in request. Use this to try rotating the |
191 | * available writeback keys. | |
ed22e1db | 192 | */ |
1ecb146f | 193 | void afs_retry_request(struct netfs_io_request *wreq, struct netfs_io_stream *stream) |
ed22e1db | 194 | { |
1ecb146f DH |
195 | struct netfs_io_subrequest *subreq = |
196 | list_first_entry(&stream->subrequests, | |
197 | struct netfs_io_subrequest, rreq_link); | |
ed22e1db | 198 | |
eddf51f2 DH |
199 | switch (wreq->origin) { |
200 | case NETFS_READAHEAD: | |
201 | case NETFS_READPAGE: | |
202 | case NETFS_READ_GAPS: | |
203 | case NETFS_READ_SINGLE: | |
204 | case NETFS_READ_FOR_WRITE: | |
db26d62d | 205 | case NETFS_UNBUFFERED_READ: |
eddf51f2 DH |
206 | case NETFS_DIO_READ: |
207 | return; | |
208 | default: | |
209 | break; | |
210 | } | |
211 | ||
1ecb146f DH |
212 | switch (subreq->error) { |
213 | case -EACCES: | |
214 | case -EPERM: | |
215 | case -ENOKEY: | |
216 | case -EKEYEXPIRED: | |
217 | case -EKEYREJECTED: | |
218 | case -EKEYREVOKED: | |
219 | afs_get_writeback_key(wreq); | |
220 | if (!wreq->netfs_priv) | |
221 | stream->failed = true; | |
222 | break; | |
ed22e1db | 223 | } |
ed22e1db DH |
224 | } |
225 | ||
31143d5d DH |
226 | /* |
227 | * write some of the pending data back to the server | |
228 | */ | |
3560358a | 229 | int afs_writepages(struct address_space *mapping, struct writeback_control *wbc) |
31143d5d | 230 | { |
ec0fa0b6 | 231 | struct afs_vnode *vnode = AFS_FS_I(mapping->host); |
31143d5d DH |
232 | int ret; |
233 | ||
ec0fa0b6 DH |
234 | /* We have to be careful as we can end up racing with setattr() |
235 | * truncating the pagecache since the caller doesn't take a lock here | |
236 | * to prevent it. | |
237 | */ | |
238 | if (wbc->sync_mode == WB_SYNC_ALL) | |
239 | down_read(&vnode->validate_lock); | |
240 | else if (!down_read_trylock(&vnode->validate_lock)) | |
241 | return 0; | |
242 | ||
3560358a | 243 | ret = netfs_writepages(mapping, wbc); |
ec0fa0b6 | 244 | up_read(&vnode->validate_lock); |
31143d5d DH |
245 | return ret; |
246 | } | |
247 | ||
31143d5d DH |
248 | /* |
249 | * flush any dirty pages for this process, and check for write errors. | |
250 | * - the return status from this call provides a reliable indication of | |
251 | * whether any write errors occurred for this process. | |
252 | */ | |
02c24a82 | 253 | int afs_fsync(struct file *file, loff_t start, loff_t end, int datasync) |
31143d5d | 254 | { |
3978d816 DH |
255 | struct afs_vnode *vnode = AFS_FS_I(file_inode(file)); |
256 | struct afs_file *af = file->private_data; | |
257 | int ret; | |
31143d5d | 258 | |
3b6492df | 259 | _enter("{%llx:%llu},{n=%pD},%d", |
3c981bfc | 260 | vnode->fid.vid, vnode->fid.vnode, file, |
31143d5d DH |
261 | datasync); |
262 | ||
3978d816 DH |
263 | ret = afs_validate(vnode, af->key); |
264 | if (ret < 0) | |
265 | return ret; | |
266 | ||
4343d008 | 267 | return file_write_and_wait_range(file, start, end); |
31143d5d | 268 | } |
9b3f26c9 DH |
269 | |
270 | /* | |
271 | * notification that a previously read-only page is about to become writable | |
272 | * - if it returns an error, the caller will deliver a bus error signal | |
273 | */ | |
0722f186 | 274 | vm_fault_t afs_page_mkwrite(struct vm_fault *vmf) |
9b3f26c9 | 275 | { |
1cf7a151 | 276 | struct file *file = vmf->vma->vm_file; |
3978d816 | 277 | |
3560358a DH |
278 | if (afs_validate(AFS_FS_I(file_inode(file)), afs_file_key(file)) < 0) |
279 | return VM_FAULT_SIGBUS; | |
280 | return netfs_page_mkwrite(vmf, NULL); | |
9b3f26c9 | 281 | } |
4343d008 DH |
282 | |
283 | /* | |
284 | * Prune the keys cached for writeback. The caller must hold vnode->wb_lock. | |
285 | */ | |
286 | void afs_prune_wb_keys(struct afs_vnode *vnode) | |
287 | { | |
288 | LIST_HEAD(graveyard); | |
289 | struct afs_wb_key *wbk, *tmp; | |
290 | ||
291 | /* Discard unused keys */ | |
292 | spin_lock(&vnode->wb_lock); | |
293 | ||
874c8ca1 DH |
294 | if (!mapping_tagged(&vnode->netfs.inode.i_data, PAGECACHE_TAG_WRITEBACK) && |
295 | !mapping_tagged(&vnode->netfs.inode.i_data, PAGECACHE_TAG_DIRTY)) { | |
4343d008 DH |
296 | list_for_each_entry_safe(wbk, tmp, &vnode->wb_keys, vnode_link) { |
297 | if (refcount_read(&wbk->usage) == 1) | |
298 | list_move(&wbk->vnode_link, &graveyard); | |
299 | } | |
300 | } | |
301 | ||
302 | spin_unlock(&vnode->wb_lock); | |
303 | ||
304 | while (!list_empty(&graveyard)) { | |
305 | wbk = list_entry(graveyard.next, struct afs_wb_key, vnode_link); | |
306 | list_del(&wbk->vnode_link); | |
307 | afs_put_wb_key(wbk); | |
308 | } | |
309 | } |