Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

cachefiles: implement on-demand read

Implement the data plane of on-demand read mode.

The early implementation [1] place the entry to
cachefiles_ondemand_read() in fscache_read(). However, fscache_read()
can only detect if the requested file range is fully cache miss, whilst
we need to notify the user daemon as long as there's a hole inside the
requested file range.

Thus the entry is now placed in cachefiles_prepare_read(). When working
in on-demand read mode, once a hole detected, the read routine will send
a READ request to the user daemon. The user daemon needs to fetch the
data and write it to the cache file. After sending the READ request, the
read routine will hang there, until the READ request is handled by the
user daemon. Then it will retry to read from the same file range. If no
progress encountered, the read routine will fail then.

A new NETFS_SREQ_ONDEMAND flag is introduced to indicate that on-demand
read should be done when a cache miss encountered.

[1] https://lore.kernel.org/all/20220406075612.60298-6-jefflexu@linux.alibaba.com/ #v8

Signed-off-by: Jeffle Xu <jefflexu@linux.alibaba.com>
Acked-by: David Howells <dhowells@redhat.com>
Link: https://lore.kernel.org/r/20220425122143.56815-6-jefflexu@linux.alibaba.com
Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>

authored by

Jeffle Xu and committed by
Gao Xiang
9032b6e8 324b954a

