← Documents Documentation/filesystems/netfs_library.rst GitHub 원문 ↗

Linux 6.18.37 · Filesystems

Network Filesystem Services Library

netfslib request·stream·subrequest, VFS/VM helper, retry, fscache callback 계약의 전문 번역입니다.

Source pathDocumentation/filesystems/netfs_library.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.

1. 요약·해설

원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.

요약·해설

netfs_library.rst:1-1051

Netfslib는 network filesystem의 VM/VFS I/O를 request, destination별 stream, RPC·cache 단위 subrequest로 분해합니다. Filesystem은 크기 협상과 실제 RPC를 담당하고 library는 folio 상태, retry, 결과 집계, local cache와 writeback 수명을 관리합니다.

Callback 구현에서 가장 중요한 계약은 prepare와 issue의 실패 전달 방식, termination 전 field 갱신, folio reference·unlock을 library에 맡기는 것입니다. Cache-only folio와 일반 dirty folio는 별도 stream으로 처리되며 deprecated `PG_private_2` 경로는 새 구현에서 피해야 합니다.

Netfslib I/O 전체 흐름
VFS·VM high-level helper 진입request와 stream 생성cache·filesystem 크기 협상subrequest 병렬 issuetermination·progress 수집실패 구간 retry·fallbackfolio 상태와 writeback resource 정리

VFS 요청이 server와 cache I/O로 분해되고 다시 합쳐지는 과정입니다.

2. 영어 원문 전체

번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.

