aboutsummaryrefslogtreecommitdiff
path: root/sys/fs/fuse
diff options
context:
space:
mode:
authorAlan Somers <asomers@FreeBSD.org>2021-10-02 18:17:36 +0000
committerAlan Somers <asomers@FreeBSD.org>2021-10-06 20:07:33 +0000
commit7430017b9978cae054ed99e5160f739e5ca021d5 (patch)
tree2d16872ddb5903a5a986ccdd766634822bcea7a2 /sys/fs/fuse
parent5d94aaacb5180798b2f698e33937f068386004eb (diff)
downloadsrc-7430017b9978cae054ed99e5160f739e5ca021d5.tar.gz
src-7430017b9978cae054ed99e5160f739e5ca021d5.zip
fusefs: fix a recurse-on-non-recursive lockmgr panic
fuse_vnop_bmap needs to know the file's size in order to calculate the optimum amount of readahead. If the file's size is unknown, it must ask the FUSE server. But if the file's data was previously cached and the server reports that its size has shrunk, fusefs must invalidate the cached data. That's not possible during VOP_BMAP because the buffer object is already locked. Fix the panic by not querying the FUSE server for the file's size during VOP_BMAP if we don't need it. That's also a a slight performance optimization. PR: 256937 Reported by: Agata <chogata@moosefs.pro> Tested by: Agata <chogata@moosefs.pro> MFC after: 2 weeks
Diffstat (limited to 'sys/fs/fuse')
-rw-r--r--sys/fs/fuse/fuse_vnops.c20
1 files changed, 16 insertions, 4 deletions
diff --git a/sys/fs/fuse/fuse_vnops.c b/sys/fs/fuse/fuse_vnops.c
index dd8ff0fcc45a..9aafbad990c5 100644
--- a/sys/fs/fuse/fuse_vnops.c
+++ b/sys/fs/fuse/fuse_vnops.c
@@ -516,8 +516,9 @@ fuse_vnop_bmap(struct vop_bmap_args *ap)
struct fuse_bmap_in *fbi;
struct fuse_bmap_out *fbo;
struct fuse_data *data;
+ struct fuse_vnode_data *fvdat = VTOFUD(vp);
uint64_t biosize;
- off_t filesize;
+ off_t fsize;
daddr_t lbn = ap->a_bn;
daddr_t *pbn = ap->a_bnp;
int *runp = ap->a_runp;
@@ -550,10 +551,21 @@ fuse_vnop_bmap(struct vop_bmap_args *ap)
*/
if (runb != NULL)
*runb = MIN(lbn, maxrun);
- if (runp != NULL) {
- error = fuse_vnode_size(vp, &filesize, td->td_ucred, td);
+ if (runp != NULL && maxrun == 0)
+ *runp = 0;
+ else if (runp != NULL) {
+ /*
+ * If the file's size is cached, use that value to calculate
+ * runp, even if the cache is expired. runp is only advisory,
+ * and the risk of getting it wrong is not worth the cost of
+ * another upcall.
+ */
+ if (fvdat->cached_attrs.va_size != VNOVAL)
+ fsize = fvdat->cached_attrs.va_size;
+ else
+ error = fuse_vnode_size(vp, &fsize, td->td_ucred, td);
if (error == 0)
- *runp = MIN(MAX(0, filesize / (off_t)biosize - lbn - 1),
+ *runp = MIN(MAX(0, fsize / (off_t)biosize - lbn - 1),
maxrun);
else
*runp = 0;