26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 1) // SPDX-License-Identifier: GPL-2.0-or-later
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 2) /* Cache data I/O routines
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 3) *
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 4) * Copyright (C) 2021 Red Hat, Inc. All Rights Reserved.
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 5) * Written by David Howells (dhowells@redhat.com)
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 6) */
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 7)
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 8) #define FSCACHE_DEBUG_LEVEL PAGE
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 9) #include <linux/module.h>
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 10) #define FSCACHE_USE_NEW_IO_API
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 11) #include <linux/fscache-cache.h>
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 12) #include <linux/slab.h>
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 13) #include <linux/netfs.h>
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 14) #include "internal.h"
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 15)
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 16) /*
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 17) * Start a cache read operation.
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 18) * - we return:
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 19) * -ENOMEM - out of memory, some pages may be being read
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 20) * -ERESTARTSYS - interrupted, some pages may be being read
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 21) * -ENOBUFS - no backing object or space available in which to cache any
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 22) * pages not being read
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 23) * -ENODATA - no data available in the backing object for some or all of
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 24) * the pages
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 25) * 0 - dispatched a read on all pages
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 26) */
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 27) int __fscache_begin_read_operation(struct netfs_read_request *rreq,
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 28) struct fscache_cookie *cookie)
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 29) {
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 30) struct fscache_retrieval *op;
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 31) struct fscache_object *object;
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 32) bool wake_cookie = false;
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 33) int ret;
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 34)
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 35) _enter("rr=%08x", rreq->debug_id);
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 36)
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 37) fscache_stat(&fscache_n_retrievals);
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 38)
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 39) if (hlist_empty(&cookie->backing_objects))
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 40) goto nobufs;
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 41)
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 42) if (test_bit(FSCACHE_COOKIE_INVALIDATING, &cookie->flags)) {
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 43) _leave(" = -ENOBUFS [invalidating]");
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 44) return -ENOBUFS;
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 45) }
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 46)
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 47) ASSERTCMP(cookie->def->type, !=, FSCACHE_COOKIE_TYPE_INDEX);
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 48)
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 49) if (fscache_wait_for_deferred_lookup(cookie) < 0)
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 50) return -ERESTARTSYS;
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 51)
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 52) op = fscache_alloc_retrieval(cookie, NULL, NULL, NULL);
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 53) if (!op)
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 54) return -ENOMEM;
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 55) trace_fscache_page_op(cookie, NULL, &op->op, fscache_page_op_retr_multi);
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 56)
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 57) spin_lock(&cookie->lock);
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 58)
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 59) if (!fscache_cookie_enabled(cookie) ||
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 60) hlist_empty(&cookie->backing_objects))
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 61) goto nobufs_unlock;
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 62) object = hlist_entry(cookie->backing_objects.first,
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 63) struct fscache_object, cookie_link);
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 64)
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 65) __fscache_use_cookie(cookie);
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 66) atomic_inc(&object->n_reads);
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 67) __set_bit(FSCACHE_OP_DEC_READ_CNT, &op->op.flags);
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 68)
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 69) if (fscache_submit_op(object, &op->op) < 0)
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 70) goto nobufs_unlock_dec;
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 71) spin_unlock(&cookie->lock);
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 72)
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 73) fscache_stat(&fscache_n_retrieval_ops);
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 74)
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 75) /* we wait for the operation to become active, and then process it
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 76) * *here*, in this thread, and not in the thread pool */
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 77) ret = fscache_wait_for_operation_activation(
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 78) object, &op->op,
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 79) __fscache_stat(&fscache_n_retrieval_op_waits),
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 80) __fscache_stat(&fscache_n_retrievals_object_dead));
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 81) if (ret < 0)
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 82) goto error;
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 83)
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 84) /* ask the cache to honour the operation */
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 85) ret = object->cache->ops->begin_read_operation(rreq, op);
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 86)
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 87) error:
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 88) if (ret == -ENOMEM)
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 89) fscache_stat(&fscache_n_retrievals_nomem);
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 90) else if (ret == -ERESTARTSYS)
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 91) fscache_stat(&fscache_n_retrievals_intr);
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 92) else if (ret == -ENODATA)
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 93) fscache_stat(&fscache_n_retrievals_nodata);
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 94) else if (ret < 0)
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 95) fscache_stat(&fscache_n_retrievals_nobufs);
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 96) else
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 97) fscache_stat(&fscache_n_retrievals_ok);
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 98)
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 99) fscache_put_retrieval(op);
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 100) _leave(" = %d", ret);
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 101) return ret;
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 102)
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 103) nobufs_unlock_dec:
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 104) atomic_dec(&object->n_reads);
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 105) wake_cookie = __fscache_unuse_cookie(cookie);
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 106) nobufs_unlock:
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 107) spin_unlock(&cookie->lock);
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 108) fscache_put_retrieval(op);
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 109) if (wake_cookie)
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 110) __fscache_wake_unused_cookie(cookie);
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 111) nobufs:
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 112) fscache_stat(&fscache_n_retrievals_nobufs);
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 113) _leave(" = -ENOBUFS");
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 114) return -ENOBUFS;
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 115) }
26aaeffcafe6c (David Howells 2021-02-22 11:39:47 +0000 116) EXPORT_SYMBOL(__fscache_begin_read_operation);