원문 전체 펼치기
1 .. SPDX-License-Identifier: GPL-2.0
2
3 ===================================
4 Network Filesystem Services Library
5 ===================================
6
7 .. Contents:
8
9 - Overview.
10 - Requests and streams.
11 - Subrequests.
12 - Result collection and retry.
13 - Local caching.
14 - Content encryption (fscrypt).
15 - Per-inode context.
16 - Inode context helper functions.
17 - Inode locking.
18 - Inode writeback.
19 - High-level VFS API.
20 - Unlocked read/write iter.
21 - Pre-locked read/write iter.
22 - Monolithic files API.
23 - Memory-mapped I/O API.
24 - High-level VM API.
25 - Deprecated PG_private2 API.
26 - I/O request API.
27 - Request structure.
28 - Stream structure.
29 - Subrequest structure.
30 - Filesystem methods.
31 - Terminating a subrequest.
32 - Local cache API.
33 - API function reference.
34
35
36 Overview
37 ========
38
39 The network filesystem services library, netfslib, is a set of functions
40 designed to aid a network filesystem in implementing VM/VFS API operations. It
41 takes over the normal buffered read, readahead, write and writeback and also
42 handles unbuffered and direct I/O.
43
44 The library provides support for (re-)negotiation of I/O sizes and retrying
45 failed I/O as well as local caching and will, in the future, provide content
46 encryption.
47
48 It insulates the filesystem from VM interface changes as much as possible and
49 handles VM features such as large multipage folios. The filesystem basically
50 just has to provide a way to perform read and write RPC calls.
51
52 The way I/O is organised inside netfslib consists of a number of objects:
53
54 * A *request*. A request is used to track the progress of the I/O overall and
55 to hold on to resources. The collection of results is done at the request
56 level. The I/O within a request is divided into a number of parallel
57 streams of subrequests.
58
59 * A *stream*. A non-overlapping series of subrequests. The subrequests
60 within a stream do not have to be contiguous.
61
62 * A *subrequest*. This is the basic unit of I/O. It represents a single RPC
63 call or a single cache I/O operation. The library passes these to the
64 filesystem and the cache to perform.
65
66 Requests and Streams
67 --------------------
68
69 When actually performing I/O (as opposed to just copying into the pagecache),
70 netfslib will create one or more requests to track the progress of the I/O and
71 to hold resources.
72
73 A read operation will have a single stream and the subrequests within that
74 stream may be of mixed origins, for instance mixing RPC subrequests and cache
75 subrequests.
76
77 On the other hand, a write operation may have multiple streams, where each
78 stream targets a different destination. For instance, there may be one stream
79 writing to the local cache and one to the server. Currently, only two streams
80 are allowed, but this could be increased if parallel writes to multiple servers
81 is desired.
82
83 The subrequests within a write stream do not need to match alignment or size
84 with the subrequests in another write stream and netfslib performs the tiling
85 of subrequests in each stream over the source buffer independently. Further,
86 each stream may contain holes that don't correspond to holes in the other
87 stream.
88
89 In addition, the subrequests do not need to correspond to the boundaries of the
90 folios or vectors in the source/destination buffer. The library handles the
91 collection of results and the wrangling of folio flags and references.
92
93 Subrequests
94 -----------
95
96 Subrequests are at the heart of the interaction between netfslib and the
97 filesystem using it. Each subrequest is expected to correspond to a single
98 read or write RPC or cache operation. The library will stitch together the
99 results from a set of subrequests to provide a higher level operation.
100
101 Netfslib has two interactions with the filesystem or the cache when setting up
102 a subrequest. First, there's an optional preparatory step that allows the
103 filesystem to negotiate the limits on the subrequest, both in terms of maximum
104 number of bytes and maximum number of vectors (e.g. for RDMA). This may
105 involve negotiating with the server (e.g. cifs needing to acquire credits).
106
107 And, secondly, there's the issuing step in which the subrequest is handed off
108 to the filesystem to perform.
109
110 Note that these two steps are done slightly differently between read and write:
111
112 * For reads, the VM/VFS tells us how much is being requested up front, so the
113 library can preset maximum values that the cache and then the filesystem can
114 then reduce. The cache also gets consulted first on whether it wants to do
115 a read before the filesystem is consulted.
116
117 * For writeback, it is unknown how much there will be to write until the
118 pagecache is walked, so no limit is set by the library.
119
120 Once a subrequest is completed, the filesystem or cache informs the library of
121 the completion and then collection is invoked. Depending on whether the
122 request is synchronous or asynchronous, the collection of results will be done
123 in either the application thread or in a work queue.
124
125 Result Collection and Retry
126 ---------------------------
127
128 As subrequests complete, the results are collected and collated by the library
129 and folio unlocking is performed progressively (if appropriate). Once the
130 request is complete, async completion will be invoked (again, if appropriate).
131 It is possible for the filesystem to provide interim progress reports to the
132 library to cause folio unlocking to happen earlier if possible.
133
134 If any subrequests fail, netfslib can retry them. It will wait until all
135 subrequests are completed, offer the filesystem the opportunity to fiddle with
136 the resources/state held by the request and poke at the subrequests before
137 re-preparing and re-issuing the subrequests.
138
139 This allows the tiling of contiguous sets of failed subrequest within a stream
140 to be changed, adding more subrequests or ditching excess as necessary (for
141 instance, if the network sizes change or the server decides it wants smaller
142 chunks).
143
144 Further, if one or more contiguous cache-read subrequests fail, the library
145 will pass them to the filesystem to perform instead, renegotiating and retiling
146 them as necessary to fit with the filesystem's parameters rather than those of
147 the cache.
148
149 Local Caching
150 -------------
151
152 One of the services netfslib provides, via ``fscache``, is the option to cache
153 on local disk a copy of the data obtained from/written to a network filesystem.
154 The library will manage the storing, retrieval and some invalidation of data
155 automatically on behalf of the filesystem if a cookie is attached to the
156 ``netfs_inode``.
157
158 Note that local caching used to use the PG_private_2 (aliased as PG_fscache) to
159 keep track of a page that was being written to the cache, but this is now
160 deprecated as PG_private_2 will be removed.
161
162 Instead, folios that are read from the server for which there was no data in
163 the cache will be marked as dirty and will have ``folio->private`` set to a
164 special value (``NETFS_FOLIO_COPY_TO_CACHE``) and left to writeback to write.
165 If the folio is modified before that happened, the special value will be
166 cleared and the write will become normally dirty.
167
168 When writeback occurs, folios that are so marked will only be written to the
169 cache and not to the server. Writeback handles mixed cache-only writes and
170 server-and-cache writes by using two streams, sending one to the cache and one
171 to the server. The server stream will have gaps in it corresponding to those
172 folios.
173
174 Content Encryption (fscrypt)
175 ----------------------------
176
177 Though it does not do so yet, at some point netfslib will acquire the ability
178 to do client-side content encryption on behalf of the network filesystem (Ceph,
179 for example). fscrypt can be used for this if appropriate (it may not be -
180 cifs, for example).
181
182 The data will be stored encrypted in the local cache using the same manner of
183 encryption as the data written to the server and the library will impose bounce
184 buffering and RMW cycles as necessary.
185
186
187 Per-Inode Context
188 =================
189
190 The network filesystem helper library needs a place to store a bit of state for
191 its use on each netfs inode it is helping to manage. To this end, a context
192 structure is defined::
193
194 struct netfs_inode {
195 struct inode inode;
196 const struct netfs_request_ops *ops;
197 struct fscache_cookie * cache;
198 loff_t remote_i_size;
199 unsigned long flags;
200 ...
201 };
202
203 A network filesystem that wants to use netfslib must place one of these in its
204 inode wrapper struct instead of the VFS ``struct inode``. This can be done in
205 a way similar to the following::
206
207 struct my_inode {
208 struct netfs_inode netfs; /* Netfslib context and vfs inode */
209 ...
210 };
211
212 This allows netfslib to find its state by using ``container_of()`` from the
213 inode pointer, thereby allowing the netfslib helper functions to be pointed to
214 directly by the VFS/VM operation tables.
215
216 The structure contains the following fields that are of interest to the
217 filesystem:
218
219 * ``inode``
220
221 The VFS inode structure.
222
223 * ``ops``
224
225 The set of operations provided by the network filesystem to netfslib.
226
227 * ``cache``
228
229 Local caching cookie, or NULL if no caching is enabled. This field does not
230 exist if fscache is disabled.
231
232 * ``remote_i_size``
233
234 The size of the file on the server. This differs from inode->i_size if
235 local modifications have been made but not yet written back.
236
237 * ``flags``
238
239 A set of flags, some of which the filesystem might be interested in:
240
241 * ``NETFS_ICTX_MODIFIED_ATTR``
242
243 Set if netfslib modifies mtime/ctime. The filesystem is free to ignore
244 this or clear it.
245
246 * ``NETFS_ICTX_UNBUFFERED``
247
248 Do unbuffered I/O upon the file. Like direct I/O but without the
249 alignment limitations. RMW will be performed if necessary. The pagecache
250 will not be used unless mmap() is also used.
251
252 * ``NETFS_ICTX_WRITETHROUGH``
253
254 Do writethrough caching upon the file. I/O will be set up and dispatched
255 as buffered writes are made to the page cache. mmap() does the normal
256 writeback thing.
257
258 * ``NETFS_ICTX_SINGLE_NO_UPLOAD``
259
260 Set if the file has a monolithic content that must be read entirely in a
261 single go and must not be written back to the server, though it can be
262 cached (e.g. AFS directories).
263
264 Inode Context Helper Functions
265 ------------------------------
266
267 To help deal with the per-inode context, a number helper functions are
268 provided. Firstly, a function to perform basic initialisation on a context and
269 set the operations table pointer::
270
271 void netfs_inode_init(struct netfs_inode *ctx,
272 const struct netfs_request_ops *ops);
273
274 then a function to cast from the VFS inode structure to the netfs context::
275
276 struct netfs_inode *netfs_inode(struct inode *inode);
277
278 and finally, a function to get the cache cookie pointer from the context
279 attached to an inode (or NULL if fscache is disabled)::
280
281 struct fscache_cookie *netfs_i_cookie(struct netfs_inode *ctx);
282
283 Inode Locking
284 -------------
285
286 A number of functions are provided to manage the locking of i_rwsem for I/O and
287 to effectively extend it to provide more separate classes of exclusion::
288
289 int netfs_start_io_read(struct inode *inode);
290 void netfs_end_io_read(struct inode *inode);
291 int netfs_start_io_write(struct inode *inode);
292 void netfs_end_io_write(struct inode *inode);
293 int netfs_start_io_direct(struct inode *inode);
294 void netfs_end_io_direct(struct inode *inode);
295
296 The exclusion breaks down into four separate classes:
297
298 1) Buffered reads and writes.
299
300 Buffered reads can run concurrently each other and with buffered writes,
301 but buffered writes cannot run concurrently with each other.
302
303 2) Direct reads and writes.
304
305 Direct (and unbuffered) reads and writes can run concurrently since they do
306 not share local buffering (i.e. the pagecache) and, in a network
307 filesystem, are expected to have exclusion managed on the server (though
308 this may not be the case for, say, Ceph).
309
310 3) Other major inode modifying operations (e.g. truncate, fallocate).
311
312 These should just access i_rwsem directly.
313
314 4) mmap().
315
316 mmap'd accesses might operate concurrently with any of the other classes.
317 They might form the buffer for an intra-file loopback DIO read/write. They
318 might be permitted on unbuffered files.
319
320 Inode Writeback
321 ---------------
322
323 Netfslib will pin resources on an inode for future writeback (such as pinning
324 use of an fscache cookie) when an inode is dirtied. However, this pinning
325 needs careful management. To manage the pinning, the following sequence
326 occurs:
327
328 1) An inode state flag ``I_PINNING_NETFS_WB`` is set by netfslib when the
329 pinning begins (when a folio is dirtied, for example) if the cache is
330 active to stop the cache structures from being discarded and the cache
331 space from being culled. This also prevents re-getting of cache resources
332 if the flag is already set.
333
334 2) This flag then cleared inside the inode lock during inode writeback in the
335 VM - and the fact that it was set is transferred to ``->unpinned_netfs_wb``
336 in ``struct writeback_control``.
337
338 3) If ``->unpinned_netfs_wb`` is now set, the write_inode procedure is forced.
339
340 4) The filesystem's ``->write_inode()`` function is invoked to do the cleanup.
341
342 5) The filesystem invokes netfs to do its cleanup.
343
344 To do the cleanup, netfslib provides a function to do the resource unpinning::
345
346 int netfs_unpin_writeback(struct inode *inode, struct writeback_control *wbc);
347
348 If the filesystem doesn't need to do anything else, this may be set as a its
349 ``.write_inode`` method.
350
351 Further, if an inode is deleted, the filesystem's write_inode method may not
352 get called, so::
353
354 void netfs_clear_inode_writeback(struct inode *inode, const void *aux);
355
356 must be called from ``->evict_inode()`` *before* ``clear_inode()`` is called.
357
358
359 High-Level VFS API
360 ==================
361
362 Netfslib provides a number of sets of API calls for the filesystem to delegate
363 VFS operations to. Netfslib, in turn, will call out to the filesystem and the
364 cache to negotiate I/O sizes, issue RPCs and provide places for it to intervene
365 at various times.
366
367 Unlocked Read/Write Iter
368 ------------------------
369
370 The first API set is for the delegation of operations to netfslib when the
371 filesystem is called through the standard VFS read/write_iter methods::
372
373 ssize_t netfs_file_read_iter(struct kiocb *iocb, struct iov_iter *iter);
374 ssize_t netfs_file_write_iter(struct kiocb *iocb, struct iov_iter *from);
375 ssize_t netfs_buffered_read_iter(struct kiocb *iocb, struct iov_iter *iter);
376 ssize_t netfs_unbuffered_read_iter(struct kiocb *iocb, struct iov_iter *iter);
377 ssize_t netfs_unbuffered_write_iter(struct kiocb *iocb, struct iov_iter *from);
378
379 They can be assigned directly to ``.read_iter`` and ``.write_iter``. They
380 perform the inode locking themselves and the first two will switch between
381 buffered I/O and DIO as appropriate.
382
383 Pre-Locked Read/Write Iter
384 --------------------------
385
386 The second API set is for the delegation of operations to netfslib when the
387 filesystem is called through the standard VFS methods, but needs to do some
388 other stuff before or after calling netfslib whilst still inside locked section
389 (e.g. Ceph negotiating caps). The unbuffered read function is::
390
391 ssize_t netfs_unbuffered_read_iter_locked(struct kiocb *iocb, struct iov_iter *iter);
392
393 This must not be assigned directly to ``.read_iter`` and the filesystem is
394 responsible for performing the inode locking before calling it. In the case of
395 buffered read, the filesystem should use ``filemap_read()``.
396
397 There are three functions for writes::
398
399 ssize_t netfs_buffered_write_iter_locked(struct kiocb *iocb, struct iov_iter *from,
400 struct netfs_group *netfs_group);
401 ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter,
402 struct netfs_group *netfs_group);
403 ssize_t netfs_unbuffered_write_iter_locked(struct kiocb *iocb, struct iov_iter *iter,
404 struct netfs_group *netfs_group);
405
406 These must not be assigned directly to ``.write_iter`` and the filesystem is
407 responsible for performing the inode locking before calling them.
408
409 The first two functions are for buffered writes; the first just adds some
410 standard write checks and jumps to the second, but if the filesystem wants to
411 do the checks itself, it can use the second directly. The third function is
412 for unbuffered or DIO writes.
413
414 On all three write functions, there is a writeback group pointer (which should
415 be NULL if the filesystem doesn't use this). Writeback groups are set on
416 folios when they're modified. If a folio to-be-modified is already marked with
417 a different group, it is flushed first. The writeback API allows writing back
418 of a specific group.
419
420 Memory-Mapped I/O API
421 ---------------------
422
423 An API for support of mmap()'d I/O is provided::
424
425 vm_fault_t netfs_page_mkwrite(struct vm_fault *vmf, struct netfs_group *netfs_group);
426
427 This allows the filesystem to delegate ``.page_mkwrite`` to netfslib. The
428 filesystem should not take the inode lock before calling it, but, as with the
429 locked write functions above, this does take a writeback group pointer. If the
430 page to be made writable is in a different group, it will be flushed first.
431
432 Monolithic Files API
433 --------------------
434
435 There is also a special API set for files for which the content must be read in
436 a single RPC (and not written back) and is maintained as a monolithic blob
437 (e.g. an AFS directory), though it can be stored and updated in the local cache::
438
439 ssize_t netfs_read_single(struct inode *inode, struct file *file, struct iov_iter *iter);
440 void netfs_single_mark_inode_dirty(struct inode *inode);
441 int netfs_writeback_single(struct address_space *mapping,
442 struct writeback_control *wbc,
443 struct iov_iter *iter);
444
445 The first function reads from a file into the given buffer, reading from the
446 cache in preference if the data is cached there; the second function allows the
447 inode to be marked dirty, causing a later writeback; and the third function can
448 be called from the writeback code to write the data to the cache, if there is
449 one.
450
451 The inode should be marked ``NETFS_ICTX_SINGLE_NO_UPLOAD`` if this API is to be
452 used. The writeback function requires the buffer to be of ITER_FOLIOQ type.
453
454 High-Level VM API
455 ==================
456
457 Netfslib also provides a number of sets of API calls for the filesystem to
458 delegate VM operations to. Again, netfslib, in turn, will call out to the
459 filesystem and the cache to negotiate I/O sizes, issue RPCs and provide places
460 for it to intervene at various times::
461
462 void netfs_readahead(struct readahead_control *);
463 int netfs_read_folio(struct file *, struct folio *);
464 int netfs_writepages(struct address_space *mapping,
465 struct writeback_control *wbc);
466 bool netfs_dirty_folio(struct address_space *mapping, struct folio *folio);
467 void netfs_invalidate_folio(struct folio *folio, size_t offset, size_t length);
468 bool netfs_release_folio(struct folio *folio, gfp_t gfp);
469
470 These are ``address_space_operations`` methods and can be set directly in the
471 operations table.
472
473 Deprecated PG_private_2 API
474 ---------------------------
475
476 There is also a deprecated function for filesystems that still use the
477 ``->write_begin`` method::
478
479 int netfs_write_begin(struct netfs_inode *inode, struct file *file,
480 struct address_space *mapping, loff_t pos, unsigned int len,
481 struct folio **_folio, void **_fsdata);
482
483 It uses the deprecated PG_private_2 flag and so should not be used.
484
485
486 I/O Request API
487 ===============
488
489 The I/O request API comprises a number of structures and a number of functions
490 that the filesystem may need to use.
491
492 Request Structure
493 -----------------
494
495 The request structure manages the request as a whole, holding some resources
496 and state on behalf of the filesystem and tracking the collection of results::
497
498 struct netfs_io_request {
499 enum netfs_io_origin origin;
500 struct inode *inode;
501 struct address_space *mapping;
502 struct netfs_group *group;
503 struct netfs_io_stream io_streams[];
504 void *netfs_priv;
505 void *netfs_priv2;
506 unsigned long long start;
507 unsigned long long len;
508 unsigned long long i_size;
509 unsigned int debug_id;
510 unsigned long flags;
511 ...
512 };
513
514 Many of the fields are for internal use, but the fields shown here are of
515 interest to the filesystem:
516
517 * ``origin``
518
519 The origin of the request (readahead, read_folio, DIO read, writeback, ...).
520
521 * ``inode``
522 * ``mapping``
523
524 The inode and the address space of the file being read from. The mapping
525 may or may not point to inode->i_data.
526
527 * ``group``
528
529 The writeback group this request is dealing with or NULL. This holds a ref
530 on the group.
531
532 * ``io_streams``
533
534 The parallel streams of subrequests available to the request. Currently two
535 are available, but this may be made extensible in future. ``NR_IO_STREAMS``
536 indicates the size of the array.
537
538 * ``netfs_priv``
539 * ``netfs_priv2``
540
541 The network filesystem's private data. The value for this can be passed in
542 to the helper functions or set during the request.
543
544 * ``start``
545 * ``len``
546
547 The file position of the start of the read request and the length. These
548 may be altered by the ->expand_readahead() op.
549
550 * ``i_size``
551
552 The size of the file at the start of the request.
553
554 * ``debug_id``
555
556 A number allocated to this operation that can be displayed in trace lines
557 for reference.
558
559 * ``flags``
560
561 Flags for managing and controlling the operation of the request. Some of
562 these may be of interest to the filesystem:
563
564 * ``NETFS_RREQ_RETRYING``
565
566 Netfslib sets this when generating retries.
567
568 * ``NETFS_RREQ_PAUSE``
569
570 The filesystem can set this to request to pause the library's subrequest
571 issuing loop - but care needs to be taken as netfslib may also set it.
572
573 * ``NETFS_RREQ_NONBLOCK``
574 * ``NETFS_RREQ_BLOCKED``
575
576 Netfslib sets the first to indicate that non-blocking mode was set by the
577 caller and the filesystem can set the second to indicate that it would
578 have had to block.
579
580 * ``NETFS_RREQ_USE_PGPRIV2``
581
582 The filesystem can set this if it wants to use PG_private_2 to track
583 whether a folio is being written to the cache. This is deprecated as
584 PG_private_2 is going to go away.
585
586 If the filesystem wants more private data than is afforded by this structure,
587 then it should wrap it and provide its own allocator.
588
589 Stream Structure
590 ----------------
591
592 A request is comprised of one or more parallel streams and each stream may be
593 aimed at a different target.
594
595 For read requests, only stream 0 is used. This can contain a mixture of
596 subrequests aimed at different sources. For write requests, stream 0 is used
597 for the server and stream 1 is used for the cache. For buffered writeback,
598 stream 0 is not enabled unless a normal dirty folio is encountered, at which
599 point ->begin_writeback() will be invoked and the filesystem can mark the
600 stream available.
601
602 The stream struct looks like::
603
604 struct netfs_io_stream {
605 unsigned char stream_nr;
606 bool avail;
607 size_t sreq_max_len;
608 unsigned int sreq_max_segs;
609 unsigned int submit_extendable_to;
610 ...
611 };
612
613 A number of members are available for access/use by the filesystem:
614
615 * ``stream_nr``
616
617 The number of the stream within the request.
618
619 * ``avail``
620
621 True if the stream is available for use. The filesystem should set this on
622 stream zero if in ->begin_writeback().
623
624 * ``sreq_max_len``
625 * ``sreq_max_segs``
626
627 These are set by the filesystem or the cache in ->prepare_read() or
628 ->prepare_write() for each subrequest to indicate the maximum number of
629 bytes and, optionally, the maximum number of segments (if not 0) that that
630 subrequest can support.
631
632 * ``submit_extendable_to``
633
634 The size that a subrequest can be rounded up to beyond the EOF, given the
635 available buffer. This allows the cache to work out if it can do a DIO read
636 or write that straddles the EOF marker.
637
638 Subrequest Structure
639 --------------------
640
641 Individual units of I/O are managed by the subrequest structure. These
642 represent slices of the overall request and run independently::
643
644 struct netfs_io_subrequest {
645 struct netfs_io_request *rreq;
646 struct iov_iter io_iter;
647 unsigned long long start;
648 size_t len;
649 size_t transferred;
650 unsigned long flags;
651 short error;
652 unsigned short debug_index;
653 unsigned char stream_nr;
654 ...
655 };
656
657 Each subrequest is expected to access a single source, though the library will
658 handle falling back from one source type to another. The members are:
659
660 * ``rreq``
661
662 A pointer to the read request.
663
664 * ``io_iter``
665
666 An I/O iterator representing a slice of the buffer to be read into or
667 written from.
668
669 * ``start``
670 * ``len``
671
672 The file position of the start of this slice of the read request and the
673 length.
674
675 * ``transferred``
676
677 The amount of data transferred so far for this subrequest. This should be
678 added to with the length of the transfer made by this issuance of the
679 subrequest. If this is less than ``len`` then the subrequest may be
680 reissued to continue.
681
682 * ``flags``
683
684 Flags for managing the subrequest. There are a number of interest to the
685 filesystem or cache:
686
687 * ``NETFS_SREQ_MADE_PROGRESS``
688
689 Set by the filesystem to indicates that at least one byte of data was read
690 or written.
691
692 * ``NETFS_SREQ_HIT_EOF``
693
694 The filesystem should set this if a read hit the EOF on the file (in which
695 case ``transferred`` should stop at the EOF). Netfslib may expand the
696 subrequest out to the size of the folio containing the EOF on the off
697 chance that a third party change happened or a DIO read may have asked for
698 more than is available. The library will clear any excess pagecache.
699
700 * ``NETFS_SREQ_CLEAR_TAIL``
701
702 The filesystem can set this to indicate that the remainder of the slice,
703 from transferred to len, should be cleared. Do not set if HIT_EOF is set.
704
705 * ``NETFS_SREQ_NEED_RETRY``
706
707 The filesystem can set this to tell netfslib to retry the subrequest.
708
709 * ``NETFS_SREQ_BOUNDARY``
710
711 This can be set by the filesystem on a subrequest to indicate that it ends
712 at a boundary with the filesystem structure (e.g. at the end of a Ceph
713 object). It tells netfslib not to retile subrequests across it.
714
715 * ``error``
716
717 This is for the filesystem to store result of the subrequest. It should be
718 set to 0 if successful and a negative error code otherwise.
719
720 * ``debug_index``
721 * ``stream_nr``
722
723 A number allocated to this slice that can be displayed in trace lines for
724 reference and the number of the request stream that it belongs to.
725
726 If necessary, the filesystem can get and put extra refs on the subrequest it is
727 given::
728
729 void netfs_get_subrequest(struct netfs_io_subrequest *subreq,
730 enum netfs_sreq_ref_trace what);
731 void netfs_put_subrequest(struct netfs_io_subrequest *subreq,
732 enum netfs_sreq_ref_trace what);
733
734 using netfs trace codes to indicate the reason. Care must be taken, however,
735 as once control of the subrequest is returned to netfslib, the same subrequest
736 can be reissued/retried.
737
738 Filesystem Methods
739 ------------------
740
741 The filesystem sets a table of operations in ``netfs_inode`` for netfslib to
742 use::
743
744 struct netfs_request_ops {
745 mempool_t *request_pool;
746 mempool_t *subrequest_pool;
747 int (*init_request)(struct netfs_io_request *rreq, struct file *file);
748 void (*free_request)(struct netfs_io_request *rreq);
749 void (*free_subrequest)(struct netfs_io_subrequest *rreq);
750 void (*expand_readahead)(struct netfs_io_request *rreq);
751 int (*prepare_read)(struct netfs_io_subrequest *subreq);
752 void (*issue_read)(struct netfs_io_subrequest *subreq);
753 void (*done)(struct netfs_io_request *rreq);
754 void (*update_i_size)(struct inode *inode, loff_t i_size);
755 void (*post_modify)(struct inode *inode);
756 void (*begin_writeback)(struct netfs_io_request *wreq);
757 void (*prepare_write)(struct netfs_io_subrequest *subreq);
758 void (*issue_write)(struct netfs_io_subrequest *subreq);
759 void (*retry_request)(struct netfs_io_request *wreq,
760 struct netfs_io_stream *stream);
761 void (*invalidate_cache)(struct netfs_io_request *wreq);
762 };
763
764 The table starts with a pair of optional pointers to memory pools from which
765 requests and subrequests can be allocated. If these are not given, netfslib
766 has default pools that it will use instead. If the filesystem wraps the netfs
767 structs in its own larger structs, then it will need to use its own pools.
768 Netfslib will allocate directly from the pools.
769
770 The methods defined in the table are:
771
772 * ``init_request()``
773 * ``free_request()``
774 * ``free_subrequest()``
775
776 [Optional] A filesystem may implement these to initialise or clean up any
777 resources that it attaches to the request or subrequest.
778
779 * ``expand_readahead()``
780
781 [Optional] This is called to allow the filesystem to expand the size of a
782 readahead request. The filesystem gets to expand the request in both
783 directions, though it must retain the initial region as that may represent
784 an allocation already made. If local caching is enabled, it gets to expand
785 the request first.
786
787 Expansion is communicated by changing ->start and ->len in the request
788 structure. Note that if any change is made, ->len must be increased by at
789 least as much as ->start is reduced.
790
791 * ``prepare_read()``
792
793 [Optional] This is called to allow the filesystem to limit the size of a
794 subrequest. It may also limit the number of individual regions in iterator,
795 such as required by RDMA. This information should be set on stream zero in::
796
797 rreq->io_streams[0].sreq_max_len
798 rreq->io_streams[0].sreq_max_segs
799
800 The filesystem can use this, for example, to chop up a request that has to
801 be split across multiple servers or to put multiple reads in flight.
802
803 Zero should be returned on success and an error code otherwise.
804
805 * ``issue_read()``
806
807 [Required] Netfslib calls this to dispatch a subrequest to the server for
808 reading. In the subrequest, ->start, ->len and ->transferred indicate what
809 data should be read from the server and ->io_iter indicates the buffer to be
810 used.
811
812 There is no return value; the ``netfs_read_subreq_terminated()`` function
813 should be called to indicate that the subrequest completed either way.
814 ->error, ->transferred and ->flags should be updated before completing. The
815 termination can be done asynchronously.
816
817 Note: the filesystem must not deal with setting folios uptodate, unlocking
818 them or dropping their refs - the library deals with this as it may have to
819 stitch together the results of multiple subrequests that variously overlap
820 the set of folios.
821
822 * ``done()``
823
824 [Optional] This is called after the folios in a read request have all been
825 unlocked (and marked uptodate if applicable).
826
827 * ``update_i_size()``
828
829 [Optional] This is invoked by netfslib at various points during the write
830 paths to ask the filesystem to update its idea of the file size. If not
831 given, netfslib will set i_size and i_blocks and update the local cache
832 cookie.
833
834 * ``post_modify()``
835
836 [Optional] This is called after netfslib writes to the pagecache or when it
837 allows an mmap'd page to be marked as writable.
838
839 * ``begin_writeback()``
840
841 [Optional] Netfslib calls this when processing a writeback request if it
842 finds a dirty page that isn't simply marked NETFS_FOLIO_COPY_TO_CACHE,
843 indicating it must be written to the server. This allows the filesystem to
844 only set up writeback resources when it knows it's going to have to perform
845 a write.
846
847 * ``prepare_write()``
848
849 [Optional] This is called to allow the filesystem to limit the size of a
850 subrequest. It may also limit the number of individual regions in iterator,
851 such as required by RDMA. This information should be set on stream to which
852 the subrequest belongs::
853
854 rreq->io_streams[subreq->stream_nr].sreq_max_len
855 rreq->io_streams[subreq->stream_nr].sreq_max_segs
856
857 The filesystem can use this, for example, to chop up a request that has to
858 be split across multiple servers or to put multiple writes in flight.
859
860 This is not permitted to return an error. Instead, in the event of failure,
861 ``netfs_prepare_write_failed()`` must be called.
862
863 * ``issue_write()``
864
865 [Required] This is used to dispatch a subrequest to the server for writing.
866 In the subrequest, ->start, ->len and ->transferred indicate what data
867 should be written to the server and ->io_iter indicates the buffer to be
868 used.
869
870 There is no return value; the ``netfs_write_subreq_terminated()`` function
871 should be called to indicate that the subrequest completed either way.
872 ->error, ->transferred and ->flags should be updated before completing. The
873 termination can be done asynchronously.
874
875 Note: the filesystem must not deal with removing the dirty or writeback
876 marks on folios involved in the operation and should not take refs or pins
877 on them, but should leave retention to netfslib.
878
879 * ``retry_request()``
880
881 [Optional] Netfslib calls this at the beginning of a retry cycle. This
882 allows the filesystem to examine the state of the request, the subrequests
883 in the indicated stream and of its own data and make adjustments or
884 renegotiate resources.
885
886 * ``invalidate_cache()``
887
888 [Optional] This is called by netfslib to invalidate data stored in the local
889 cache in the event that writing to the local cache fails, providing updated
890 coherency data that netfs can't provide.
891
892 Terminating a subrequest
893 ------------------------
894
895 When a subrequest completes, there are a number of functions that the cache or
896 subrequest can call to inform netfslib of the status change. One function is
897 provided to terminate a write subrequest at the preparation stage and acts
898 synchronously:
899
900 * ``void netfs_prepare_write_failed(struct netfs_io_subrequest *subreq);``
901
902 Indicate that the ->prepare_write() call failed. The ``error`` field should
903 have been updated.
904
905 Note that ->prepare_read() can return an error as a read can simply be aborted.
906 Dealing with writeback failure is trickier.
907
908 The other functions are used for subrequests that got as far as being issued:
909
910 * ``void netfs_read_subreq_terminated(struct netfs_io_subrequest *subreq);``
911
912 Tell netfslib that a read subrequest has terminated. The ``error``,
913 ``flags`` and ``transferred`` fields should have been updated.
914
915 * ``void netfs_write_subrequest_terminated(void *_op, ssize_t transferred_or_error);``
916
917 Tell netfslib that a write subrequest has terminated. Either the amount of
918 data processed or the negative error code can be passed in. This is
919 can be used as a kiocb completion function.
920
921 * ``void netfs_read_subreq_progress(struct netfs_io_subrequest *subreq);``
922
923 This is provided to optionally update netfslib on the incremental progress
924 of a read, allowing some folios to be unlocked early and does not actually
925 terminate the subrequest. The ``transferred`` field should have been
926 updated.
927
928 Local Cache API
929 ---------------
930
931 Netfslib provides a separate API for a local cache to implement, though it
932 provides some somewhat similar routines to the filesystem request API.
933
934 Firstly, the netfs_io_request object contains a place for the cache to hang its
935 state::
936
937 struct netfs_cache_resources {
938 const struct netfs_cache_ops *ops;
939 void *cache_priv;
940 void *cache_priv2;
941 unsigned int debug_id;
942 unsigned int inval_counter;
943 };
944
945 This contains an operations table pointer and two private pointers plus the
946 debug ID of the fscache cookie for tracing purposes and an invalidation counter
947 that is cranked by calls to ``fscache_invalidate()`` allowing cache subrequests
948 to be invalidated after completion.
949
950 The cache operation table looks like the following::
951
952 struct netfs_cache_ops {
953 void (*end_operation)(struct netfs_cache_resources *cres);
954 void (*expand_readahead)(struct netfs_cache_resources *cres,
955 loff_t *_start, size_t *_len, loff_t i_size);
956 enum netfs_io_source (*prepare_read)(struct netfs_io_subrequest *subreq,
957 loff_t i_size);
958 int (*read)(struct netfs_cache_resources *cres,
959 loff_t start_pos,
960 struct iov_iter *iter,
961 bool seek_data,
962 netfs_io_terminated_t term_func,
963 void *term_func_priv);
964 void (*prepare_write_subreq)(struct netfs_io_subrequest *subreq);
965 void (*issue_write)(struct netfs_io_subrequest *subreq);
966 };
967
968 With a termination handler function pointer::
969
970 typedef void (*netfs_io_terminated_t)(void *priv,
971 ssize_t transferred_or_error,
972 bool was_async);
973
974 The methods defined in the table are:
975
976 * ``end_operation()``
977
978 [Required] Called to clean up the resources at the end of the read request.
979
980 * ``expand_readahead()``
981
982 [Optional] Called at the beginning of a readahead operation to allow the
983 cache to expand a request in either direction. This allows the cache to
984 size the request appropriately for the cache granularity.
985
986 * ``prepare_read()``
987
988 [Required] Called to configure the next slice of a request. ->start and
989 ->len in the subrequest indicate where and how big the next slice can be;
990 the cache gets to reduce the length to match its granularity requirements.
991
992 The function is passed pointers to the start and length in its parameters,
993 plus the size of the file for reference, and adjusts the start and length
994 appropriately. It should return one of:
995
996 * ``NETFS_FILL_WITH_ZEROES``
997 * ``NETFS_DOWNLOAD_FROM_SERVER``
998 * ``NETFS_READ_FROM_CACHE``
999 * ``NETFS_INVALID_READ``
1001 to indicate whether the slice should just be cleared or whether it should be
1002 downloaded from the server or read from the cache - or whether slicing
1003 should be given up at the current point.
1005 * ``read()``
1007 [Required] Called to read from the cache. The start file offset is given
1008 along with an iterator to read to, which gives the length also. It can be
1009 given a hint requesting that it seek forward from that start position for
1010 data.
1012 Also provided is a pointer to a termination handler function and private
1013 data to pass to that function. The termination function should be called
1014 with the number of bytes transferred or an error code, plus a flag
1015 indicating whether the termination is definitely happening in the caller's
1016 context.
1018 * ``prepare_write_subreq()``
1020 [Required] This is called to allow the cache to limit the size of a
1021 subrequest. It may also limit the number of individual regions in iterator,
1022 such as required by DIO/DMA. This information should be set on stream to
1023 which the subrequest belongs::
1025 rreq->io_streams[subreq->stream_nr].sreq_max_len
1026 rreq->io_streams[subreq->stream_nr].sreq_max_segs
1028 The filesystem can use this, for example, to chop up a request that has to
1029 be split across multiple servers or to put multiple writes in flight.
1031 This is not permitted to return an error. In the event of failure,
1032 ``netfs_prepare_write_failed()`` must be called.
1034 * ``issue_write()``
1036 [Required] This is used to dispatch a subrequest to the cache for writing.
1037 In the subrequest, ->start, ->len and ->transferred indicate what data
1038 should be written to the cache and ->io_iter indicates the buffer to be
1039 used.
1041 There is no return value; the ``netfs_write_subreq_terminated()`` function
1042 should be called to indicate that the subrequest completed either way.
1043 ->error, ->transferred and ->flags should be updated before completing. The
1044 termination can be done asynchronously.
1047 API Function Reference
1048 ======================
1050 .. kernel-doc:: include/linux/netfs.h
1051 .. kernel-doc:: fs/netfs/buffered_read.c

3. 한국어 전문 번역

영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.

netfslib의 범위와 세 객체

1-66

Network filesystem services library인 netfslib는 network filesystem이 VM/VFS API operation을 구현하도록 돕는 함수 집합입니다. 일반 buffered read, readahead, write, writeback을 맡고 unbuffered 및 direct I/O도 처리합니다.

I/O 크기 재협상과 실패한 I/O retry, local caching을 지원하며 미래에는 content encryption도 제공할 예정입니다. VM interface 변경에서 파일시스템을 가능한 한 격리하고 large multipage folio 같은 VM 기능을 처리하므로 파일시스템은 기본적으로 read·write RPC 수단만 제공하면 됩니다.

내부 I/O는 request, stream, subrequest 세 객체로 구성됩니다. Request는 전체 I/O 진행과 resource를 추적하며 결과 집계도 request level에서 수행합니다. 하나의 request I/O는 여러 parallel stream의 subrequest로 나뉩니다.

Stream은 서로 겹치지 않는 subrequest의 연속이며 내부 subrequest가 반드시 contiguous일 필요는 없습니다. Subrequest는 기본 I/O 단위로 RPC 하나 또는 cache I/O 하나를 나타내며 library가 filesystem이나 cache에 실행을 맡깁니다.

netfslib 객체 계층
request: 전체 진행·resource·결과 집계parallel stream: destination별 non-overlap 작업열subrequest: RPC 또는 cache I/O 한 건filesystem·cache가 실행request level에서 결과 재조립

전체 작업에서 실제 RPC·cache operation까지의 분해입니다.

.. SPDX-License-Identifier: GPL-2.0

===================================
Network Filesystem Services Library
===================================

.. Contents:

 - Overview.
   - Requests and streams.
   - Subrequests.
   - Result collection and retry.
   - Local caching.
   - Content encryption (fscrypt).
 - Per-inode context.
   - Inode context helper functions.
   - Inode locking.
   - Inode writeback.
 - High-level VFS API.
   - Unlocked read/write iter.
   - Pre-locked read/write iter.
   - Monolithic files API.
   - Memory-mapped I/O API.
 - High-level VM API.
   - Deprecated PG_private2 API.
 - I/O request API.
   - Request structure.
   - Stream structure.
   - Subrequest structure.
   - Filesystem methods.
   - Terminating a subrequest.
   - Local cache API.
 - API function reference.


Overview
========

The network filesystem services library, netfslib, is a set of functions
designed to aid a network filesystem in implementing VM/VFS API operations.  It
takes over the normal buffered read, readahead, write and writeback and also
handles unbuffered and direct I/O.

The library provides support for (re-)negotiation of I/O sizes and retrying
failed I/O as well as local caching and will, in the future, provide content
encryption.

It insulates the filesystem from VM interface changes as much as possible and
handles VM features such as large multipage folios.  The filesystem basically
just has to provide a way to perform read and write RPC calls.

The way I/O is organised inside netfslib consists of a number of objects:

 * A *request*.  A request is used to track the progress of the I/O overall and
   to hold on to resources.  The collection of results is done at the request
   level.  The I/O within a request is divided into a number of parallel
   streams of subrequests.

 * A *stream*.  A non-overlapping series of subrequests.  The subrequests
   within a stream do not have to be contiguous.

 * A *subrequest*.  This is the basic unit of I/O.  It represents a single RPC
   call or a single cache I/O operation.  The library passes these to the
   filesystem and the cache to perform.

Requests and Streams

읽기와 쓰기 stream 구성

67-93

Page cache에 복사만 하는 경우가 아니라 실제 I/O를 수행할 때 netfslib는 진행 추적과 resource 보유를 위해 request를 하나 이상 만듭니다.

Read operation은 stream 하나만 사용하며 그 안에는 RPC와 cache subrequest처럼 source가 다른 subrequest가 섞일 수 있습니다.

Write operation은 destination마다 별도 stream을 둘 수 있습니다. 예를 들어 local cache용 stream과 server용 stream이 있습니다. 현재 최대 두 stream만 허용하지만 여러 server에 병렬 write가 필요하면 늘릴 수 있습니다.

한 write stream의 subrequest alignment·size는 다른 stream과 맞을 필요가 없습니다. Netfslib가 각 stream에서 source buffer 위 subrequest tiling을 독립 수행하고, 한 stream에는 다른 stream과 대응하지 않는 hole도 있을 수 있습니다.

Subrequest는 source·destination buffer의 folio 또는 vector boundary와도 맞을 필요가 없습니다. Library가 결과 집계와 folio flag·reference 처리를 담당합니다.

Read·write stream 차이
operationstream 구성
readstream 1개, RPC·cache source 혼합 가능
writedestination별 stream, 현재 server+cache 2개
tilingstream마다 alignment·size·hole 독립
buffer 경계folio·vector boundary와 일치 불필요

Source 혼합과 destination 병렬화 방식을 비교합니다.

--------------------

When actually performing I/O (as opposed to just copying into the pagecache),
netfslib will create one or more requests to track the progress of the I/O and
to hold resources.

A read operation will have a single stream and the subrequests within that
stream may be of mixed origins, for instance mixing RPC subrequests and cache
subrequests.

On the other hand, a write operation may have multiple streams, where each
stream targets a different destination.  For instance, there may be one stream
writing to the local cache and one to the server.  Currently, only two streams
are allowed, but this could be increased if parallel writes to multiple servers
is desired.

The subrequests within a write stream do not need to match alignment or size
with the subrequests in another write stream and netfslib performs the tiling
of subrequests in each stream over the source buffer independently.  Further,
each stream may contain holes that don't correspond to holes in the other
stream.

In addition, the subrequests do not need to correspond to the boundaries of the
folios or vectors in the source/destination buffer.  The library handles the
collection of results and the wrangling of folio flags and references.

Subrequests

Subrequest 협상과 발행

94-125

Subrequest는 netfslib와 사용하는 filesystem 사이 상호작용의 중심입니다. 각 subrequest는 read·write RPC 하나 또는 cache operation 하나에 대응하며 library가 여러 결과를 이어 붙여 고수준 operation을 만듭니다.

설정 과정은 두 단계입니다. 선택적 prepare 단계에서 filesystem은 최대 byte 수와 최대 vector 수를 제한할 수 있습니다. RDMA 제한이나 CIFS credit 획득처럼 server와의 협상이 필요할 수 있습니다. 다음 issue 단계에서 subrequest를 filesystem에 넘겨 실제 실행합니다.

Read는 VM/VFS가 요청 크기를 미리 알려주므로 library가 최대값을 설정한 뒤 cache, filesystem 순으로 줄일 수 있습니다. Cache가 read를 수행할 의사가 있는지도 filesystem보다 먼저 확인합니다.

Writeback은 page cache를 걸어보기 전까지 쓸 양을 모르므로 library가 한도를 설정하지 않습니다.

완료 시 filesystem 또는 cache가 library에 알리고 collection이 시작됩니다. Sync request는 application thread, async request는 work queue에서 결과를 집계합니다.

Subrequest 수명주기
선택적 prepare와 byte·vector 제한filesystem 또는 cache에 issueRPC·cache I/O 실행termination 통지application thread 또는 work queue에서 collection

크기 협상에서 결과 collection까지의 공통 흐름입니다.

-----------

Subrequests are at the heart of the interaction between netfslib and the
filesystem using it.  Each subrequest is expected to correspond to a single
read or write RPC or cache operation.  The library will stitch together the
results from a set of subrequests to provide a higher level operation.

Netfslib has two interactions with the filesystem or the cache when setting up
a subrequest.  First, there's an optional preparatory step that allows the
filesystem to negotiate the limits on the subrequest, both in terms of maximum
number of bytes and maximum number of vectors (e.g. for RDMA).  This may
involve negotiating with the server (e.g. cifs needing to acquire credits).

And, secondly, there's the issuing step in which the subrequest is handed off
to the filesystem to perform.

Note that these two steps are done slightly differently between read and write:

 * For reads, the VM/VFS tells us how much is being requested up front, so the
   library can preset maximum values that the cache and then the filesystem can
   then reduce.  The cache also gets consulted first on whether it wants to do
   a read before the filesystem is consulted.

 * For writeback, it is unknown how much there will be to write until the
   pagecache is walked, so no limit is set by the library.

Once a subrequest is completed, the filesystem or cache informs the library of
the completion and then collection is invoked.  Depending on whether the
request is synchronous or asynchronous, the collection of results will be done
in either the application thread or in a work queue.

Result Collection and Retry

결과 집계와 실패 구간 retiling

126-149

Subrequest가 끝날 때마다 library가 결과를 모아 정리하고 적절하면 folio를 점진적으로 unlock합니다. Request가 끝나면 필요 시 async completion을 호출합니다. Filesystem이 중간 진행을 알려 더 일찍 folio를 unlock하게 할 수도 있습니다.

Subrequest가 실패하면 netfslib가 retry할 수 있습니다. 모든 subrequest 완료를 기다린 뒤 filesystem이 request resource·state와 subrequest를 조정할 기회를 주고 다시 prepare·issue합니다.

이 과정에서 stream 안의 연속 실패 subrequest tiling을 바꾸고 필요에 따라 subrequest를 추가하거나 남는 것을 버릴 수 있습니다. Network size가 달라지거나 server가 더 작은 chunk를 요구하는 경우가 예입니다.

연속된 cache-read subrequest 하나 이상이 실패하면 library가 filesystem 실행으로 전환합니다. Cache parameter가 아니라 filesystem parameter에 맞게 다시 협상하고 retile합니다.

Retry와 fallback
모든 subrequest completion 수집filesystem이 request·resource 상태 조정연속 실패 구간 retile재-prepare·재-issuecache read 실패 시 server RPC로 fallback

모든 결과를 모은 뒤 실패 구간만 새 조건으로 재구성합니다.

---------------------------

As subrequests complete, the results are collected and collated by the library
and folio unlocking is performed progressively (if appropriate).  Once the
request is complete, async completion will be invoked (again, if appropriate).
It is possible for the filesystem to provide interim progress reports to the
library to cause folio unlocking to happen earlier if possible.

If any subrequests fail, netfslib can retry them.  It will wait until all
subrequests are completed, offer the filesystem the opportunity to fiddle with
the resources/state held by the request and poke at the subrequests before
re-preparing and re-issuing the subrequests.

This allows the tiling of contiguous sets of failed subrequest within a stream
to be changed, adding more subrequests or ditching excess as necessary (for
instance, if the network sizes change or the server decides it wants smaller
chunks).

Further, if one or more contiguous cache-read subrequests fail, the library
will pass them to the filesystem to perform instead, renegotiating and retiling
them as necessary to fit with the filesystem's parameters rather than those of
the cache.

Local Caching

fscache와 cache-only writeback

150-174

Netfslib는 `fscache`를 통해 network filesystem에서 얻거나 쓴 데이터 사본을 local disk에 cache할 수 있습니다. `netfs_inode`에 cookie가 연결되면 library가 저장·조회와 일부 invalidation을 자동 관리합니다.

과거에는 cache에 write 중인 page를 추적하려고 `PG_private_2`, 별칭 `PG_fscache`를 사용했지만 `PG_private_2` 제거 예정으로 이 방식은 deprecated되었습니다.

대신 cache에 데이터가 없어 server에서 읽은 folio를 dirty로 표시하고 `folio->private`에 `NETFS_FOLIO_COPY_TO_CACHE`를 설정하여 writeback이 cache에 쓰게 합니다. 그 전에 folio가 수정되면 special value를 clear하고 일반 dirty write가 됩니다.

Writeback에서 이 표시가 있는 folio는 server가 아니라 cache에만 씁니다. Cache-only와 server-and-cache write가 섞이면 두 stream을 사용합니다. Cache stream과 server stream을 따로 보내며 server stream에는 cache-only folio 위치에 hole이 생깁니다.

Local cache writeback 분기
folio 상태write destination
`NETFS_FOLIO_COPY_TO_CACHE`cache only
표시 뒤 수정됨표시 clear, 일반 dirty
일반 dirtyserver + 필요 시 cache
혼합 requestcache stream + hole이 있는 server stream

Folio 상태가 destination stream을 결정합니다.

-------------

One of the services netfslib provides, via ``fscache``, is the option to cache
on local disk a copy of the data obtained from/written to a network filesystem.
The library will manage the storing, retrieval and some invalidation of data
automatically on behalf of the filesystem if a cookie is attached to the
``netfs_inode``.

Note that local caching used to use the PG_private_2 (aliased as PG_fscache) to
keep track of a page that was being written to the cache, but this is now
deprecated as PG_private_2 will be removed.

Instead, folios that are read from the server for which there was no data in
the cache will be marked as dirty and will have ``folio->private`` set to a
special value (``NETFS_FOLIO_COPY_TO_CACHE``) and left to writeback to write.
If the folio is modified before that happened, the special value will be
cleared and the write will become normally dirty.

When writeback occurs, folios that are so marked will only be written to the
cache and not to the server.  Writeback handles mixed cache-only writes and
server-and-cache writes by using two streams, sending one to the cache and one
to the server.  The server stream will have gaps in it corresponding to those
folios.

Content Encryption (fscrypt)

향후 client-side content encryption

175-187

현재는 아직 구현하지 않지만 netfslib는 미래에 network filesystem을 대신해 client-side content encryption을 수행할 예정입니다. Ceph 같은 경우 적절하면 `fscrypt`를 사용할 수 있지만 CIFS처럼 적합하지 않은 경우도 있습니다.

Local cache에는 server에 쓰는 데이터와 같은 암호화 방식으로 encrypted data를 저장합니다. Library는 필요에 따라 bounce buffering과 read-modify-write cycle을 적용합니다.

예정된 encryption 경로
filesystem별 fscrypt 적합성 판단client-side content encryption동일 방식으로 server와 cache에 저장필요 시 bounce buffer부분 변경 시 RMW cycle

Server와 local cache가 같은 ciphertext 표현을 사용합니다.

----------------------------

Though it does not do so yet, at some point netfslib will acquire the ability
to do client-side content encryption on behalf of the network filesystem (Ceph,
for example).  fscrypt can be used for this if appropriate (it may not be -
cifs, for example).

The data will be stored encrypted in the local cache using the same manner of
encryption as the data written to the server and the library will impose bounce
buffering and RMW cycles as necessary.


Per-Inode Context

netfs_inode embedding과 상태 flag

188-264

Netfslib는 관리하는 각 netfs inode에 상태를 저장할 공간이 필요해 `struct netfs_inode`를 정의합니다. Network filesystem은 inode wrapper에서 VFS `struct inode` 대신 이 구조체를 포함해야 합니다. 예시 `struct my_inode`는 `struct netfs_inode netfs`를 embedded합니다.

그러면 netfslib가 inode pointer에서 `container_of()`로 상태를 찾을 수 있어 helper를 VFS/VM operation table에 직접 연결할 수 있습니다.

`inode`는 VFS inode, `ops`는 filesystem이 netfslib에 제공하는 operation set입니다. `cache`는 local cache cookie이며 caching이 없거나 fscache가 disabled이면 NULL 또는 field 자체가 없습니다.

`remote_i_size`는 server의 file size입니다. Local modification이 아직 writeback되지 않았으면 `inode->i_size`와 다를 수 있습니다.

`flags` 중 `NETFS_ICTX_MODIFIED_ATTR`은 netfslib가 mtime/ctime을 수정했음을 나타내며 filesystem이 무시하거나 clear할 수 있습니다.

`NETFS_ICTX_UNBUFFERED`는 alignment 제한 없는 direct I/O 유사 unbuffered I/O를 사용합니다. 필요하면 RMW를 하고 mmap도 사용하지 않는 한 page cache를 쓰지 않습니다. `NETFS_ICTX_WRITETHROUGH`는 buffered write가 page cache에 들어갈 때 I/O를 설정·dispatch하며 mmap은 일반 writeback을 사용합니다.

`NETFS_ICTX_SINGLE_NO_UPLOAD`는 AFS directory처럼 content 전체를 한 번에 읽어야 하고 server에는 writeback하면 안 되는 monolithic file을 표시합니다. Local cache에는 저장할 수 있습니다.

`netfs_inode` 공개 상태
항목의미
`ops`filesystem 제공 request operation
`cache`fscache cookie 또는 NULL
`remote_i_size`server가 아는 file size
`UNBUFFERED`alignment 제한 없는 pagecache 비사용 I/O
`WRITETHROUGH`buffered write와 동시에 I/O
`SINGLE_NO_UPLOAD`전체 read, server upload 금지

Filesystem이 직접 해석하는 field와 flag입니다.

=================

The network filesystem helper library needs a place to store a bit of state for
its use on each netfs inode it is helping to manage.  To this end, a context
structure is defined::

        struct netfs_inode {
                struct inode inode;
                const struct netfs_request_ops *ops;
                struct fscache_cookie * cache;
                loff_t remote_i_size;
                unsigned long flags;
                ...
        };

A network filesystem that wants to use netfslib must place one of these in its
inode wrapper struct instead of the VFS ``struct inode``.  This can be done in
a way similar to the following::

        struct my_inode {
                struct netfs_inode netfs; /* Netfslib context and vfs inode */
                ...
        };

This allows netfslib to find its state by using ``container_of()`` from the
inode pointer, thereby allowing the netfslib helper functions to be pointed to
directly by the VFS/VM operation tables.

The structure contains the following fields that are of interest to the
filesystem:

 * ``inode``

   The VFS inode structure.

 * ``ops``

   The set of operations provided by the network filesystem to netfslib.

 * ``cache``

   Local caching cookie, or NULL if no caching is enabled.  This field does not
   exist if fscache is disabled.

 * ``remote_i_size``

   The size of the file on the server.  This differs from inode->i_size if
   local modifications have been made but not yet written back.

 * ``flags``

   A set of flags, some of which the filesystem might be interested in:

   * ``NETFS_ICTX_MODIFIED_ATTR``

     Set if netfslib modifies mtime/ctime.  The filesystem is free to ignore
     this or clear it.

   * ``NETFS_ICTX_UNBUFFERED``

     Do unbuffered I/O upon the file.  Like direct I/O but without the
     alignment limitations.  RMW will be performed if necessary.  The pagecache
     will not be used unless mmap() is also used.

   * ``NETFS_ICTX_WRITETHROUGH``

     Do writethrough caching upon the file.  I/O will be set up and dispatched
     as buffered writes are made to the page cache.  mmap() does the normal
     writeback thing.

   * ``NETFS_ICTX_SINGLE_NO_UPLOAD``

     Set if the file has a monolithic content that must be read entirely in a
     single go and must not be written back to the server, though it can be
     cached (e.g. AFS directories).

Inode Context Helper Functions

Per-inode context helper

265-283

`netfs_inode_init(ctx, ops)`는 context 기본 초기화를 수행하고 operation table pointer를 설정합니다.

`netfs_inode(inode)`는 VFS inode 구조체에서 netfs context로 cast합니다. `netfs_i_cookie(ctx)`는 inode context에 연결된 cache cookie를 반환하며 fscache가 disabled이면 NULL입니다.

Inode context helper
filesystem inode wrapper에 `netfs_inode` embedding`netfs_inode_init()`VFS inode를 `netfs_inode()`로 변환`netfs_i_cookie()`로 cache cookie 조회

Embedding된 context의 초기화와 접근 순서입니다.

------------------------------

To help deal with the per-inode context, a number helper functions are
provided.  Firstly, a function to perform basic initialisation on a context and
set the operations table pointer::

        void netfs_inode_init(struct netfs_inode *ctx,
                              const struct netfs_request_ops *ops);

then a function to cast from the VFS inode structure to the netfs context::

        struct netfs_inode *netfs_inode(struct inode *inode);

and finally, a function to get the cache cookie pointer from the context
attached to an inode (or NULL if fscache is disabled)::

        struct fscache_cookie *netfs_i_cookie(struct netfs_inode *ctx);

Inode Locking

I/O class별 i_rwsem exclusion

284-320

Netfslib는 I/O용 `i_rwsem` locking을 관리하고 더 많은 exclusion class로 사실상 확장하는 `netfs_start_io_read`, `netfs_start_io_write`, `netfs_start_io_direct`와 대응하는 `netfs_end_io_*` 함수를 제공합니다.

Buffered read는 서로 병렬 실행할 수 있고 buffered write와도 병렬입니다. 그러나 buffered write끼리는 동시에 실행할 수 없습니다.

Direct 및 unbuffered read·write는 local buffer인 page cache를 공유하지 않고 network filesystem에서는 server가 exclusion을 관리할 것으로 기대하므로 서로 병렬 실행할 수 있습니다. Ceph 등은 예외일 수 있습니다.

Truncate, fallocate 같은 주요 inode modification은 `i_rwsem`에 직접 접근해야 합니다. mmap access는 다른 모든 class와 병렬일 수 있고 intra-file loopback DIO read/write의 buffer가 될 수도 있으며 unbuffered file에서도 허용될 수 있습니다.

Netfs I/O exclusion class
class동시 실행
buffered read다른 read 및 buffered write와 가능
buffered write다른 buffered write와 불가
direct·unbuffered서로 가능, server exclusion 기대
truncate·fallocate`i_rwsem` 직접 사용
mmap다른 class와 병렬 가능

같은 inode에서 허용되는 concurrency입니다.

-------------

A number of functions are provided to manage the locking of i_rwsem for I/O and
to effectively extend it to provide more separate classes of exclusion::

        int netfs_start_io_read(struct inode *inode);
        void netfs_end_io_read(struct inode *inode);
        int netfs_start_io_write(struct inode *inode);
        void netfs_end_io_write(struct inode *inode);
        int netfs_start_io_direct(struct inode *inode);
        void netfs_end_io_direct(struct inode *inode);

The exclusion breaks down into four separate classes:

 1) Buffered reads and writes.

    Buffered reads can run concurrently each other and with buffered writes,
    but buffered writes cannot run concurrently with each other.

 2) Direct reads and writes.

    Direct (and unbuffered) reads and writes can run concurrently since they do
    not share local buffering (i.e. the pagecache) and, in a network
    filesystem, are expected to have exclusion managed on the server (though
    this may not be the case for, say, Ceph).

 3) Other major inode modifying operations (e.g. truncate, fallocate).

    These should just access i_rwsem directly.

 4) mmap().

    mmap'd accesses might operate concurrently with any of the other classes.
    They might form the buffer for an intra-file loopback DIO read/write.  They
    might be permitted on unbuffered files.