+117 -2
+9
fs/cachefiles/internal.h
··· 292 292 extern int cachefiles_ondemand_init_object(struct cachefiles_object *object); 293 293 extern void cachefiles_ondemand_clean_object(struct cachefiles_object *object); 294 294 295 + extern int cachefiles_ondemand_read(struct cachefiles_object *object, 296 + loff_t pos, size_t len); 297 + 295 298 #else 296 299 static inline ssize_t cachefiles_ondemand_daemon_read(struct cachefiles_cache *cache, 297 300 char __user *_buffer, size_t buflen) ··· 309 306 310 307 static inline void cachefiles_ondemand_clean_object(struct cachefiles_object *object) 311 308 { 309 + } 310 + 311 + static inline int cachefiles_ondemand_read(struct cachefiles_object *object, 312 + loff_t pos, size_t len) 313 + { 314 + return -EOPNOTSUPP; 312 315 } 313 316 #endif 314 317
+13 -2
fs/cachefiles/io.c
··· 403 403 enum netfs_io_source ret = NETFS_DOWNLOAD_FROM_SERVER; 404 404 loff_t off, to; 405 405 ino_t ino = file ? file_inode(file)->i_ino : 0; 406 + int rc; 406 407 407 408 _enter("%zx @%llx/%llx", subreq->len, subreq->start, i_size); 408 409 ··· 416 415 if (test_bit(FSCACHE_COOKIE_NO_DATA_TO_READ, &cookie->flags)) { 417 416 __set_bit(NETFS_SREQ_COPY_TO_CACHE, &subreq->flags); 418 417 why = cachefiles_trace_read_no_data; 419 - goto out_no_object; 418 + if (!test_bit(NETFS_SREQ_ONDEMAND, &subreq->flags)) 419 + goto out_no_object; 420 420 } 421 421 422 422 /* The object and the file may be being created in the background. */ ··· 434 432 object = cachefiles_cres_object(cres); 435 433 cache = object->volume->cache; 436 434 cachefiles_begin_secure(cache, &saved_cred); 437 - 435 + retry: 438 436 off = cachefiles_inject_read_error(); 439 437 if (off == 0) 440 438 off = vfs_llseek(file, subreq->start, SEEK_DATA); ··· 485 483 486 484 download_and_store: 487 485 __set_bit(NETFS_SREQ_COPY_TO_CACHE, &subreq->flags); 486 + if (test_bit(NETFS_SREQ_ONDEMAND, &subreq->flags)) { 487 + rc = cachefiles_ondemand_read(object, subreq->start, 488 + subreq->len); 489 + if (!rc) { 490 + __clear_bit(NETFS_SREQ_ONDEMAND, &subreq->flags); 491 + goto retry; 492 + } 493 + ret = NETFS_INVALID_READ; 494 + } 488 495 out: 489 496 cachefiles_end_secure(cache, saved_cred); 490 497 out_no_object:
+77
fs/cachefiles/ondemand.c
··· 10 10 struct cachefiles_object *object = file->private_data; 11 11 struct cachefiles_cache *cache = object->volume->cache; 12 12 int object_id = object->ondemand_id; 13 + struct cachefiles_req *req; 14 + XA_STATE(xas, &cache->reqs, 0); 13 15 16 + xa_lock(&cache->reqs); 14 17 object->ondemand_id = CACHEFILES_ONDEMAND_ID_CLOSED; 18 + 19 + /* 20 + * Flush all pending READ requests since their completion depends on 21 + * anon_fd. 22 + */ 23 + xas_for_each(&xas, req, ULONG_MAX) { 24 + if (req->msg.opcode == CACHEFILES_OP_READ) { 25 + req->error = -EIO; 26 + complete(&req->done); 27 + xas_store(&xas, NULL); 28 + } 29 + } 30 + xa_unlock(&cache->reqs); 31 + 15 32 xa_erase(&cache->ondemand_ids, object_id); 16 33 cachefiles_put_object(object, cachefiles_obj_put_ondemand_fd); 17 34 cachefiles_put_unbind_pincount(cache); ··· 74 57 return vfs_llseek(file, pos, whence); 75 58 } 76 59 60 + static long cachefiles_ondemand_fd_ioctl(struct file *filp, unsigned int ioctl, 61 + unsigned long arg) 62 + { 63 + struct cachefiles_object *object = filp->private_data; 64 + struct cachefiles_cache *cache = object->volume->cache; 65 + struct cachefiles_req *req; 66 + unsigned long id; 67 + 68 + if (ioctl != CACHEFILES_IOC_READ_COMPLETE) 69 + return -EINVAL; 70 + 71 + if (!test_bit(CACHEFILES_ONDEMAND_MODE, &cache->flags)) 72 + return -EOPNOTSUPP; 73 + 74 + id = arg; 75 + req = xa_erase(&cache->reqs, id); 76 + if (!req) 77 + return -EINVAL; 78 + 79 + complete(&req->done); 80 + return 0; 81 + } 82 + 77 83 static const struct file_operations cachefiles_ondemand_fd_fops = { 78 84 .owner = THIS_MODULE, 79 85 .release = cachefiles_ondemand_fd_release, 80 86 .write_iter = cachefiles_ondemand_fd_write_iter, 81 87 .llseek = cachefiles_ondemand_fd_llseek, 88 + .unlocked_ioctl = cachefiles_ondemand_fd_ioctl, 82 89 }; 83 90 84 91 /* ··· 429 388 return 0; 430 389 } 431 390 391 + struct cachefiles_read_ctx { 392 + loff_t off; 393 + size_t len; 394 + }; 395 + 396 + static int cachefiles_ondemand_init_read_req(struct cachefiles_req *req, 397 + void *private) 398 + { 399 + struct cachefiles_object *object = req->object; 400 + struct cachefiles_read *load = (void *)req->msg.data; 401 + struct cachefiles_read_ctx *read_ctx = private; 402 + int object_id = object->ondemand_id; 403 + 404 + /* Stop enqueuing requests when daemon has closed anon_fd. */ 405 + if (object_id <= 0) { 406 + WARN_ON_ONCE(object_id == 0); 407 + pr_info_once("READ: anonymous fd closed prematurely.\n"); 408 + return -EIO; 409 + } 410 + 411 + req->msg.object_id = object_id; 412 + load->off = read_ctx->off; 413 + load->len = read_ctx->len; 414 + return 0; 415 + } 416 + 432 417 int cachefiles_ondemand_init_object(struct cachefiles_object *object) 433 418 { 434 419 struct fscache_cookie *cookie = object->cookie; ··· 483 416 { 484 417 cachefiles_ondemand_send_req(object, CACHEFILES_OP_CLOSE, 0, 485 418 cachefiles_ondemand_init_close_req, NULL); 419 + } 420 + 421 + int cachefiles_ondemand_read(struct cachefiles_object *object, 422 + loff_t pos, size_t len) 423 + { 424 + struct cachefiles_read_ctx read_ctx = {pos, len}; 425 + 426 + return cachefiles_ondemand_send_req(object, CACHEFILES_OP_READ, 427 + sizeof(struct cachefiles_read), 428 + cachefiles_ondemand_init_read_req, &read_ctx); 486 429 }
+1
include/linux/netfs.h
··· 159 159 #define NETFS_SREQ_SHORT_IO 2 /* Set if the I/O was short */ 160 160 #define NETFS_SREQ_SEEK_DATA_READ 3 /* Set if ->read() should SEEK_DATA first */ 161 161 #define NETFS_SREQ_NO_PROGRESS 4 /* Set if we didn't manage to read any data */ 162 + #define NETFS_SREQ_ONDEMAND 5 /* Set if it's from on-demand read mode */ 162 163 }; 163 164 164 165 enum netfs_io_origin {
+17
include/uapi/linux/cachefiles.h
··· 3 3 #define _LINUX_CACHEFILES_H 4 4 5 5 #include <linux/types.h> 6 + #include <linux/ioctl.h> 6 7 7 8 /* 8 9 * Fscache ensures that the maximum length of cookie key is 255. The volume key ··· 14 13 enum cachefiles_opcode { 15 14 CACHEFILES_OP_OPEN, 16 15 CACHEFILES_OP_CLOSE, 16 + CACHEFILES_OP_READ, 17 17 }; 18 18 19 19 /* ··· 49 47 __u32 flags; 50 48 __u8 data[]; 51 49 }; 50 + 51 + /* 52 + * @off indicates the starting offset of the requested file range 53 + * @len indicates the length of the requested file range 54 + */ 55 + struct cachefiles_read { 56 + __u64 off; 57 + __u64 len; 58 + }; 59 + 60 + /* 61 + * Reply for READ request 62 + * @arg for this ioctl is the @id field of READ request. 63 + */ 64 + #define CACHEFILES_IOC_READ_COMPLETE _IOW(0x98, 1, int) 52 65 53 66 #endif