Inode Writeback

Writeback resource pin과 unpin

321-359

Netfslib는 inode가 dirty될 때 fscache cookie 같은 향후 writeback resource를 pin합니다. Cache가 active이면 folio dirty 시 `I_PINNING_NETFS_WB`를 설정하여 cache structure 폐기와 cache space culling을 막고, 이미 설정된 경우 resource를 다시 얻지 않게 합니다.

VM inode writeback 중 inode lock 안에서 flag를 clear하고 설정되어 있었다는 사실을 `struct writeback_control::unpinned_netfs_wb`로 이전합니다. 이 값이 설정되면 `write_inode` procedure를 강제합니다.

Filesystem의 `->write_inode()`가 cleanup을 수행하고 다시 netfs cleanup을 호출합니다. `netfs_unpin_writeback(inode, wbc)`가 resource unpin을 담당하며 다른 작업이 없다면 그대로 `.write_inode` method로 지정할 수 있습니다.

Inode가 삭제되면 filesystem `write_inode`가 호출되지 않을 수 있습니다. 그러므로 `->evict_inode()`에서 `clear_inode()`보다 먼저 `netfs_clear_inode_writeback(inode, aux)`를 반드시 호출해야 합니다.

Writeback pin 수명주기
cache active 상태에서 folio dirty`I_PINNING_NETFS_WB` 설정·resource pinVM writeback에서 flag를 `unpinned_netfs_wb`로 이전`->write_inode()`와 `netfs_unpin_writeback()`삭제 시 `clear_inode()` 전에 별도 clear

Dirty 시점의 pin을 write_inode 또는 eviction에서 확실히 해제합니다.

---------------

Netfslib will pin resources on an inode for future writeback (such as pinning
use of an fscache cookie) when an inode is dirtied.  However, this pinning
needs careful management.  To manage the pinning, the following sequence
occurs:

 1) An inode state flag ``I_PINNING_NETFS_WB`` is set by netfslib when the
    pinning begins (when a folio is dirtied, for example) if the cache is
    active to stop the cache structures from being discarded and the cache
    space from being culled.  This also prevents re-getting of cache resources
    if the flag is already set.

 2) This flag then cleared inside the inode lock during inode writeback in the
    VM - and the fact that it was set is transferred to ``->unpinned_netfs_wb``
    in ``struct writeback_control``.

 3) If ``->unpinned_netfs_wb`` is now set, the write_inode procedure is forced.

 4) The filesystem's ``->write_inode()`` function is invoked to do the cleanup.

 5) The filesystem invokes netfs to do its cleanup.

To do the cleanup, netfslib provides a function to do the resource unpinning::

        int netfs_unpin_writeback(struct inode *inode, struct writeback_control *wbc);

If the filesystem doesn't need to do anything else, this may be set as a its
``.write_inode`` method.

Further, if an inode is deleted, the filesystem's write_inode method may not
get called, so::

        void netfs_clear_inode_writeback(struct inode *inode, const void *aux);

must be called from ``->evict_inode()`` *before* ``clear_inode()`` is called.


High-Level VFS API

Lock을 자체 관리하는 read/write_iter

360-383

Netfslib는 VFS operation을 위임할 고수준 API 묶음을 제공합니다. 내부에서 filesystem·cache를 호출해 I/O 크기를 협상하고 RPC를 issue하며 여러 개입 지점을 제공합니다.

표준 VFS `read_iter`·`write_iter`에 직접 지정할 수 있는 함수는 `netfs_file_read_iter`, `netfs_file_write_iter`, `netfs_buffered_read_iter`, `netfs_unbuffered_read_iter`, `netfs_unbuffered_write_iter`입니다.

이 함수들은 inode locking을 직접 수행합니다. 앞의 두 generic file 함수는 상황에 맞게 buffered I/O와 DIO를 전환합니다.

Unlocked iter API
API역할
`netfs_file_read_iter`buffered·DIO 자동 선택 read
`netfs_file_write_iter`buffered·DIO 자동 선택 write
`netfs_buffered_read_iter`buffered read
`netfs_unbuffered_*_iter`unbuffered read·write

Operation table에 직접 연결할 수 있는 entry point입니다.

==================

Netfslib provides a number of sets of API calls for the filesystem to delegate
VFS operations to.  Netfslib, in turn, will call out to the filesystem and the
cache to negotiate I/O sizes, issue RPCs and provide places for it to intervene
at various times.

Unlocked Read/Write Iter
------------------------

The first API set is for the delegation of operations to netfslib when the
filesystem is called through the standard VFS read/write_iter methods::

        ssize_t netfs_file_read_iter(struct kiocb *iocb, struct iov_iter *iter);
        ssize_t netfs_file_write_iter(struct kiocb *iocb, struct iov_iter *from);
        ssize_t netfs_buffered_read_iter(struct kiocb *iocb, struct iov_iter *iter);
        ssize_t netfs_unbuffered_read_iter(struct kiocb *iocb, struct iov_iter *iter);
        ssize_t netfs_unbuffered_write_iter(struct kiocb *iocb, struct iov_iter *from);

They can be assigned directly to ``.read_iter`` and ``.write_iter``.  They
perform the inode locking themselves and the first two will switch between
buffered I/O and DIO as appropriate.

Pre-Locked Read/Write Iter

Filesystem이 lock을 보유하는 iter API

384-420

Filesystem이 netfslib 호출 전후에 locked section 안에서 Ceph capability 협상 같은 추가 작업을 해야 할 때 pre-locked API를 사용합니다.

`netfs_unbuffered_read_iter_locked()`는 `.read_iter`에 직접 지정하면 안 되며 호출 전에 filesystem이 inode lock을 수행해야 합니다. Buffered read에는 `filemap_read()`를 사용합니다.

Write용 `netfs_buffered_write_iter_locked`, `netfs_perform_write`, `netfs_unbuffered_write_iter_locked`도 `.write_iter`에 직접 지정할 수 없고 filesystem이 먼저 inode를 lock해야 합니다.

앞의 두 함수는 buffered write입니다. 첫 함수는 표준 write check 뒤 둘째 함수로 이동하고, filesystem이 check를 직접 하면 둘째를 바로 쓸 수 있습니다. 셋째는 unbuffered 또는 DIO write입니다.

세 write 함수는 모두 writeback group pointer를 받으며 사용하지 않으면 NULL이어야 합니다. 수정되는 folio에 group을 설정하고, 다른 group이 이미 표시되어 있으면 먼저 flush합니다. Writeback API는 특정 group만 골라 writeback할 수 있습니다.

Pre-locked write
filesystem이 inode lock 획득capability 등 사전 작업locked write helper 호출group 충돌 folio 선행 flush사후 작업 뒤 inode unlock

Filesystem 고유 작업과 netfslib write를 같은 lock 구간에 둡니다.

--------------------------

The second API set is for the delegation of operations to netfslib when the
filesystem is called through the standard VFS methods, but needs to do some
other stuff before or after calling netfslib whilst still inside locked section
(e.g. Ceph negotiating caps).  The unbuffered read function is::

        ssize_t netfs_unbuffered_read_iter_locked(struct kiocb *iocb, struct iov_iter *iter);

This must not be assigned directly to ``.read_iter`` and the filesystem is
responsible for performing the inode locking before calling it.  In the case of
buffered read, the filesystem should use ``filemap_read()``.

There are three functions for writes::

        ssize_t netfs_buffered_write_iter_locked(struct kiocb *iocb, struct iov_iter *from,
                                                 struct netfs_group *netfs_group);
        ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter,
                                    struct netfs_group *netfs_group);
        ssize_t netfs_unbuffered_write_iter_locked(struct kiocb *iocb, struct iov_iter *iter,
                                                   struct netfs_group *netfs_group);

These must not be assigned directly to ``.write_iter`` and the filesystem is
responsible for performing the inode locking before calling them.

The first two functions are for buffered writes; the first just adds some
standard write checks and jumps to the second, but if the filesystem wants to
do the checks itself, it can use the second directly.  The third function is
for unbuffered or DIO writes.

On all three write functions, there is a writeback group pointer (which should
be NULL if the filesystem doesn't use this).  Writeback groups are set on
folios when they're modified.  If a folio to-be-modified is already marked with
a different group, it is flushed first.  The writeback API allows writing back
of a specific group.

Memory-Mapped I/O API

mmap page_mkwrite와 monolithic file

421-454

`netfs_page_mkwrite(vmf, netfs_group)`는 filesystem이 `.page_mkwrite`를 netfslib에 위임하도록 합니다. 호출 전에 inode lock을 잡으면 안 됩니다. Locked write 함수처럼 writeback group을 받고 writeable로 만들 page가 다른 group이면 먼저 flush합니다.

Content를 RPC 한 번에 전부 읽고 server에는 writeback하지 않는 monolithic blob용 API도 있습니다. AFS directory가 예이며 local cache에는 저장·갱신할 수 있습니다.

`netfs_read_single`은 cache data가 있으면 우선 사용해 file을 buffer로 읽습니다. `netfs_single_mark_inode_dirty`는 이후 writeback을 유발하도록 inode를 dirty로 표시하고 `netfs_writeback_single`은 writeback code에서 data를 cache에 씁니다.

이 API를 쓰는 inode에는 `NETFS_ICTX_SINGLE_NO_UPLOAD`를 설정해야 합니다. Writeback 함수의 buffer는 `ITER_FOLIOQ` type이어야 합니다.

특수 VFS API
API핵심 조건
`netfs_page_mkwrite`사전 inode lock 금지, group 충돌 flush
`netfs_read_single`cache 우선, 전체 object read
`netfs_writeback_single`cache에만 write, `ITER_FOLIOQ`
monolithic inode`SINGLE_NO_UPLOAD` 설정

Memory-mapped write와 monolithic object의 서로 다른 계약입니다.

---------------------

An API for support of mmap()'d I/O is provided::

        vm_fault_t netfs_page_mkwrite(struct vm_fault *vmf, struct netfs_group *netfs_group);

This allows the filesystem to delegate ``.page_mkwrite`` to netfslib.  The
filesystem should not take the inode lock before calling it, but, as with the
locked write functions above, this does take a writeback group pointer.  If the
page to be made writable is in a different group, it will be flushed first.

Monolithic Files API
--------------------

There is also a special API set for files for which the content must be read in
a single RPC (and not written back) and is maintained as a monolithic blob
(e.g. an AFS directory), though it can be stored and updated in the local cache::

        ssize_t netfs_read_single(struct inode *inode, struct file *file, struct iov_iter *iter);
        void netfs_single_mark_inode_dirty(struct inode *inode);
        int netfs_writeback_single(struct address_space *mapping,
                                   struct writeback_control *wbc,
                                   struct iov_iter *iter);

The first function reads from a file into the given buffer, reading from the
cache in preference if the data is cached there; the second function allows the
inode to be marked dirty, causing a later writeback; and the third function can
be called from the writeback code to write the data to the cache, if there is
one.

The inode should be marked ``NETFS_ICTX_SINGLE_NO_UPLOAD`` if this API is to be
used.  The writeback function requires the buffer to be of ITER_FOLIOQ type.

High-Level VM API

High-level VM API와 deprecated PG_private_2

455-486

VM operation을 위임하는 함수는 `netfs_readahead`, `netfs_read_folio`, `netfs_writepages`, `netfs_dirty_folio`, `netfs_invalidate_folio`, `netfs_release_folio`입니다. 모두 `address_space_operations` method이므로 operation table에 직접 설정할 수 있습니다.

아직 `->write_begin`을 쓰는 파일시스템을 위한 `netfs_write_begin`도 있지만 deprecated `PG_private_2` flag를 사용하므로 새 코드에서 사용하면 안 됩니다.

VM delegation API
상태API
current`netfs_readahead`, `netfs_read_folio`, `netfs_writepages`
current`netfs_dirty_folio`, invalidate·release helper
deprecated`netfs_write_begin` (`PG_private_2`)

직접 연결 가능한 current helper와 폐기 예정 helper를 구분합니다.

==================

Netfslib also provides a number of sets of API calls for the filesystem to
delegate VM operations to.  Again, netfslib, in turn, will call out to the
filesystem and the cache to negotiate I/O sizes, issue RPCs and provide places
for it to intervene at various times::

        void netfs_readahead(struct readahead_control *);
        int netfs_read_folio(struct file *, struct folio *);
        int netfs_writepages(struct address_space *mapping,
                             struct writeback_control *wbc);
        bool netfs_dirty_folio(struct address_space *mapping, struct folio *folio);
        void netfs_invalidate_folio(struct folio *folio, size_t offset, size_t length);
        bool netfs_release_folio(struct folio *folio, gfp_t gfp);

These are ``address_space_operations`` methods and can be set directly in the
operations table.

Deprecated PG_private_2 API
---------------------------

There is also a deprecated function for filesystems that still use the
``->write_begin`` method::

        int netfs_write_begin(struct netfs_inode *inode, struct file *file,
                              struct address_space *mapping, loff_t pos, unsigned int len,
                              struct folio **_folio, void **_fsdata);

It uses the deprecated PG_private_2 flag and so should not be used.


I/O Request API

netfs_io_request field와 request flag

487-589

`struct netfs_io_request`는 request 전체를 관리하며 filesystem을 대신해 resource·state를 보유하고 결과 collection을 추적합니다.

`origin`은 readahead, read_folio, DIO read, writeback 등 request 기원을 나타냅니다. `inode`와 `mapping`은 읽는 file의 inode와 address space이며 mapping이 `inode->i_data`일 수도 아닐 수도 있습니다.

`group`은 이 request가 다루는 writeback group 또는 NULL이며 group reference를 보유합니다. `io_streams`는 parallel subrequest stream array입니다. 현재 두 개이고 `NR_IO_STREAMS`가 array size를 나타내며 미래에 확장될 수 있습니다.

`netfs_priv`와 `netfs_priv2`는 network filesystem private data입니다. Helper 인수로 전달하거나 request 진행 중 설정할 수 있습니다.

`start`와 `len`은 read request 시작 file position과 길이이며 `->expand_readahead()`가 바꿀 수 있습니다. `i_size`는 request 시작 시 file size이고 `debug_id`는 trace line에 표시하는 operation 번호입니다.

`NETFS_RREQ_RETRYING`은 retry 생성 중 library가 설정합니다. `NETFS_RREQ_PAUSE`는 filesystem이 subrequest issue loop 일시 정지를 요청할 때 설정할 수 있지만 netfslib도 설정할 수 있어 주의해야 합니다.

`NETFS_RREQ_NONBLOCK`은 caller가 nonblocking mode를 설정했음을 library가 표시하고, filesystem은 block해야 했음을 `NETFS_RREQ_BLOCKED`로 표시할 수 있습니다.

`NETFS_RREQ_USE_PGPRIV2`는 cache write 중 folio 추적에 `PG_private_2`를 쓰려는 filesystem용이지만 해당 flag 제거 예정으로 deprecated입니다. 더 많은 private data가 필요하면 request 구조체를 감싸고 자체 allocator를 제공해야 합니다.

Request control flag
flag설정 주체·의미
`RETRYING`netfslib: retry 생성 중
`PAUSE`양쪽: issue loop 일시 정지
`NONBLOCK`netfslib: caller nonblocking
`BLOCKED`filesystem: 실행하려면 block 필요
`USE_PGPRIV2`filesystem: deprecated cache 추적

Library와 filesystem이 각각 설정하는 상태입니다.

===============

The I/O request API comprises a number of structures and a number of functions
that the filesystem may need to use.

Request Structure
-----------------

The request structure manages the request as a whole, holding some resources
and state on behalf of the filesystem and tracking the collection of results::

        struct netfs_io_request {
                enum netfs_io_origin        origin;
                struct inode                *inode;
                struct address_space        *mapping;
                struct netfs_group        *group;
                struct netfs_io_stream        io_streams[];
                void                        *netfs_priv;
                void                        *netfs_priv2;
                unsigned long long        start;
                unsigned long long        len;
                unsigned long long        i_size;
                unsigned int                debug_id;
                unsigned long                flags;
                ...
        };

Many of the fields are for internal use, but the fields shown here are of
interest to the filesystem:

 * ``origin``

   The origin of the request (readahead, read_folio, DIO read, writeback, ...).

 * ``inode``
 * ``mapping``

   The inode and the address space of the file being read from.  The mapping
   may or may not point to inode->i_data.

 * ``group``

   The writeback group this request is dealing with or NULL.  This holds a ref
   on the group.

 * ``io_streams``

   The parallel streams of subrequests available to the request.  Currently two
   are available, but this may be made extensible in future.  ``NR_IO_STREAMS``
   indicates the size of the array.

 * ``netfs_priv``
 * ``netfs_priv2``

   The network filesystem's private data.  The value for this can be passed in
   to the helper functions or set during the request.

 * ``start``
 * ``len``

   The file position of the start of the read request and the length.  These
   may be altered by the ->expand_readahead() op.

 * ``i_size``

   The size of the file at the start of the request.

 * ``debug_id``

   A number allocated to this operation that can be displayed in trace lines
   for reference.

 * ``flags``

   Flags for managing and controlling the operation of the request.  Some of
   these may be of interest to the filesystem:

   * ``NETFS_RREQ_RETRYING``

     Netfslib sets this when generating retries.

   * ``NETFS_RREQ_PAUSE``

     The filesystem can set this to request to pause the library's subrequest
     issuing loop - but care needs to be taken as netfslib may also set it.

   * ``NETFS_RREQ_NONBLOCK``
   * ``NETFS_RREQ_BLOCKED``

     Netfslib sets the first to indicate that non-blocking mode was set by the
     caller and the filesystem can set the second to indicate that it would
     have had to block.

   * ``NETFS_RREQ_USE_PGPRIV2``

     The filesystem can set this if it wants to use PG_private_2 to track
     whether a folio is being written to the cache.  This is deprecated as
     PG_private_2 is going to go away.

If the filesystem wants more private data than is afforded by this structure,
then it should wrap it and provide its own allocator.

Stream Structure

netfs_io_stream field와 EOF 확장

590-638

Request는 destination이 서로 다른 `struct netfs_io_stream` 하나 이상으로 구성됩니다. Read request는 stream 0만 사용하며 source가 다른 subrequest를 섞을 수 있습니다. Write request는 stream 0이 server, stream 1이 cache용입니다.

Buffered writeback에서 일반 dirty folio를 만나기 전에는 stream 0을 활성화하지 않습니다. 발견 시 `->begin_writeback()`을 호출하고 filesystem이 stream을 available로 표시할 수 있습니다.

`stream_nr`는 request 안 stream 번호이고 `avail`은 사용 가능 여부입니다. `->begin_writeback()` 안에서 filesystem이 stream 0의 `avail`을 설정해야 합니다.

`sreq_max_len`과 `sreq_max_segs`는 `->prepare_read()` 또는 `->prepare_write()`가 각 subrequest의 최대 byte 수와 optional 최대 segment 수를 설정합니다. Segment 값 0은 제한이 없다는 뜻입니다.

`submit_extendable_to`는 available buffer가 허용하는 범위에서 EOF 너머로 subrequest를 round up할 수 있는 크기입니다. Cache가 EOF marker를 가로지르는 DIO read·write 가능 여부를 판단할 수 있게 합니다.

Stream 번호와 destination
streamreadwrite
0혼합 source readserver
1미사용local cache
`avail`read 설정에 따름`begin_writeback`에서 server 활성화

Read와 write에서 고정적으로 사용하는 stream입니다.

----------------

A request is comprised of one or more parallel streams and each stream may be
aimed at a different target.

For read requests, only stream 0 is used.  This can contain a mixture of
subrequests aimed at different sources.  For write requests, stream 0 is used
for the server and stream 1 is used for the cache.  For buffered writeback,
stream 0 is not enabled unless a normal dirty folio is encountered, at which
point ->begin_writeback() will be invoked and the filesystem can mark the
stream available.

The stream struct looks like::

        struct netfs_io_stream {
                unsigned char                stream_nr;
                bool                        avail;
                size_t                        sreq_max_len;
                unsigned int                sreq_max_segs;
                unsigned int                submit_extendable_to;
                ...
        };

A number of members are available for access/use by the filesystem:

 * ``stream_nr``

   The number of the stream within the request.

 * ``avail``

   True if the stream is available for use.  The filesystem should set this on
   stream zero if in ->begin_writeback().

 * ``sreq_max_len``
 * ``sreq_max_segs``

   These are set by the filesystem or the cache in ->prepare_read() or
   ->prepare_write() for each subrequest to indicate the maximum number of
   bytes and, optionally, the maximum number of segments (if not 0) that that
   subrequest can support.

 * ``submit_extendable_to``

   The size that a subrequest can be rounded up to beyond the EOF, given the
   available buffer.  This allows the cache to work out if it can do a DIO read
   or write that straddles the EOF marker.

Subrequest Structure

netfs_io_subrequest 진행·경계 flag

639-738

`struct netfs_io_subrequest`는 전체 request의 slice인 독립 I/O 단위를 관리합니다. 하나의 source만 접근하는 것이 원칙이지만 library가 source type fallback을 처리합니다.

`rreq`는 parent request pointer이고 `io_iter`는 읽을 또는 쓸 buffer slice의 I/O iterator입니다. `start`와 `len`은 slice의 시작 file position과 길이입니다.

`transferred`는 현재까지 전송한 양입니다. 각 issue에서 전송한 길이를 누적해야 하며 `len`보다 작으면 계속하기 위해 재issue할 수 있습니다.

`NETFS_SREQ_MADE_PROGRESS`는 한 byte 이상 읽거나 썼음을 filesystem이 표시합니다. `NETFS_SREQ_HIT_EOF`는 read가 EOF에 도달했음을 나타내며 `transferred`는 EOF에서 멈춰야 합니다. Library는 third-party change나 긴 DIO request 가능성 때문에 EOF folio 크기까지 subrequest를 확장할 수 있고 초과 page cache를 clear합니다.

`NETFS_SREQ_CLEAR_TAIL`은 `transferred`부터 `len`까지 남은 slice를 clear하도록 지시합니다. `HIT_EOF`와 동시에 설정하면 안 됩니다. `NETFS_SREQ_NEED_RETRY`는 retry 요청입니다.

`NETFS_SREQ_BOUNDARY`는 Ceph object 끝처럼 filesystem structure 경계에서 subrequest가 끝남을 나타냅니다. Netfslib는 이 경계를 넘어 retile하지 않습니다.

`error`는 성공 시 0, 실패 시 negative error code입니다. `debug_index`는 trace용 slice 번호이고 `stream_nr`는 소속 request stream 번호입니다.

필요하면 `netfs_get_subrequest`와 `netfs_put_subrequest`로 추가 reference를 관리하고 trace code로 이유를 표시할 수 있습니다. 제어권을 library에 돌려준 뒤 같은 subrequest가 reissue·retry될 수 있으므로 보관한 reference 사용에 주의해야 합니다.

Subrequest flag 규칙
flag계약
`MADE_PROGRESS`최소 1 byte 전송
`HIT_EOF``transferred`가 EOF에서 종료
`CLEAR_TAIL`남은 slice zero, `HIT_EOF`와 동시 금지
`NEED_RETRY`subrequest retry 요청
`BOUNDARY`이 지점을 넘어 retile 금지

진행·EOF·tail·retry·구조 경계를 구분합니다.

--------------------

Individual units of I/O are managed by the subrequest structure.  These
represent slices of the overall request and run independently::

        struct netfs_io_subrequest {
                struct netfs_io_request *rreq;
                struct iov_iter                io_iter;
                unsigned long long        start;
                size_t                        len;
                size_t                        transferred;
                unsigned long                flags;
                short                        error;
                unsigned short                debug_index;
                unsigned char                stream_nr;
                ...
        };

Each subrequest is expected to access a single source, though the library will
handle falling back from one source type to another.  The members are:

 * ``rreq``

   A pointer to the read request.

 * ``io_iter``

   An I/O iterator representing a slice of the buffer to be read into or
   written from.

 * ``start``
 * ``len``

   The file position of the start of this slice of the read request and the
   length.

 * ``transferred``

   The amount of data transferred so far for this subrequest.  This should be
   added to with the length of the transfer made by this issuance of the
   subrequest.  If this is less than ``len`` then the subrequest may be
   reissued to continue.

 * ``flags``

   Flags for managing the subrequest.  There are a number of interest to the
   filesystem or cache:

   * ``NETFS_SREQ_MADE_PROGRESS``

     Set by the filesystem to indicates that at least one byte of data was read
     or written.

   * ``NETFS_SREQ_HIT_EOF``

     The filesystem should set this if a read hit the EOF on the file (in which
     case ``transferred`` should stop at the EOF).  Netfslib may expand the
     subrequest out to the size of the folio containing the EOF on the off
     chance that a third party change happened or a DIO read may have asked for
     more than is available.  The library will clear any excess pagecache.

   * ``NETFS_SREQ_CLEAR_TAIL``

     The filesystem can set this to indicate that the remainder of the slice,
     from transferred to len, should be cleared.  Do not set if HIT_EOF is set.

   * ``NETFS_SREQ_NEED_RETRY``

     The filesystem can set this to tell netfslib to retry the subrequest.

   * ``NETFS_SREQ_BOUNDARY``

     This can be set by the filesystem on a subrequest to indicate that it ends
     at a boundary with the filesystem structure (e.g. at the end of a Ceph
     object).  It tells netfslib not to retile subrequests across it.

 * ``error``

   This is for the filesystem to store result of the subrequest.  It should be
   set to 0 if successful and a negative error code otherwise.

 * ``debug_index``
 * ``stream_nr``

   A number allocated to this slice that can be displayed in trace lines for
   reference and the number of the request stream that it belongs to.

If necessary, the filesystem can get and put extra refs on the subrequest it is
given::

        void netfs_get_subrequest(struct netfs_io_subrequest *subreq,
                                  enum netfs_sreq_ref_trace what);
        void netfs_put_subrequest(struct netfs_io_subrequest *subreq,
                                  enum netfs_sreq_ref_trace what);

using netfs trace codes to indicate the reason.  Care must be taken, however,
as once control of the subrequest is returned to netfslib, the same subrequest
can be reissued/retried.

Filesystem Methods

Request pool·초기화·readahead·prepare_read

739-804

Filesystem은 `netfs_inode`에 `struct netfs_request_ops` table을 설정합니다. 첫 두 pointer `request_pool`, `subrequest_pool`은 optional mempool입니다. 없으면 netfslib default pool을 쓰며 filesystem이 netfs 구조체를 더 큰 자체 구조체로 감싸면 자체 pool이 필요합니다. Library가 pool에서 직접 할당합니다.

Optional `init_request`, `free_request`, `free_subrequest`는 request·subrequest에 연결한 filesystem resource를 초기화하거나 정리합니다.

Optional `expand_readahead()`는 readahead request를 양방향으로 확장합니다. 이미 할당된 영역일 수 있는 초기 region은 반드시 유지해야 합니다. Local caching이 enabled이면 cache가 먼저 확장합니다.

확장은 request의 `->start`, `->len`을 변경해 알립니다. Start를 줄였다면 len을 최소한 같은 양 이상 늘려야 합니다.

Optional `prepare_read()`는 subrequest size와 RDMA 같은 iterator region 수를 제한합니다. 값을 stream 0의 `sreq_max_len`, `sreq_max_segs`에 설정합니다. 여러 server로 분할하거나 여러 read를 in-flight하기 위해 request를 자를 수 있습니다. 성공 시 0, 실패 시 error code입니다.

Read request 준비
request·subrequest pool 할당cache가 readahead 범위 우선 확장filesystem `expand_readahead()``prepare_read()`가 stream 0 제한 설정server read subrequest 생성

Cache와 filesystem이 순서대로 범위와 slice 제한을 조정합니다.

------------------

The filesystem sets a table of operations in ``netfs_inode`` for netfslib to
use::

        struct netfs_request_ops {
                mempool_t *request_pool;
                mempool_t *subrequest_pool;
                int (*init_request)(struct netfs_io_request *rreq, struct file *file);
                void (*free_request)(struct netfs_io_request *rreq);
                void (*free_subrequest)(struct netfs_io_subrequest *rreq);
                void (*expand_readahead)(struct netfs_io_request *rreq);
                int (*prepare_read)(struct netfs_io_subrequest *subreq);
                void (*issue_read)(struct netfs_io_subrequest *subreq);
                void (*done)(struct netfs_io_request *rreq);
                void (*update_i_size)(struct inode *inode, loff_t i_size);
                void (*post_modify)(struct inode *inode);
                void (*begin_writeback)(struct netfs_io_request *wreq);
                void (*prepare_write)(struct netfs_io_subrequest *subreq);
                void (*issue_write)(struct netfs_io_subrequest *subreq);
                void (*retry_request)(struct netfs_io_request *wreq,
                                      struct netfs_io_stream *stream);
                void (*invalidate_cache)(struct netfs_io_request *wreq);
        };

The table starts with a pair of optional pointers to memory pools from which
requests and subrequests can be allocated.  If these are not given, netfslib
has default pools that it will use instead.  If the filesystem wraps the netfs
structs in its own larger structs, then it will need to use its own pools.
Netfslib will allocate directly from the pools.

The methods defined in the table are:

 * ``init_request()``
 * ``free_request()``
 * ``free_subrequest()``

   [Optional] A filesystem may implement these to initialise or clean up any
   resources that it attaches to the request or subrequest.

 * ``expand_readahead()``

   [Optional] This is called to allow the filesystem to expand the size of a
   readahead request.  The filesystem gets to expand the request in both
   directions, though it must retain the initial region as that may represent
   an allocation already made.  If local caching is enabled, it gets to expand
   the request first.

   Expansion is communicated by changing ->start and ->len in the request
   structure.  Note that if any change is made, ->len must be increased by at
   least as much as ->start is reduced.

 * ``prepare_read()``

   [Optional] This is called to allow the filesystem to limit the size of a
   subrequest.  It may also limit the number of individual regions in iterator,
   such as required by RDMA.  This information should be set on stream zero in::

        rreq->io_streams[0].sreq_max_len
        rreq->io_streams[0].sreq_max_segs

   The filesystem can use this, for example, to chop up a request that has to
   be split across multiple servers or to put multiple reads in flight.

   Zero should be returned on success and an error code otherwise.

issue_read와 writeback 시작 hook

805-846

Required `issue_read()`는 subrequest를 server read로 dispatch합니다. `->start`, `->len`, `->transferred`가 읽을 data 범위를, `->io_iter`가 buffer를 나타냅니다.

반환값은 없습니다. 성공·실패 어느 경우든 `netfs_read_subreq_terminated()`를 호출해야 하고 먼저 `->error`, `->transferred`, `->flags`를 갱신해야 합니다. 비동기 termination도 가능합니다.

Filesystem은 folio uptodate 설정, unlock, reference drop을 처리하면 안 됩니다. 서로 다른 subrequest가 같은 folio 집합을 겹쳐 다룰 수 있어 library가 결과를 이어 붙인 뒤 처리합니다.

Optional `done()`은 read request의 모든 folio가 unlock되고 해당하면 uptodate 표시된 뒤 호출됩니다.

Optional `update_i_size()`는 write path 여러 지점에서 filesystem의 file size 인식을 갱신하라고 요청합니다. 없으면 netfslib가 `i_size`, `i_blocks`, local cache cookie를 갱신합니다. Optional `post_modify()`는 page cache write 뒤 또는 mmap page를 writeable로 허용한 뒤 호출됩니다.

Optional `begin_writeback()`은 cache-copy 표시만 있는 것이 아닌 일반 dirty page를 발견해 server write가 필요할 때 호출됩니다. 실제 write가 필요하다는 사실을 안 뒤에만 filesystem이 writeback resource를 설정할 수 있게 합니다.

`issue_read()` 완료 책임
filesystem이 RPC dispatcherror·transferred·flags 갱신`netfs_read_subreq_terminated()`netfslib가 결과 stitch·uptodate·unlock모든 folio 뒤 optional `done()`

Filesystem과 library의 folio 책임을 분리합니다.

 * ``issue_read()``

   [Required] Netfslib calls this to dispatch a subrequest to the server for
   reading.  In the subrequest, ->start, ->len and ->transferred indicate what
   data should be read from the server and ->io_iter indicates the buffer to be
   used.

   There is no return value; the ``netfs_read_subreq_terminated()`` function
   should be called to indicate that the subrequest completed either way.
   ->error, ->transferred and ->flags should be updated before completing.  The
   termination can be done asynchronously.

   Note: the filesystem must not deal with setting folios uptodate, unlocking
   them or dropping their refs - the library deals with this as it may have to
   stitch together the results of multiple subrequests that variously overlap
   the set of folios.

 * ``done()``

   [Optional] This is called after the folios in a read request have all been
   unlocked (and marked uptodate if applicable).

 * ``update_i_size()``

   [Optional] This is invoked by netfslib at various points during the write
   paths to ask the filesystem to update its idea of the file size.  If not
   given, netfslib will set i_size and i_blocks and update the local cache
   cookie.
   
 * ``post_modify()``

   [Optional] This is called after netfslib writes to the pagecache or when it
   allows an mmap'd page to be marked as writable.
   
 * ``begin_writeback()``

   [Optional] Netfslib calls this when processing a writeback request if it
   finds a dirty page that isn't simply marked NETFS_FOLIO_COPY_TO_CACHE,
   indicating it must be written to the server.  This allows the filesystem to
   only set up writeback resources when it knows it's going to have to perform
   a write.
   

prepare_write·issue_write·retry·cache invalidation

847-892

Optional `prepare_write()`는 subrequest 크기와 RDMA 등에 필요한 iterator region 수를 제한하고 소속 stream의 `sreq_max_len`, `sreq_max_segs`에 설정합니다. 여러 server로 분할하거나 여러 write를 in-flight하는 데 사용할 수 있습니다.

이 callback은 error를 반환할 수 없습니다. 실패하면 `netfs_prepare_write_failed()`를 호출해야 합니다.

Required `issue_write()`는 server write를 dispatch합니다. `start`, `len`, `transferred`가 data 범위이고 `io_iter`가 buffer입니다. 반환값은 없으며 완료 전 field를 갱신한 뒤 `netfs_write_subreq_terminated()`를 호출합니다. 비동기 종료도 가능합니다.

Filesystem은 관련 folio의 dirty·writeback mark를 제거하거나 reference·pin을 잡으면 안 되고 보존 책임을 netfslib에 맡깁니다.

Optional `retry_request()`는 retry cycle 시작 시 호출되어 request, 지정 stream의 subrequest, filesystem private state를 검사하고 resource를 조정·재협상하게 합니다.

Optional `invalidate_cache()`는 local cache write가 실패했을 때 netfslib가 cache data를 invalidate하고 netfs가 제공할 수 없는 최신 coherency data를 filesystem이 제공하도록 호출합니다.

Write callback 실패·완료 규칙
callback실패·완료 전달
`prepare_write`반환 error 금지, `netfs_prepare_write_failed()`
`issue_write`반환값 없음, termination helper 필수
`retry_request`retry 전 resource 재협상
`invalidate_cache`cache write 실패 후 coherency 갱신

반환값 대신 termination helper를 호출하는 계약입니다.

 * ``prepare_write()``

   [Optional] This is called to allow the filesystem to limit the size of a
   subrequest.  It may also limit the number of individual regions in iterator,
   such as required by RDMA.  This information should be set on stream to which
   the subrequest belongs::

        rreq->io_streams[subreq->stream_nr].sreq_max_len
        rreq->io_streams[subreq->stream_nr].sreq_max_segs

   The filesystem can use this, for example, to chop up a request that has to
   be split across multiple servers or to put multiple writes in flight.

   This is not permitted to return an error.  Instead, in the event of failure,
   ``netfs_prepare_write_failed()`` must be called.

 * ``issue_write()``

   [Required] This is used to dispatch a subrequest to the server for writing.
   In the subrequest, ->start, ->len and ->transferred indicate what data
   should be written to the server and ->io_iter indicates the buffer to be
   used.

   There is no return value; the ``netfs_write_subreq_terminated()`` function
   should be called to indicate that the subrequest completed either way.
   ->error, ->transferred and ->flags should be updated before completing.  The
   termination can be done asynchronously.

   Note: the filesystem must not deal with removing the dirty or writeback
   marks on folios involved in the operation and should not take refs or pins
   on them, but should leave retention to netfslib.

 * ``retry_request()``

   [Optional] Netfslib calls this at the beginning of a retry cycle.  This
   allows the filesystem to examine the state of the request, the subrequests
   in the indicated stream and of its own data and make adjustments or
   renegotiate resources.
   
 * ``invalidate_cache()``

   [Optional] This is called by netfslib to invalidate data stored in the local
   cache in the event that writing to the local cache fails, providing updated
   coherency data that netfs can't provide.

Terminating a subrequest

Subrequest 종료와 중간 진행 통지

893-928

Subrequest 상태가 바뀌면 cache 또는 filesystem이 termination helper로 netfslib에 알립니다.

`netfs_prepare_write_failed(subreq)`는 issue 전 prepare 단계 write 실패를 동기적으로 알리며 `error` field를 먼저 갱신해야 합니다. `prepare_read()`는 단순 abort할 수 있어 error를 반환하지만 writeback failure 처리는 더 복잡합니다.

Issue된 read는 `netfs_read_subreq_terminated(subreq)`로 종료하며 `error`, `flags`, `transferred`를 미리 갱신합니다.

`netfs_write_subrequest_terminated(_op, transferred_or_error)`는 처리 byte 수 또는 negative error를 받아 write 종료를 알리고 `kiocb` completion function으로도 사용할 수 있습니다.

`netfs_read_subreq_progress(subreq)`는 read의 incremental progress를 선택적으로 알려 일부 folio를 조기에 unlock하게 하지만 subrequest를 종료하지는 않습니다. `transferred`를 먼저 갱신해야 합니다.

Termination helper
helper의미
`netfs_prepare_write_failed`issue 전 synchronous write 실패
`netfs_read_subreq_terminated`read 종료
`netfs_write_subrequest_terminated`write byte 수 또는 error
`netfs_read_subreq_progress`종료 없이 진행량 통지

준비 실패, 발행 후 종료, 중간 진행을 구분합니다.

------------------------

When a subrequest completes, there are a number of functions that the cache or
subrequest can call to inform netfslib of the status change.  One function is
provided to terminate a write subrequest at the preparation stage and acts
synchronously:

 * ``void netfs_prepare_write_failed(struct netfs_io_subrequest *subreq);``

   Indicate that the ->prepare_write() call failed.  The ``error`` field should
   have been updated.

Note that ->prepare_read() can return an error as a read can simply be aborted.
Dealing with writeback failure is trickier.

The other functions are used for subrequests that got as far as being issued:

 * ``void netfs_read_subreq_terminated(struct netfs_io_subrequest *subreq);``

   Tell netfslib that a read subrequest has terminated.  The ``error``,
   ``flags`` and ``transferred`` fields should have been updated.

 * ``void netfs_write_subrequest_terminated(void *_op, ssize_t transferred_or_error);``

   Tell netfslib that a write subrequest has terminated.  Either the amount of
   data processed or the negative error code can be passed in.  This is
   can be used as a kiocb completion function.

 * ``void netfs_read_subreq_progress(struct netfs_io_subrequest *subreq);``

   This is provided to optionally update netfslib on the incremental progress
   of a read, allowing some folios to be unlocked early and does not actually
   terminate the subrequest.  The ``transferred`` field should have been
   updated.

Local Cache API

Local cache resource와 operation table

929-975

Netfslib는 filesystem request API와 유사하지만 별도인 local cache 구현 API를 제공합니다.

`struct netfs_cache_resources`는 cache operation table `ops`, private pointer 두 개, tracing용 fscache cookie `debug_id`, invalidation counter를 보유합니다. `fscache_invalidate()`가 counter를 증가시켜 완료 뒤 cache subrequest도 invalid로 판정할 수 있게 합니다.

`struct netfs_cache_ops`는 `end_operation`, `expand_readahead`, `prepare_read`, `read`, `prepare_write_subreq`, `issue_write` callback을 제공합니다.

Cache read의 termination callback type `netfs_io_terminated_t`는 private pointer, 전송 byte 또는 error, caller context에서 확실히 종료되는지를 나타내는 `was_async` flag를 받습니다.

Cache resource state
필드역할
`ops`cache operation table
`cache_priv`·`cache_priv2`cache private data
`debug_id`fscache cookie trace ID
`inval_counter`완료 후 stale subrequest 판정

Request에 연결되는 cache-private 정보입니다.

---------------

Netfslib provides a separate API for a local cache to implement, though it
provides some somewhat similar routines to the filesystem request API.

Firstly, the netfs_io_request object contains a place for the cache to hang its
state::

        struct netfs_cache_resources {
                const struct netfs_cache_ops        *ops;
                void                                *cache_priv;
                void                                *cache_priv2;
                unsigned int                        debug_id;
                unsigned int                        inval_counter;
        };

This contains an operations table pointer and two private pointers plus the
debug ID of the fscache cookie for tracing purposes and an invalidation counter
that is cranked by calls to ``fscache_invalidate()`` allowing cache subrequests
to be invalidated after completion.

The cache operation table looks like the following::

        struct netfs_cache_ops {
                void (*end_operation)(struct netfs_cache_resources *cres);
                void (*expand_readahead)(struct netfs_cache_resources *cres,
                                         loff_t *_start, size_t *_len, loff_t i_size);
                enum netfs_io_source (*prepare_read)(struct netfs_io_subrequest *subreq,
                                                     loff_t i_size);
                int (*read)(struct netfs_cache_resources *cres,
                            loff_t start_pos,
                            struct iov_iter *iter,
                            bool seek_data,
                            netfs_io_terminated_t term_func,
                            void *term_func_priv);
                void (*prepare_write_subreq)(struct netfs_io_subrequest *subreq);
                void (*issue_write)(struct netfs_io_subrequest *subreq);
        };

With a termination handler function pointer::

        typedef void (*netfs_io_terminated_t)(void *priv,
                                              ssize_t transferred_or_error,
                                              bool was_async);

The methods defined in the table are:

Cache operation 종료·확장·read source 선택

976-1004

Required `end_operation()`은 read request 끝에서 cache resource를 정리합니다.

Optional `expand_readahead()`는 readahead 시작 시 cache granularity에 맞도록 request를 양방향 확장합니다.

Required `prepare_read()`는 다음 request slice를 설정합니다. Subrequest의 `start`, `len`이 가능한 위치와 크기를 나타내며 cache가 granularity에 맞게 길이를 줄일 수 있습니다. File size도 참고 인수로 받습니다.

반환값 `NETFS_FILL_WITH_ZEROES`, `NETFS_DOWNLOAD_FROM_SERVER`, `NETFS_READ_FROM_CACHE`, `NETFS_INVALID_READ`는 slice를 zero-fill할지, server에서 받을지, cache에서 읽을지, 현재 위치의 slicing을 포기할지 나타냅니다.

Cache read source 선택
subrequest start·len 후보cache granularity에 맞게 축소zero-fill / server download / cache read 선택유효하지 않으면 현재 slicing 중단request 종료 시 `end_operation()`

Cache granularity와 보유 data에 따라 slice 처리 방식을 결정합니다.

 * ``end_operation()``

   [Required] Called to clean up the resources at the end of the read request.

 * ``expand_readahead()``

   [Optional] Called at the beginning of a readahead operation to allow the
   cache to expand a request in either direction.  This allows the cache to
   size the request appropriately for the cache granularity.

 * ``prepare_read()``

   [Required] Called to configure the next slice of a request.  ->start and
   ->len in the subrequest indicate where and how big the next slice can be;
   the cache gets to reduce the length to match its granularity requirements.

   The function is passed pointers to the start and length in its parameters,
   plus the size of the file for reference, and adjusts the start and length
   appropriately.  It should return one of:

   * ``NETFS_FILL_WITH_ZEROES``
   * ``NETFS_DOWNLOAD_FROM_SERVER``
   * ``NETFS_READ_FROM_CACHE``
   * ``NETFS_INVALID_READ``

   to indicate whether the slice should just be cleared or whether it should be
   downloaded from the server or read from the cache - or whether slicing
   should be given up at the current point.

Cache read·write dispatch 계약

1005-1047

Required `read()`는 cache에서 읽습니다. 시작 file offset과 길이를 포함하는 destination iterator를 받고, 해당 위치부터 data를 찾아 앞으로 seek하라는 hint도 받을 수 있습니다.

Termination handler와 private data도 전달됩니다. Handler는 전송 byte 수 또는 error와 종료가 caller context에서 확실히 일어나는지를 나타내는 flag를 받아 호출되어야 합니다.

Required `prepare_write_subreq()`는 cache write subrequest 크기와 DIO/DMA 같은 iterator region 수를 제한하고 소속 stream의 `sreq_max_len`, `sreq_max_segs`에 설정합니다. Error를 반환할 수 없으며 실패하면 `netfs_prepare_write_failed()`를 호출합니다.

Required cache `issue_write()`는 subrequest를 cache write로 dispatch합니다. 범위는 `start`, `len`, `transferred`, buffer는 `io_iter`가 나타냅니다. 반환값은 없고 field를 갱신한 뒤 `netfs_write_subreq_terminated()`를 호출해야 하며 비동기 종료가 가능합니다.

Cache I/O completion
cache read/write dispatch전송량 또는 error 결정read: 전달된 termination handlerwrite: `netfs_write_subreq_terminated()`async 여부와 field 상태를 함께 전달

Read와 write 모두 callback 기반으로 결과를 netfslib에 반환합니다.

 * ``read()``

   [Required] Called to read from the cache.  The start file offset is given
   along with an iterator to read to, which gives the length also.  It can be
   given a hint requesting that it seek forward from that start position for
   data.

   Also provided is a pointer to a termination handler function and private
   data to pass to that function.  The termination function should be called
   with the number of bytes transferred or an error code, plus a flag
   indicating whether the termination is definitely happening in the caller's
   context.

 * ``prepare_write_subreq()``

   [Required] This is called to allow the cache to limit the size of a
   subrequest.  It may also limit the number of individual regions in iterator,
   such as required by DIO/DMA.  This information should be set on stream to
   which the subrequest belongs::

        rreq->io_streams[subreq->stream_nr].sreq_max_len
        rreq->io_streams[subreq->stream_nr].sreq_max_segs

   The filesystem can use this, for example, to chop up a request that has to
   be split across multiple servers or to put multiple writes in flight.

   This is not permitted to return an error.  In the event of failure,
   ``netfs_prepare_write_failed()`` must be called.

 * ``issue_write()``

   [Required] This is used to dispatch a subrequest to the cache for writing.
   In the subrequest, ->start, ->len and ->transferred indicate what data
   should be written to the cache and ->io_iter indicates the buffer to be
   used.

   There is no return value; the ``netfs_write_subreq_terminated()`` function
   should be called to indicate that the subrequest completed either way.
   ->error, ->transferred and ->flags should be updated before completing.  The
   termination can be done asynchronously.


API Function Reference

Kernel-doc API reference

1048-1051

API function reference는 `include/linux/netfs.h`와 `fs/netfs/buffered_read.c`의 kernel-doc을 포함합니다. 선언·구현의 최신 parameter와 반환 규칙은 이 generated reference에서 확인해야 합니다.

Netfslib API source
source path범위
`include/linux/netfs.h`공개 type·helper 선언
`fs/netfs/buffered_read.c`buffered read 구현 함수

공개 선언과 buffered read 구현의 kernel-doc 위치입니다.

======================

.. kernel-doc:: include/linux/netfs.h
.. kernel-doc:: fs/netfs/buffered_read.c