Compare commits

...
43 Commits
Author SHA1 Message Date
Antonio SJ Musumeci 61e31eecf6 checkpoint 2022-11-29 17:24:09 -06:00
trapexitandGitHub ac1f4b4d52 Merge pull request #1105 from trapexit/ll
Misc cleanup
2022-11-27 23:29:53 -05:00
Antonio SJ Musumeci ddf5e53aa4 Misc cleanup 2022-11-27 22:23:38 -06:00
trapexitandGitHub a2a12afb34 Merge pull request #1104 from trapexit/ll
Remove libfuse abstraction in prep for adding request data
2022-11-27 00:39:05 -05:00
Antonio SJ Musumeci 7606430188 Remove libfuse abstraction in prep for adding request data 2022-11-26 23:30:27 -06:00
trapexitandGitHub 629806e896 Merge pull request #1093 from lgtm-migrator/codeql
Add CodeQL workflow for GitHub code scanning
2022-11-11 09:53:27 -05:00
LGTM Migrator 50fbf14e1e Add CodeQL workflow for GitHub code scanning 2022-11-11 07:59:54 +00:00
trapexitandGitHub 4a67bbdc71 Merge pull request #1092 from trapexit/cleanup
Remove write_buf, simplify FUSE msg dispatching
2022-11-10 23:24:25 -05:00
Antonio SJ Musumeci dba9c4451a Remove write_buf, simplify FUSE msg dispatching 2022-11-10 22:43:02 -05:00
trapexitandGitHub fea499e220 Merge pull request #1091 from trapexit/cleanup
Remove unnecessary libfuse abstractions
2022-11-07 23:35:18 -05:00
Antonio SJ Musumeci 9d056d609f Remove unnecessary libfuse abstractions 2022-11-07 23:09:25 -05:00
trapexitandGitHub 9a839dd8ba Merge pull request #1089 from trapexit/32bit
Tweaks for 32bit systems
2022-11-05 23:37:19 -04:00
Antonio SJ Musumeci 32e2c9c48e Tweaks for 32bit systems 2022-11-05 23:28:10 -04:00
trapexitandGitHub 83d7886a0a Merge pull request #1087 from trapexit/kernelh
Update fuse_kernel.h
2022-11-03 23:29:22 -04:00
Antonio SJ Musumeci 316abba0ac Update fuse_kernel.h 2022-11-03 23:28:44 -04:00
trapexitandGitHub 8001c58c36 Merge pull request #1085 from trapexit/symlinkify
Fix setting of stat vars for symlinkify
2022-10-31 19:47:36 -04:00
Antonio SJ Musumeci 3b0d7fb26e Fix setting of stat vars for symlinkify 2022-10-30 22:27:33 -04:00
trapexitandGitHub 5d3c5002e0 Merge pull request #1058 from trapexit/docs
Support doc update
2022-08-08 14:09:22 -04:00
Antonio SJ Musumeci 9082285cc8 Support doc update 2022-08-08 13:40:43 -04:00
trapexitandGitHub d1762b2bac Merge pull request #1057 from trapexit/cfgerrs
Error when given invalid policy names
2022-08-06 23:08:10 -04:00
Antonio SJ Musumeci 46ce28b149 Error when given invalid policy names 2022-08-06 23:01:23 -04:00
trapexitandGitHub faadeb75e0 Merge pull request #1045 from Gelma/master
Fix typos
2022-06-22 14:27:13 -04:00
Andrea Gelmini 338e559e53 Fix typos 2022-06-22 11:51:23 +02:00
trapexitandGitHub 3db673410f Merge pull request #1039 from trapexit/docs
Add details about usage of FUSE to docs
2022-05-23 12:49:06 -04:00
Antonio SJ Musumeci 77f098614f Add details about usage of FUSE to docs 2022-05-23 12:40:00 -04:00
trapexitandGitHub 9589846e9a Merge pull request #1032 from trapexit/support
Rework support section in readme
2022-04-25 17:44:16 -04:00
Antonio SJ Musumeci e2dda3c1b1 Rework support section in readme 2022-04-25 17:42:31 -04:00
trapexitandGitHub d9ab18282f Merge pull request #1031 from trapexit/root-parent
Return ENOENT when dotdot for root node requested
2022-04-12 23:18:57 -04:00
Antonio SJ Musumeci 14c2ff9ab8 Return ENOENT when dotdot for root node requested 2022-04-12 23:17:39 -04:00
trapexitandGitHub 77e6f400b5 Merge pull request #1026 from trapexit/loglock
Lock less often during logging
2022-03-20 22:45:07 -04:00
Antonio SJ Musumeci b95ff8ba3a Lock less often during logging 2022-03-20 22:34:55 -04:00
trapexitandGitHub 4bf8738e5c Merge pull request #1025 from trapexit/estale
Change ENOENT to ESTALE for looking up paths to handle rename race conditions
2022-03-20 12:19:00 -04:00
Antonio SJ Musumeci 3f060f4512 Change ENOENT to ESTALE for looking up paths to handle rename race conditions
As done in https://github.com/libfuse/libfuse/pull/636
2022-03-20 12:09:22 -04:00
trapexitandGitHub c4c35a9ad0 Merge pull request #1023 from trapexit/follow-symlink-fix
Fix query of attr during symlink
2022-03-19 17:01:11 -04:00
Antonio SJ Musumeci c9a935835f Fix query of attr during symlink
Using getattr when follow-symlink is enabled causes invalid type to the kernel
if symlink pointed to non-symlink.
2022-03-19 16:18:46 -04:00
trapexitandGitHub 015002ebd9 Merge pull request #1020 from trapexit/slab-maintenance
Rework node slab garbage collection to limit blocking work threads
2022-03-19 15:54:29 -04:00
Antonio SJ Musumeci 9ca10b2413 Rework node slab garbage collection to limit blocking work threads
Also remove debug mode from forcing foreground mode
2022-03-19 13:33:14 -04:00
trapexitandGitHub 2d5c2c2b6e Merge pull request #1007 from trapexit/trapexit-patch-1
Update bug_report.md
2022-01-18 21:16:22 -05:00
trapexitandGitHub e3ab739a56 Update bug_report.md 2022-01-18 21:15:59 -05:00
trapexit c784d06029 Merge pull request #1005 from trapexit/readme-readahead
Update README.md regarding readahead
2022-01-15 17:39:31 -05:00
trapexitandGitHub 58803f4845 Update README.md 2022-01-15 17:33:07 -05:00
trapexitandGitHub f159fe61f9 Merge pull request #997 from trapexit/link-getattr
Call FUSE getattr rather than syscall for extra logic
2021-12-18 17:21:19 -05:00
Antonio SJ Musumeci c43b464d6c Call FUSE getattr rather than syscall for extra logic
While more efficient calling regular getattr (stat) leads to incorrect
information being returned and would not work correctly when using
symlinkify.
2021-12-18 17:07:23 -05:00
37 changed files with 3029 additions and 7209 deletions
+7 -5
View File
@@ -9,7 +9,9 @@ assignees: ''
**Describe the bug**
A clear and concise description of the unexpected behavior. Please be sure to use latest release of mergerfs to ensure the issue still exists.
A clear and concise description of the unexpected behavior.
**Please be sure to use latest release of mergerfs to ensure the issue still exists. Not your distro's latest but the latest official release.**
The master branch is **not** to be considered production ready. Feel free to file bug reports but do so indicating clearly that you are testing unreleased code.
@@ -18,9 +20,9 @@ The master branch is **not** to be considered production ready. Feel free to fil
Steps to reproduce the behavior. List **all** steps to reproduce. **All** settings.
Please simplify the reproduction as much as possible.
Please simplify the reproduction as much as possible.
- Unless it is dependenat on multiple branches, use a single branch
- Use standard tooling if possible (touch,truncate,rm,rmdir,ln,etc.)
- Reproduce with standard tooling if possible (touch,truncate,rm,rmdir,ln,etc.) Having to install 3rd party software will make debugging more difficult.
**Expected behavior**
@@ -35,8 +37,8 @@ A clear and concise description of the expected behavior.
- mergerfs settings
- List of drives, filesystems, & sizes:
- `df -h`
- `lsblk`
- A strace of the application having a problem:
- `lsblk -f`
- A strace of the application having a problem:
- `strace -fvTtt -s 256 -o /tmp/app.strace.txt <cmd>`
- `strace -fvTtt -s 256 -o /tmp/app.strace.txt -p <appPID>`
- strace of mergerfs while app tried to do it's thing:
+2 -2
View File
@@ -1,10 +1,10 @@
---
name: Question
about: When you're looking for information
about: When you're looking for information or general support
title: ''
labels: investigating, question
assignees: ''
---
You can also ask questions on Discord for realtime help: https://discord.gg/MpAr69V
For general questions and support please use [GitHub Discussions](https://github.com/trapexit/mergerfs/discussions) or [Discord](https://discord.gg/MpAr69V).
+42
View File
@@ -0,0 +1,42 @@
name: "CodeQL"
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
schedule:
- cron: "7 3 * * 6"
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ python, cpp ]
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
queries: +security-and-quality
- name: Autobuild
uses: github/codeql-action/autobuild@v2
if: ${{ matrix.language == 'python' || matrix.language == 'cpp' }}
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
with:
category: "/language:${{ matrix.language }}"
+38 -36
View File
@@ -1,6 +1,6 @@
% mergerfs(1) mergerfs user manual
% Antonio SJ Musumeci <trapexit@spawn.link>
% 2021-10-25
% 2022-05-23
# NAME
@@ -324,7 +324,7 @@ NFS is not fully POSIX compliant and historically certain behaviors, such as ope
This hack addresses the issue where the creation of a file with a read-only mode but with a read/write or write only flag. Normally this is perfectly valid but NFS chops the one open call into multiple calls. Exactly how it is translated depends on the configuration and versions of the NFS server and clients but it results in a permission error because a normal user is not allowed to open a read-only file as writable.
Even though it's a more niche situation this hack breaks normal security and behavior and as such is `off` by default. If set to `git` it will only perform the hack when the path in question includes `/.git/`. `all` will result it it applying anytime a readonly file which is empty is opened for writing.
Even though it's a more niche situation this hack breaks normal security and behavior and as such is `off` by default. If set to `git` it will only perform the hack when the path in question includes `/.git/`. `all` will result it applying anytime a readonly file which is empty is opened for writing.
# FUNCTIONS, CATEGORIES and POLICIES
@@ -367,7 +367,7 @@ Policies basically search branches and create a list of files / paths for functi
Policies may have their own additional filtering such as those that require existing paths to be present.
If all branches are filtered an error will be returned. Typically **EROFS** (read-only filesystem) or **ENOSPC** (no space left on device) depending on the most recent reason for filtering a branch. **ENOENT** will be returned if no elegible branch is found.
If all branches are filtered an error will be returned. Typically **EROFS** (read-only filesystem) or **ENOSPC** (no space left on device) depending on the most recent reason for filtering a branch. **ENOENT** will be returned if no eligible branch is found.
#### Path Preservation
@@ -739,7 +739,7 @@ MergerFS does not natively support any sort of tiered caching. Most users have n
1. Fast network, slow drives, many readers: You've a 10+Gbps network with many readers and your regular drives can't keep up.
2. Fast network, slow drives, small'ish bursty writes: You have a 10+Gbps network and wish to transfer amounts of data less than your cache drive but wish to do so quickly.
With #1 its arguable if you should be using mergerfs at all. RAID would probably be the better solution. If you're going to use mergerfs there are other tactics that may help: spreading the data across drives (see the mergerfs.dup tool) and setting `func.open=rand`, using `symlinkify`, or using dm-cache or a similar technology to add tiered cache to the underlying device.
With #1 it's arguable if you should be using mergerfs at all. RAID would probably be the better solution. If you're going to use mergerfs there are other tactics that may help: spreading the data across drives (see the mergerfs.dup tool) and setting `func.open=rand`, using `symlinkify`, or using dm-cache or a similar technology to add tiered cache to the underlying device.
With #2 one could use dm-cache as well but there is another solution which requires only mergerfs and a cronjob.
@@ -829,6 +829,8 @@ NOTE: be sure to read about these features before changing them to understand wh
* use `symlinkify` if your data is largely static and read-only
* use tiered cache drives
* use LVM and LVM cache to place a SSD in front of your HDDs
* if `cache.files` is enabled increase readahead: `echo "1024" > /sys/class/bdi/0:$(stat -c%d /MOUNT)/read_ahead_kb`
* increase readahead on all devices: `ls -1 /sys/class/bdi/*/read_ahead_kb | xargs -n1 -I{} sh -c "echo 1024 > {}"`
If you come across a setting that significantly impacts performance please contact trapexit so he may investigate further.
@@ -882,7 +884,7 @@ echo 3 | sudo tee /proc/sys/vm/drop_caches
* If you don't see some directories and files you expect, policies seem to skip branches, you get strange permission errors, etc. be sure the underlying filesystems' permissions are all the same. Use `mergerfs.fsck` to audit the drive for out of sync permissions.
* If you still have permission issues be sure you are using POSIX ACL compliant filesystems. mergerfs doesn't generally make exceptions for FAT, NTFS, or other non-POSIX filesystem.
* Do **not** use `cache.files=off` if you expect applications (such as rtorrent) to use [mmap](http://linux.die.net/man/2/mmap) files. Shared mmap is not currently supported in FUSE w/ page caching disabled. Enabling `dropcacheonclose` is recommended when `cache.files=partial|full|auto-full`.
* [Kodi](http://kodi.tv), [Plex](http://plex.tv), [Subsonic](http://subsonic.org), etc. can use directory [mtime](http://linux.die.net/man/2/stat) to more efficiently determine whether to scan for new content rather than simply performing a full scan. If using the default **getattr** policy of **ff** it's possible those programs will miss an update on account of it returning the first directory found's **stat** info and its a later directory on another mount which had the **mtime** recently updated. To fix this you will want to set **func.getattr=newest**. Remember though that this is just **stat**. If the file is later **open**'ed or **unlink**'ed and the policy is different for those then a completely different file or directory could be acted on.
* [Kodi](http://kodi.tv), [Plex](http://plex.tv), [Subsonic](http://subsonic.org), etc. can use directory [mtime](http://linux.die.net/man/2/stat) to more efficiently determine whether to scan for new content rather than simply performing a full scan. If using the default **getattr** policy of **ff** it's possible those programs will miss an update on account of it returning the first directory found's **stat** info and it's a later directory on another mount which had the **mtime** recently updated. To fix this you will want to set **func.getattr=newest**. Remember though that this is just **stat**. If the file is later **open**'ed or **unlink**'ed and the policy is different for those then a completely different file or directory could be acted on.
* Some policies mixed with some functions may result in strange behaviors. Not that some of these behaviors and race conditions couldn't happen outside **mergerfs** but that they are far more likely to occur on account of the attempt to merge together multiple sources of data which could be out of sync due to the different policies.
* For consistency its generally best to set **category** wide policies rather than individual **func**'s. This will help limit the confusion of tools such as [rsync](http://linux.die.net/man/1/rsync). However, the flexibility is there if needed.
@@ -1081,7 +1083,7 @@ Remember that hardlinks will NOT work across devices. That includes between the
#### Can I use mergerfs without SnapRAID? SnapRAID without mergerfs?
Yes. They are completely unreleated pieces of software.
Yes. They are completely unrelated pieces of software.
#### Can mergerfs run via Docker, Podman, Kubernetes, etc.
@@ -1109,6 +1111,32 @@ Whenever you run into a split permission issue (seeing some but not all files) t
If using a network filesystem such as NFS, SMB, CIFS (Samba) be sure to pay close attention to anything regarding permissioning and users. Root squashing and user translation for instance has bitten a few mergerfs users. Some of these also affect the use of mergerfs from container platforms such as Docker.
#### Why use FUSE? Why not a kernel based solution?
As with any two solutions to a problem there are advantages and disadvantages to each one.
A FUSE based solution has all the downsides of FUSE:
* Higher IO latency due to the trips in and out of kernel space
* Higher general overhead due to trips in and out of kernel space
* Double caching when using page caching
* Misc limitations due to FUSE's design
But FUSE also has a lot of upsides:
* Easier to offer a cross platform solution
* Easier forward and backward compatibility
* Easier updates for users
* Easier and faster release cadence
* Allows more flexibility in design and features
* Overall easier to write, secure, and maintain
* Ability to run without root access or need to change the kernel
* Much lower barrier to entry (getting code into the kernel takes a lot of time and effort initially)
FUSE was chosen because of all the advantages listed above. The negatives of FUSE do not outweigh the positives.
#### Is my OS's libfuse needed for mergerfs to work?
No. Normally `mount.fuse` is needed to get mergerfs (or any FUSE filesystem to mount using the `mount` command but in vendoring the libfuse library the `mount.fuse` app has been renamed to `mount.mergerfs` meaning the filesystem type in `fstab` can simply be `mergerfs`. That said there should be no harm in having it installed and continuing to using `fuse.mergerfs` as the type in `/etc/fstab`.
@@ -1263,6 +1291,8 @@ Filesystems are complex and difficult to debug. mergerfs, while being just a pro
**Please make sure you are using the [latest release](https://github.com/trapexit/mergerfs/releases) or have tried it in comparison. Old versions, which are often included in distros like Debian and Ubuntu, are not ever going to be updated and your bug may have been addressed already.**
**For commercial support or feature requests please contact me directly.**
#### Information to include in bug reports
@@ -1292,37 +1322,9 @@ Filesystems are complex and difficult to debug. mergerfs, while being just a pro
#### Support development
This software is free to use and released under a very liberal license (ISC). That said if you like this software and would like to support its development donations are welcome.
This software is released under the very liberal ISC license and is therefore free to use for personal or commercial uses. That said if you like this software and have the means please consider supporting its development.
Crypto is fine in whatever protocol you prefer. My preferences for fiat would be GitHub Sponsors or PayPal though feel free to use any platform listed below.
* GitHub Sponsors: https://github.com/sponsors/trapexit
* PayPal: https://paypal.me/trapexit
* Patreon: https://www.patreon.com/trapexit
* BuyMeACoffee: https://buymeacoff.ee/trapexit
* Ko-Fi: https://ko-fi.com/trapexit
* Open Collective: https://opencollective.com/trapexit
* Bitcoin (BTC): bc1qu537hqlnmn2wawx9n7nws0dlkz55h0cd93ny28
* Bitcoin Cash (BCH): bitcoincash:qqp0vh9v44us74gaggwjfv9y54zfjmmd7srlqxa3xt
* Bitcoin SV (BSV): 1FkFuxRtt3f8LbkpeUKRZq7gKJFzGSGgZV
* Bitcoin Gold (BTG): AaPuJgJeohPjkB3LxJM6NKGnaHoRJ8ieT3
* Litecoin (LTC): MJQzsHBdNnkyGqCFdcAdHYKugicBmfAXfQ
* Dogecoin (DOGE): DLJNLVe28vZ4SMQSxDJLBQBv57rGtUoWFh
* Ethereum (ETH): 0xB8d6d55c0319aacC327860d13f891427caEede7a
* Any ERC20 Token: 0xB8d6d55c0319aacC327860d13f891427caEede7a
* Ethereum Classic (ETC): 0x2B6054428e69a1201B6555f7a2aEc0Fba01EAD9F
* Harmony (ONE): one1hrtd2hqrrx4vcvncvrgnlzg5yl9wahn66lq6rw (0xB8d6d55c0319aacC327860d13f891427caEede7a)
* Monero (XMR): 45BBZMrJwPSaFwSoqLVNEggWR2BJJsXxz7bNz8FXnnFo3GyhVJFSCrCFSS7zYwDa9r1TmFmGMxQ2HTntuc11yZ9q1LeCE8f
* Dash (DASH): XvsFrohu8tbjA4E8p7xsc86E2ADxLHGXHL
* Chia (XCH): xch18l7e2q34jtuyzkq0jg8vp7yrtnfwzly30w3yyhkk96um2ur4yqcq6p2een
* LBRY Credits (LBC): bFusyoZPkSuzM2Pr8mcthgvkymaosJZt5r
* Ripple (XRP): r9f6aoxaGD8aymxqH89Ke1PCUPkNiFdZZC
* Tezos (XTZ): tz1ZxerkbbALsuU9XGV9K9fFpuLWnKAGfc1C
* Zcash (ZEC): t1Zo1GGn2T3GrhKvgdtnTsTnWu6tCPaCaHG
* DigiByte (DGB): Sb8r1qTrryY9Sp4YkTE1eeKEGVzgArnE5N
* Namecoin (NMC): NDzb9FkoptGu5QbgetCkodJqo2zE1cTwyb
* Vertcoin (VTC): 3PYdhokAGXJwWrwHRoTywxG4iUDk6EHjKe
* Other crypto currencies: contact me for address
https://github.com/trapexit/support
# LINKS
-3547
View File
File diff suppressed because it is too large Load Diff
+9 -1
View File
@@ -37,7 +37,6 @@ SRC = \
lib/debug.c \
lib/fuse.c \
lib/fuse_dirents.c \
lib/fuse_kern_chan.c \
lib/fuse_loop_mt.c \
lib/fuse_lowlevel.c \
lib/fuse_mt.c \
@@ -57,6 +56,12 @@ CFLAGS := \
-Wall \
-pipe \
-MMD
CXXFLAGS := \
${CXXFLAGS} \
-std=c++17 \
-Wall \
-pipe \
-MMD
FUSERMOUNT_DIR = $(BINDIR)
FUSE_FLAGS = \
-Iinclude \
@@ -101,6 +106,9 @@ mount.mergerfs: build/mount.mergerfs
build/%.o: lib/%.c
$(CC) $(CFLAGS) $(FUSE_FLAGS) -c $< -o $@
build/%.o: lib/%.cpp
$(CXX) $(CXXFLAGS) $(FUSE_FLAGS) -c $< -o $@
clean:
rm -rf build
+4 -98
View File
@@ -475,9 +475,10 @@ struct fuse_operations
*
* Introduced in version 2.9
*/
int (*write_buf) (const fuse_file_info_t *ffi,
struct fuse_bufvec *buf,
off_t off);
int (*write) (const fuse_file_info_t *ffi,
const char *data,
size_t size,
off_t off);
/** Store data from an open file in a buffer
*
@@ -729,101 +730,6 @@ struct fuse_fs;
* fuse_fs_releasedir and fuse_fs_statfs, which return 0.
*/
int fuse_fs_getattr(struct fuse_fs *fs,
const char *path,
struct stat *buf,
fuse_timeouts_t *timeout);
int fuse_fs_fgetattr(struct fuse_fs *fs,
struct stat *buf,
fuse_file_info_t *fi,
fuse_timeouts_t *timeout);
int fuse_fs_rename(struct fuse_fs *fs, const char *oldpath,
const char *newpath);
int fuse_fs_unlink(struct fuse_fs *fs, const char *path);
int fuse_fs_rmdir(struct fuse_fs *fs, const char *path);
int fuse_fs_symlink(struct fuse_fs *fs,
const char *linkname,
const char *path,
struct stat *st,
fuse_timeouts_t *timeouts);
int fuse_fs_link(struct fuse_fs *fs,
const char *oldpath,
const char *newpath,
struct stat *st,
fuse_timeouts_t *timeouts);
int fuse_fs_release(struct fuse_fs *fs,
fuse_file_info_t *fi);
int fuse_fs_open(struct fuse_fs *fs, const char *path,
fuse_file_info_t *fi);
int fuse_fs_read_buf(struct fuse_fs *fs,
struct fuse_bufvec **bufp, size_t size, off_t off,
fuse_file_info_t *fi);
int fuse_fs_write_buf(struct fuse_fs *fs,
struct fuse_bufvec *buf, off_t off,
fuse_file_info_t *fi);
int fuse_fs_fsync(struct fuse_fs *fs, int datasync,
fuse_file_info_t *fi);
int fuse_fs_flush(struct fuse_fs *fs,
fuse_file_info_t *fi);
int fuse_fs_statfs(struct fuse_fs *fs, const char *path, struct statvfs *buf);
int fuse_fs_opendir(struct fuse_fs *fs, const char *path,
fuse_file_info_t *fi);
int fuse_fs_readdir(struct fuse_fs *fs,
fuse_file_info_t *fi,
fuse_dirents_t *buf);
int fuse_fs_fsyncdir(struct fuse_fs *fs, int datasync,
fuse_file_info_t *fi);
int fuse_fs_releasedir(struct fuse_fs *fs,
fuse_file_info_t *fi);
int fuse_fs_create(struct fuse_fs *fs, const char *path, mode_t mode,
fuse_file_info_t *fi);
int fuse_fs_lock(struct fuse_fs *fs,
fuse_file_info_t *fi, int cmd, struct flock *lock);
int fuse_fs_flock(struct fuse_fs *fs,
fuse_file_info_t *fi, int op);
int fuse_fs_chmod(struct fuse_fs *fs, const char *path, mode_t mode);
int fuse_fs_chown(struct fuse_fs *fs, const char *path, uid_t uid, gid_t gid);
int fuse_fs_truncate(struct fuse_fs *fs, const char *path, off_t size);
int fuse_fs_ftruncate(struct fuse_fs *fs, off_t size,
fuse_file_info_t *fi);
int fuse_fs_utimens(struct fuse_fs *fs, const char *path,
const struct timespec tv[2]);
int fuse_fs_access(struct fuse_fs *fs, const char *path, int mask);
int fuse_fs_readlink(struct fuse_fs *fs, const char *path, char *buf,
size_t len);
int fuse_fs_mknod(struct fuse_fs *fs, const char *path, mode_t mode,
dev_t rdev);
int fuse_fs_mkdir(struct fuse_fs *fs, const char *path, mode_t mode);
int fuse_fs_setxattr(struct fuse_fs *fs, const char *path, const char *name,
const char *value, size_t size, int flags);
int fuse_fs_getxattr(struct fuse_fs *fs, const char *path, const char *name,
char *value, size_t size);
int fuse_fs_listxattr(struct fuse_fs *fs, const char *path, char *list,
size_t size);
int fuse_fs_removexattr(struct fuse_fs *fs, const char *path,
const char *name);
int fuse_fs_bmap(struct fuse_fs *fs, const char *path, size_t blocksize,
uint64_t *idx);
int fuse_fs_ioctl(struct fuse_fs *fs, unsigned long cmd, void *arg,
fuse_file_info_t *fi, unsigned int flags,
void *data, uint32_t *out_bufsz);
int fuse_fs_poll(struct fuse_fs *fs,
fuse_file_info_t *fi, fuse_pollhandle_t *ph,
unsigned *reventsp);
int fuse_fs_fallocate(struct fuse_fs *fs, int mode,
off_t offset, off_t length, fuse_file_info_t *fi);
void fuse_fs_init(struct fuse_fs *fs, struct fuse_conn_info *conn);
void fuse_fs_destroy(struct fuse_fs *fs);
int fuse_fs_prepare_hide(struct fuse_fs *fs, const char *path, uint64_t *fh);
int fuse_fs_free_hide(struct fuse_fs *fs, uint64_t fh);
ssize_t fuse_fs_copy_file_range(struct fuse_fs *fs,
fuse_file_info_t *fi_in, off_t off_in,
fuse_file_info_t *fi_out, off_t off_out,
size_t len, int flags);
int fuse_notify_poll(fuse_pollhandle_t *ph);
/**
+165 -22
View File
@@ -172,6 +172,31 @@
* - add FUSE_WRITE_KILL_PRIV flag
* - add FUSE_SETUPMAPPING and FUSE_REMOVEMAPPING
* - add map_alignment to fuse_init_out, add FUSE_MAP_ALIGNMENT flag
*
* 7.32
* - add flags to fuse_attr, add FUSE_ATTR_SUBMOUNT, add FUSE_SUBMOUNTS
*
* 7.33
* - add FUSE_HANDLE_KILLPRIV_V2, FUSE_WRITE_KILL_SUIDGID, FATTR_KILL_SUIDGID
* - add FUSE_OPEN_KILL_SUIDGID
* - extend fuse_setxattr_in, add FUSE_SETXATTR_EXT
* - add FUSE_SETXATTR_ACL_KILL_SGID
*
* 7.34
* - add FUSE_SYNCFS
*
* 7.35
* - add FOPEN_NOFLUSH
*
* 7.36
* - extend fuse_init_in with reserved fields, add FUSE_INIT_EXT init flag
* - add flags2 to fuse_init_in and fuse_init_out
* - add FUSE_SECURITY_CTX init flag
* - add security context to create, mkdir, symlink, and mknod requests
* - add FUSE_HAS_INODE_DAX, FUSE_ATTR_DAX
*
* 7.37
* - add FUSE_TMPFILE
*/
#ifndef _LINUX_FUSE_H
@@ -207,7 +232,7 @@
#define FUSE_KERNEL_VERSION 7
/** Minor version number of this interface */
#define FUSE_KERNEL_MINOR_VERSION 31
#define FUSE_KERNEL_MINOR_VERSION 37
/** The node ID of the root inode */
#define FUSE_ROOT_ID 1
@@ -231,7 +256,7 @@ struct fuse_attr {
uint32_t gid;
uint32_t rdev;
uint32_t blksize;
uint32_t padding;
uint32_t flags;
};
struct fuse_kstatfs {
@@ -257,17 +282,18 @@ struct fuse_file_lock {
/**
* Bitmasks for fuse_setattr_in.valid
*/
#define FATTR_MODE (1 << 0)
#define FATTR_UID (1 << 1)
#define FATTR_GID (1 << 2)
#define FATTR_SIZE (1 << 3)
#define FATTR_ATIME (1 << 4)
#define FATTR_MTIME (1 << 5)
#define FATTR_FH (1 << 6)
#define FATTR_ATIME_NOW (1 << 7)
#define FATTR_MTIME_NOW (1 << 8)
#define FATTR_LOCKOWNER (1 << 9)
#define FATTR_CTIME (1 << 10)
#define FATTR_MODE (1 << 0)
#define FATTR_UID (1 << 1)
#define FATTR_GID (1 << 2)
#define FATTR_SIZE (1 << 3)
#define FATTR_ATIME (1 << 4)
#define FATTR_MTIME (1 << 5)
#define FATTR_FH (1 << 6)
#define FATTR_ATIME_NOW (1 << 7)
#define FATTR_MTIME_NOW (1 << 8)
#define FATTR_LOCKOWNER (1 << 9)
#define FATTR_CTIME (1 << 10)
#define FATTR_KILL_SUIDGID (1 << 11)
/**
* Flags returned by the OPEN request
@@ -277,12 +303,14 @@ struct fuse_file_lock {
* FOPEN_NONSEEKABLE: the file is not seekable
* FOPEN_CACHE_DIR: allow caching this directory
* FOPEN_STREAM: the file is stream-like (no file position at all)
* FOPEN_NOFLUSH: don't flush data cache on close (unless FUSE_WRITEBACK_CACHE)
*/
#define FOPEN_DIRECT_IO (1 << 0)
#define FOPEN_KEEP_CACHE (1 << 1)
#define FOPEN_NONSEEKABLE (1 << 2)
#define FOPEN_CACHE_DIR (1 << 3)
#define FOPEN_STREAM (1 << 4)
#define FOPEN_NOFLUSH (1 << 5)
/**
* INIT request/reply flags
@@ -313,7 +341,21 @@ struct fuse_file_lock {
* FUSE_CACHE_SYMLINKS: cache READLINK responses
* FUSE_NO_OPENDIR_SUPPORT: kernel supports zero-message opendir
* FUSE_EXPLICIT_INVAL_DATA: only invalidate cached pages on explicit request
* FUSE_MAP_ALIGNMENT: map_alignment field is valid
* FUSE_MAP_ALIGNMENT: init_out.map_alignment contains log2(byte alignment) for
* foffset and moffset fields in struct
* fuse_setupmapping_out and fuse_removemapping_one.
* FUSE_SUBMOUNTS: kernel supports auto-mounting directory submounts
* FUSE_HANDLE_KILLPRIV_V2: fs kills suid/sgid/cap on write/chown/trunc.
* Upon write/truncate suid/sgid is only killed if caller
* does not have CAP_FSETID. Additionally upon
* write/truncate sgid is killed only if file has group
* execute permission. (Same as Linux VFS behavior).
* FUSE_SETXATTR_EXT: Server supports extended struct fuse_setxattr_in
* FUSE_INIT_EXT: extended fuse_init_in request
* FUSE_INIT_RESERVED: reserved, do not use
* FUSE_SECURITY_CTX: add security context to create, mkdir, symlink, and
* mknod
* FUSE_HAS_INODE_DAX: use per inode DAX
*/
#define FUSE_ASYNC_READ (1 << 0)
#define FUSE_POSIX_LOCKS (1 << 1)
@@ -342,6 +384,14 @@ struct fuse_file_lock {
#define FUSE_NO_OPENDIR_SUPPORT (1 << 24)
#define FUSE_EXPLICIT_INVAL_DATA (1 << 25)
#define FUSE_MAP_ALIGNMENT (1 << 26)
#define FUSE_SUBMOUNTS (1 << 27)
#define FUSE_HANDLE_KILLPRIV_V2 (1 << 28)
#define FUSE_SETXATTR_EXT (1 << 29)
#define FUSE_INIT_EXT (1 << 30)
#define FUSE_INIT_RESERVED (1 << 31)
/* bits 32..63 get shifted down 32 bits into the flags2 field */
#define FUSE_SECURITY_CTX (1ULL << 32)
#define FUSE_HAS_INODE_DAX (1ULL << 33)
/**
* CUSE INIT request/reply flags
@@ -371,11 +421,14 @@ struct fuse_file_lock {
*
* FUSE_WRITE_CACHE: delayed write from page cache, file handle is guessed
* FUSE_WRITE_LOCKOWNER: lock_owner field is valid
* FUSE_WRITE_KILL_PRIV: kill suid and sgid bits
* FUSE_WRITE_KILL_SUIDGID: kill suid and sgid bits
*/
#define FUSE_WRITE_CACHE (1 << 0)
#define FUSE_WRITE_LOCKOWNER (1 << 1)
#define FUSE_WRITE_KILL_PRIV (1 << 2)
#define FUSE_WRITE_KILL_SUIDGID (1 << 2)
/* Obsolete alias; this flag implies killing suid/sgid only. */
#define FUSE_WRITE_KILL_PRIV FUSE_WRITE_KILL_SUIDGID
/**
* Read flags
@@ -417,6 +470,27 @@ struct fuse_file_lock {
*/
#define FUSE_FSYNC_FDATASYNC (1 << 0)
/**
* fuse_attr flags
*
* FUSE_ATTR_SUBMOUNT: Object is a submount root
* FUSE_ATTR_DAX: Enable DAX for this file in per inode DAX mode
*/
#define FUSE_ATTR_SUBMOUNT (1 << 0)
#define FUSE_ATTR_DAX (1 << 1)
/**
* Open flags
* FUSE_OPEN_KILL_SUIDGID: Kill suid and sgid if executable
*/
#define FUSE_OPEN_KILL_SUIDGID (1 << 0)
/**
* setxattr flags
* FUSE_SETXATTR_ACL_KILL_SGID: Clear SGID when system.posix_acl_access is set
*/
#define FUSE_SETXATTR_ACL_KILL_SGID (1 << 0)
enum fuse_opcode {
FUSE_LOOKUP = 1,
FUSE_FORGET = 2, /* no reply */
@@ -465,6 +539,8 @@ enum fuse_opcode {
FUSE_COPY_FILE_RANGE = 47,
FUSE_SETUPMAPPING = 48,
FUSE_REMOVEMAPPING = 49,
FUSE_SYNCFS = 50,
FUSE_TMPFILE = 51,
/* CUSE specific operations */
CUSE_INIT = 4096,
@@ -578,14 +654,14 @@ struct fuse_setattr_in {
struct fuse_open_in {
uint32_t flags;
uint32_t unused;
uint32_t open_flags; /* FUSE_OPEN_... */
};
struct fuse_create_in {
uint32_t flags;
uint32_t mode;
uint32_t umask;
uint32_t padding;
uint32_t open_flags; /* FUSE_OPEN_... */
};
struct fuse_open_out {
@@ -647,9 +723,13 @@ struct fuse_fsync_in {
uint32_t padding;
};
#define FUSE_COMPAT_SETXATTR_IN_SIZE 8
struct fuse_setxattr_in {
uint32_t size;
uint32_t flags;
uint32_t setxattr_flags;
uint32_t padding;
};
struct fuse_getxattr_in {
@@ -684,6 +764,8 @@ struct fuse_init_in {
uint32_t minor;
uint32_t max_readahead;
uint32_t flags;
uint32_t flags2;
uint32_t unused[11];
};
#define FUSE_COMPAT_INIT_OUT_SIZE 8
@@ -700,7 +782,8 @@ struct fuse_init_out {
uint32_t time_gran;
uint16_t max_pages;
uint16_t map_alignment;
uint32_t unused[8];
uint32_t flags2;
uint32_t unused[7];
};
#define CUSE_INIT_INFO_MAX 4096
@@ -808,9 +891,12 @@ struct fuse_dirent {
char name[];
};
#define FUSE_NAME_OFFSET offsetof(struct fuse_dirent, name)
#define FUSE_DIRENT_ALIGN(x) \
/* Align variable length records to 64bit boundary */
#define FUSE_REC_ALIGN(x) \
(((x) + sizeof(uint64_t) - 1) & ~(sizeof(uint64_t) - 1))
#define FUSE_NAME_OFFSET offsetof(struct fuse_dirent, name)
#define FUSE_DIRENT_ALIGN(x) FUSE_REC_ALIGN(x)
#define FUSE_DIRENT_SIZE(d) \
FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + (d)->namelen)
@@ -869,7 +955,8 @@ struct fuse_notify_retrieve_in {
};
/* Device ioctls: */
#define FUSE_DEV_IOC_CLONE _IOR(229, 0, uint32_t)
#define FUSE_DEV_IOC_MAGIC 229
#define FUSE_DEV_IOC_CLONE _IOR(FUSE_DEV_IOC_MAGIC, 0, uint32_t)
struct fuse_lseek_in {
uint64_t fh;
@@ -892,4 +979,60 @@ struct fuse_copy_file_range_in {
uint64_t flags;
};
#define FUSE_SETUPMAPPING_FLAG_WRITE (1ull << 0)
#define FUSE_SETUPMAPPING_FLAG_READ (1ull << 1)
struct fuse_setupmapping_in {
/* An already open handle */
uint64_t fh;
/* Offset into the file to start the mapping */
uint64_t foffset;
/* Length of mapping required */
uint64_t len;
/* Flags, FUSE_SETUPMAPPING_FLAG_* */
uint64_t flags;
/* Offset in Memory Window */
uint64_t moffset;
};
struct fuse_removemapping_in {
/* number of fuse_removemapping_one follows */
uint32_t count;
};
struct fuse_removemapping_one {
/* Offset into the dax window start the unmapping */
uint64_t moffset;
/* Length of mapping required */
uint64_t len;
};
#define FUSE_REMOVEMAPPING_MAX_ENTRY \
(PAGE_SIZE / sizeof(struct fuse_removemapping_one))
struct fuse_syncfs_in {
uint64_t padding;
};
/*
* For each security context, send fuse_secctx with size of security context
* fuse_secctx will be followed by security context name and this in turn
* will be followed by actual context label.
* fuse_secctx, name, context
*/
struct fuse_secctx {
uint32_t size;
uint32_t padding;
};
/*
* Contains the information about how many fuse_secctx structures are being
* sent and what's the total size of all security contexts (including
* size of fuse_secctx_header).
*
*/
struct fuse_secctx_header {
uint32_t size;
uint32_t nr_secctx;
};
#endif /* _LINUX_FUSE_H */
+97 -362
View File
@@ -25,6 +25,7 @@
#include "extern_c.h"
#include "fuse_common.h"
#include "fuse_kernel.h"
#include <fcntl.h>
#include <stdint.h>
@@ -117,12 +118,6 @@ struct fuse_ctx
mode_t umask;
};
struct fuse_forget_data
{
uint64_t ino;
uint64_t nlookup;
};
/* ----------------------------------------------------------- *
* Request methods and replies *
* ----------------------------------------------------------- */
@@ -183,7 +178,8 @@ struct fuse_lowlevel_ops
* @param parent inode number of the parent directory
* @param name the name to look up
*/
void (*lookup)(fuse_req_t req, uint64_t parent, const char *name);
void (*lookup)(fuse_req_t req,
struct fuse_in_header *hdr);
/**
* Forget about an inode
@@ -221,7 +217,8 @@ struct fuse_lowlevel_ops
* @param ino the inode number
* @param nlookup the number of lookups to forget
*/
void (*forget)(fuse_req_t req, uint64_t ino, uint64_t nlookup);
void (*forget)(fuse_req_t req,
struct fuse_in_header *hdr);
/**
* Get file attributes
@@ -229,13 +226,9 @@ struct fuse_lowlevel_ops
* Valid replies:
* fuse_reply_attr
* fuse_reply_err
*
* @param req request handle
* @param ino the inode number
* @param fi for future use, currently always NULL
*/
void (*getattr)(fuse_req_t req, uint64_t ino,
fuse_file_info_t *fi);
void (*getattr)(fuse_req_t req,
struct fuse_in_header *hdr);
/**
* Set file attributes
@@ -264,8 +257,8 @@ struct fuse_lowlevel_ops
* Changed in version 2.5:
* file information filled in for ftruncate
*/
void (*setattr)(fuse_req_t req, uint64_t ino, struct stat *attr,
int to_set, fuse_file_info_t *fi);
void (*setattr)(fuse_req_t req,
struct fuse_in_header *hdr);
/**
* Read symbolic link
@@ -277,7 +270,8 @@ struct fuse_lowlevel_ops
* @param req request handle
* @param ino the inode number
*/
void (*readlink)(fuse_req_t req, uint64_t ino);
void (*readlink)(fuse_req_t req,
struct fuse_in_header *hdr);
/**
* Create file node
@@ -295,8 +289,8 @@ struct fuse_lowlevel_ops
* @param mode file type and mode with which to create the new file
* @param rdev the device number (only valid if created file is a device)
*/
void (*mknod)(fuse_req_t req, uint64_t parent, const char *name,
mode_t mode, dev_t rdev);
void (*mknod)(fuse_req_t req,
struct fuse_in_header *hdr);
/**
* Create a directory
@@ -310,8 +304,8 @@ struct fuse_lowlevel_ops
* @param name to create
* @param mode with which to create the new file
*/
void (*mkdir)(fuse_req_t req, uint64_t parent, const char *name,
mode_t mode);
void (*mkdir)(fuse_req_t req,
struct fuse_in_header *hdr);
/**
* Remove a file
@@ -328,7 +322,8 @@ struct fuse_lowlevel_ops
* @param parent inode number of the parent directory
* @param name to remove
*/
void (*unlink)(fuse_req_t req, uint64_t parent, const char *name);
void (*unlink)(fuse_req_t req,
struct fuse_in_header *hdr);
/**
* Remove a directory
@@ -345,7 +340,8 @@ struct fuse_lowlevel_ops
* @param parent inode number of the parent directory
* @param name to remove
*/
void (*rmdir)(fuse_req_t req, uint64_t parent, const char *name);
void (*rmdir)(fuse_req_t req,
struct fuse_in_header *hdr);
/**
* Create a symbolic link
@@ -359,8 +355,8 @@ struct fuse_lowlevel_ops
* @param parent inode number of the parent directory
* @param name to create
*/
void (*symlink)(fuse_req_t req, const char *link, uint64_t parent,
const char *name);
void (*symlink)(fuse_req_t req,
struct fuse_in_header *hdr);
/** Rename a file
*
@@ -379,8 +375,8 @@ struct fuse_lowlevel_ops
* @param newparent inode number of the new parent directory
* @param newname new name
*/
void (*rename)(fuse_req_t req, uint64_t parent, const char *name,
uint64_t newparent, const char *newname);
void (*rename)(fuse_req_t req,
struct fuse_in_header *hdr);
/**
* Create a hard link
@@ -394,8 +390,8 @@ struct fuse_lowlevel_ops
* @param newparent inode number of the new parent directory
* @param newname new name to create
*/
void (*link)(fuse_req_t req, uint64_t ino, uint64_t newparent,
const char *newname);
void (*link)(fuse_req_t req,
struct fuse_in_header *hdr);
/**
* Open a file
@@ -422,8 +418,8 @@ struct fuse_lowlevel_ops
* @param ino the inode number
* @param fi file information
*/
void (*open)(fuse_req_t req, uint64_t ino,
fuse_file_info_t *fi);
void (*open)(fuse_req_t req,
struct fuse_in_header *hdr);
/**
* Read data
@@ -450,8 +446,8 @@ struct fuse_lowlevel_ops
* @param off offset to read from
* @param fi file information
*/
void (*read)(fuse_req_t req, uint64_t ino, size_t size, off_t off,
fuse_file_info_t *fi);
void (*read)(fuse_req_t req,
struct fuse_in_header *hdr);
/**
* Write data
@@ -476,8 +472,8 @@ struct fuse_lowlevel_ops
* @param off offset to write to
* @param fi file information
*/
void (*write)(fuse_req_t req, uint64_t ino, const char *buf,
size_t size, off_t off, fuse_file_info_t *fi);
void (*write)(fuse_req_t req,
struct fuse_in_header *hdr);
/**
* Flush method
@@ -508,8 +504,8 @@ struct fuse_lowlevel_ops
* @param ino the inode number
* @param fi file information
*/
void (*flush)(fuse_req_t req, uint64_t ino,
fuse_file_info_t *fi);
void (*flush)(fuse_req_t req,
struct fuse_in_header *hdr);
/**
* Release an open file
@@ -535,8 +531,8 @@ struct fuse_lowlevel_ops
* @param ino the inode number
* @param fi file information
*/
void (*release)(fuse_req_t req, uint64_t ino,
fuse_file_info_t *fi);
void (*release)(fuse_req_t req,
struct fuse_in_header *hdr);
/**
* Synchronize file contents
@@ -552,8 +548,8 @@ struct fuse_lowlevel_ops
* @param datasync flag indicating if only data should be flushed
* @param fi file information
*/
void (*fsync)(fuse_req_t req, uint64_t ino, int datasync,
fuse_file_info_t *fi);
void (*fsync)(fuse_req_t req,
struct fuse_in_header *hdr);
/**
* Open a directory
@@ -576,8 +572,8 @@ struct fuse_lowlevel_ops
* @param ino the inode number
* @param fi file information
*/
void (*opendir)(fuse_req_t req, uint64_t ino,
fuse_file_info_t *fi);
void (*opendir)(fuse_req_t req,
struct fuse_in_header *hdr);
/**
* Read directory
@@ -600,12 +596,11 @@ struct fuse_lowlevel_ops
* @param off offset to continue reading the directory stream
* @param fi file information
*/
void (*readdir)(fuse_req_t req, uint64_t ino, size_t size, off_t off,
fuse_file_info_t *llffi);
void (*readdir)(fuse_req_t req,
struct fuse_in_header *hdr);
void (*readdir_plus)(fuse_req_t req, uint64_t ino,
size_t size, off_t off,
fuse_file_info_t *ffi);
void (*readdir_plus)(fuse_req_t req,
struct fuse_in_header *hdr);
/**
* Release an open directory
@@ -623,8 +618,8 @@ struct fuse_lowlevel_ops
* @param ino the inode number
* @param fi file information
*/
void (*releasedir)(fuse_req_t req, uint64_t ino,
fuse_file_info_t *fi);
void (*releasedir)(fuse_req_t req,
struct fuse_in_header *hdr);
/**
* Synchronize directory contents
@@ -643,8 +638,8 @@ struct fuse_lowlevel_ops
* @param datasync flag indicating if only data should be flushed
* @param fi file information
*/
void (*fsyncdir)(fuse_req_t req, uint64_t ino, int datasync,
fuse_file_info_t *fi);
void (*fsyncdir)(fuse_req_t req,
struct fuse_in_header *hdr);
/**
* Get file system statistics
@@ -656,7 +651,8 @@ struct fuse_lowlevel_ops
* @param req request handle
* @param ino the inode number, zero means "undefined"
*/
void (*statfs)(fuse_req_t req, uint64_t ino);
void (*statfs)(fuse_req_t req,
struct fuse_in_header *hdr);
/**
* Set an extended attribute
@@ -664,8 +660,8 @@ struct fuse_lowlevel_ops
* Valid replies:
* fuse_reply_err
*/
void (*setxattr)(fuse_req_t req, uint64_t ino, const char *name,
const char *value, size_t size, int flags);
void (*setxattr)(fuse_req_t req,
struct fuse_in_header *hdr);
/**
* Get an extended attribute
@@ -690,8 +686,8 @@ struct fuse_lowlevel_ops
* @param name of the extended attribute
* @param size maximum size of the value to send
*/
void (*getxattr)(fuse_req_t req, uint64_t ino, const char *name,
size_t size);
void (*getxattr)(fuse_req_t req,
struct fuse_in_header *hdr);
/**
* List extended attribute names
@@ -716,7 +712,8 @@ struct fuse_lowlevel_ops
* @param ino the inode number
* @param size maximum size of the list to send
*/
void (*listxattr)(fuse_req_t req, uint64_t ino, size_t size);
void (*listxattr)(fuse_req_t req,
struct fuse_in_header *hdr);
/**
* Remove an extended attribute
@@ -728,7 +725,8 @@ struct fuse_lowlevel_ops
* @param ino the inode number
* @param name of the extended attribute
*/
void (*removexattr)(fuse_req_t req, uint64_t ino, const char *name);
void (*removexattr)(fuse_req_t req,
const struct fuse_in_header *hdr);
/**
* Check file access permissions
@@ -748,7 +746,8 @@ struct fuse_lowlevel_ops
* @param ino the inode number
* @param mask requested access mode
*/
void (*access)(fuse_req_t req, uint64_t ino, int mask);
void (*access)(fuse_req_t req,
struct fuse_in_header *hdr);
/**
* Create and open a file
@@ -783,8 +782,8 @@ struct fuse_lowlevel_ops
* @param mode file type and mode with which to create the new file
* @param fi file information
*/
void (*create)(fuse_req_t req, uint64_t parent, const char *name,
mode_t mode, fuse_file_info_t *fi);
void (*create)(fuse_req_t req,
struct fuse_in_header *hdr);
/**
* Test for a POSIX file lock
@@ -800,9 +799,8 @@ struct fuse_lowlevel_ops
* @param fi file information
* @param lock the region/type to test
*/
void (*getlk)(fuse_req_t req, uint64_t ino,
fuse_file_info_t *fi, struct flock *lock);
void (*getlk)(fuse_req_t req,
const struct fuse_in_header *hdr);
/**
* Acquire, modify or release a POSIX file lock
*
@@ -848,8 +846,8 @@ struct fuse_lowlevel_ops
* @param blocksize unit of block index
* @param idx block index within file
*/
void (*bmap)(fuse_req_t req, uint64_t ino, size_t blocksize,
uint64_t idx);
void (*bmap)(fuse_req_t req,
const struct fuse_in_header *hdr);
/**
* Ioctl
@@ -878,9 +876,8 @@ struct fuse_lowlevel_ops
* @param in_bufsz number of fetched bytes
* @param out_bufsz maximum size of output data
*/
void (*ioctl)(fuse_req_t req, uint64_t ino, unsigned long cmd, void *arg,
fuse_file_info_t *fi, unsigned flags,
const void *in_buf, uint32_t in_bufsz, uint32_t out_bufsz);
void (*ioctl)(fuse_req_t req,
const struct fuse_in_header *hdr);
/**
* Poll for IO readiness
@@ -908,40 +905,8 @@ struct fuse_lowlevel_ops
* @param fi file information
* @param ph poll handle to be used for notification
*/
void (*poll)(fuse_req_t req,
uint64_t ino,
fuse_file_info_t *fi,
fuse_pollhandle_t *ph);
/**
* Write data made available in a buffer
*
* This is a more generic version of the ->write() method. If
* FUSE_CAP_SPLICE_READ is set in fuse_conn_info.want and the
* kernel supports splicing from the fuse device, then the
* data will be made available in pipe for supporting zero
* copy data transfer.
*
* buf->count is guaranteed to be one (and thus buf->idx is
* always zero). The write_buf handler must ensure that
* bufv->off is correctly updated (reflecting the number of
* bytes read from bufv->buf[0]).
*
* Introduced in version 2.9
*
* Valid replies:
* fuse_reply_write
* fuse_reply_err
*
* @param req request handle
* @param ino the inode number
* @param bufv buffer containing the data
* @param off offset to write to
* @param fi file information
*/
void (*write_buf)(fuse_req_t req, uint64_t ino,
struct fuse_bufvec *bufv, off_t off,
fuse_file_info_t *fi);
void (*poll)(fuse_req_t req,
const struct fuse_in_header *hdr);
/**
* Callback function for the retrieve request
@@ -957,8 +922,10 @@ struct fuse_lowlevel_ops
* @param offset the offset supplied to fuse_lowlevel_notify_retrieve()
* @param bufv the buffer containing the returned data
*/
void (*retrieve_reply)(fuse_req_t req, void *cookie, uint64_t ino,
off_t offset, struct fuse_bufvec *bufv);
void (*retrieve_reply)(fuse_req_t req,
void *cookie,
uint64_t ino,
off_t offset);
/**
* Forget about multiple inodes
@@ -973,8 +940,8 @@ struct fuse_lowlevel_ops
*
* @param req request handle
*/
void (*forget_multi)(fuse_req_t req, size_t count,
struct fuse_forget_data *forgets);
void (*forget_multi)(fuse_req_t req,
struct fuse_in_header *hdr);
/**
* Acquire, modify or release a BSD file lock
@@ -1013,8 +980,8 @@ struct fuse_lowlevel_ops
* @param mode determines the operation to be performed on the given range,
* see fallocate(2)
*/
void (*fallocate)(fuse_req_t req, uint64_t ino, int mode,
off_t offset, off_t length, fuse_file_info_t *fi);
void (*fallocate)(fuse_req_t req,
const struct fuse_in_header *hdr);
/**
* Copy a range of data from one file to another
@@ -1052,15 +1019,8 @@ struct fuse_lowlevel_ops
* @param len maximum size of the data to copy
* @param flags passed along with the copy_file_range() syscall
*/
void (*copy_file_range)(fuse_req_t req,
uint64_t ino_in,
off_t off_in,
fuse_file_info_t *fi_in,
uint64_t ino_out,
off_t off_out,
fuse_file_info_t *fi_out,
size_t len,
int flags);
void (*copy_file_range)(fuse_req_t req,
const struct fuse_in_header *hdr);
};
/**
@@ -1163,7 +1123,8 @@ int fuse_reply_readlink(fuse_req_t req, const char *link);
* @param fi file information
* @return zero for success, -errno for failure to send reply
*/
int fuse_reply_open(fuse_req_t req, const fuse_file_info_t *fi);
int fuse_reply_open(fuse_req_t req,
const fuse_file_info_t *fi);
/**
* Reply with number of bytes written
@@ -1503,231 +1464,30 @@ struct fuse_session *fuse_lowlevel_new(struct fuse_args *args,
* Session interface *
* ----------------------------------------------------------- */
/**
* Session operations
*
* This is used in session creation
*/
struct fuse_session_ops
{
/**
* Hook to process a request (mandatory)
*
* @param data user data passed to fuse_session_new()
* @param buf buffer containing the raw request
* @param len request length
* @param ch channel on which the request was received
*/
void (*process)(void *data, const char *buf, size_t len,
struct fuse_chan *ch);
/**
* Hook for session exit and reset (optional)
*
* @param data user data passed to fuse_session_new()
* @param val exited status (1 - exited, 0 - not exited)
*/
void (*exit)(void *data, int val);
/**
* Hook for querying the current exited status (optional)
*
* @param data user data passed to fuse_session_new()
* @return 1 if exited, 0 if not exited
*/
int (*exited)(void *data);
/**
* Hook for cleaning up the channel on destroy (optional)
*
* @param data user data passed to fuse_session_new()
*/
void (*destroy)(void *data);
};
/**
* Create a new session
*
* @param op session operations
* @param data user data
* @return new session object, or NULL on failure
*/
struct fuse_session *fuse_session_new(struct fuse_session_ops *op, void *data);
/**
* Assign a channel to a session
*
* Note: currently only a single channel may be assigned. This may
* change in the future
*
* If a session is destroyed, the assigned channel is also destroyed
*
* @param se the session
* @param ch the channel
*/
struct fuse_session *fuse_session_new(void *data,
void *receive_buf,
void *process_buf,
void *destroy);
void fuse_session_add_chan(struct fuse_session *se, struct fuse_chan *ch);
/**
* Remove a channel from a session
*
* If the channel is not assigned to a session, then this is a no-op
*
* @param ch the channel to remove
*/
void fuse_session_remove_chan(struct fuse_chan *ch);
/**
* Iterate over the channels assigned to a session
*
* The iterating function needs to start with a NULL channel, and
* after that needs to pass the previously returned channel to the
* function.
*
* @param se the session
* @param ch the previous channel, or NULL
* @return the next channel, or NULL if no more channels exist
*/
struct fuse_chan *fuse_session_next_chan(struct fuse_session *se,
struct fuse_chan *ch);
/**
* Process a raw request
*
* @param se the session
* @param buf buffer containing the raw request
* @param len request length
* @param ch channel on which the request was received
*/
void fuse_session_process(struct fuse_session *se, const char *buf, size_t len,
struct fuse_chan *ch);
/**
* Process a raw request supplied in a generic buffer
*
* This is a more generic version of fuse_session_process(). The
* fuse_buf may contain a memory buffer or a pipe file descriptor.
*
* @param se the session
* @param buf the fuse_buf containing the request
* @param ch channel on which the request was received
*/
void fuse_session_process_buf(struct fuse_session *se,
const struct fuse_buf *buf, struct fuse_chan *ch);
/**
* Receive a raw request supplied in a generic buffer
*
* This is a more generic version of fuse_chan_recv(). The fuse_buf
* supplied to this function contains a suitably allocated memory
* buffer. This may be overwritten with a file descriptor buffer.
*
* @param se the session
* @param buf the fuse_buf to store the request in
* @param chp pointer to the channel
* @return the actual size of the raw request, or -errno on error
*/
int fuse_session_receive_buf(struct fuse_session *se, struct fuse_buf *buf,
struct fuse_chan **chp);
/**
* Destroy a session
*
* @param se the session
*/
void fuse_session_destroy(struct fuse_session *se);
/**
* Exit a session
*
* @param se the session
*/
void fuse_session_exit(struct fuse_session *se);
/**
* Reset the exited status of a session
*
* @param se the session
*/
void fuse_session_reset(struct fuse_session *se);
/**
* Query the exited status of a session
*
* @param se the session
* @return 1 if exited, 0 if not exited
*/
int fuse_session_exited(struct fuse_session *se);
/**
* Get the user data provided to the session
*
* @param se the session
* @return the user data
*/
void fuse_session_reset(struct fuse_session *se);
void *fuse_session_data(struct fuse_session *se);
int fuse_session_receive(struct fuse_session *se,
struct fuse_buf *buf);
void fuse_session_process(struct fuse_session *se,
const void *buf,
const size_t bufsize);
/**
* Enter a multi-threaded event loop
*
* @param se the session
* @return 0 on success, -1 on error
*/
int fuse_session_loop_mt(struct fuse_session *se, const int threads);
/* ----------------------------------------------------------- *
* Channel interface *
* ----------------------------------------------------------- */
/**
* Channel operations
*
* This is used in channel creation
*/
struct fuse_chan_ops
{
/**
* Hook for receiving a raw request
*
* @param ch pointer to the channel
* @param buf the buffer to store the request in
* @param size the size of the buffer
* @return the actual size of the raw request, or -1 on error
*/
int (*receive)(struct fuse_chan **chp, char *buf, size_t size);
/**
* Hook for sending a raw reply
*
* A return value of -ENOENT means, that the request was
* interrupted, and the reply was discarded
*
* @param ch the channel
* @param iov vector of blocks
* @param count the number of blocks in vector
* @return zero on success, -errno on failure
*/
int (*send)(struct fuse_chan *ch, const struct iovec iov[],
size_t count);
/**
* Destroy the channel
*
* @param ch the channel
*/
void (*destroy)(struct fuse_chan *ch);
};
/**
* Create a new channel
*
* @param op channel operations
* @param fd file descriptor of the channel
* @param bufsize the minimal receive buffer size
* @param data user data
* @return the new channel object, or NULL on failure
*/
struct fuse_chan *fuse_chan_new(struct fuse_chan_ops *op, int fd,
size_t bufsize, void *data);
struct fuse_chan *fuse_chan_new(int fd, size_t bufsize);
/**
* Query the file descriptor of the channel
@@ -1761,37 +1521,12 @@ void *fuse_chan_data(struct fuse_chan *ch);
*/
struct fuse_session *fuse_chan_session(struct fuse_chan *ch);
/**
* Receive a raw request
*
* A return value of -ENODEV means, that the filesystem was unmounted
*
* @param ch pointer to the channel
* @param buf the buffer to store the request in
* @param size the size of the buffer
* @return the actual size of the raw request, or -errno on error
*/
int fuse_chan_recv(struct fuse_chan **ch, char *buf, size_t size);
/**
* Send a raw reply
*
* A return value of -ENOENT means, that the request was
* interrupted, and the reply was discarded
*
* @param ch the channel
* @param iov vector of blocks
* @param count the number of blocks in vector
* @return zero on success, -errno on failure
*/
int fuse_chan_send(struct fuse_chan *ch, const struct iovec iov[],
int fuse_chan_recv(struct fuse_chan *ch,
char *buf,
size_t size);
int fuse_chan_send(struct fuse_chan *ch,
const struct iovec iov[],
size_t count);
/**
* Destroy a channel
*
* @param ch the channel
*/
void fuse_chan_destroy(struct fuse_chan *ch);
EXTERN_C_END
+14
View File
@@ -0,0 +1,14 @@
#pragma once
#include <stdint.h>
struct fuse_chan;
struct fuse_ll;
typedef struct fuse_pollhandle_t fuse_pollhandle_t;
struct fuse_pollhandle_t
{
uint64_t kh;
struct fuse_chan *ch;
struct fuse_ll *f;
};
+1 -2
View File
@@ -182,8 +182,7 @@ static ssize_t fuse_buf_splice(const struct fuse_buf *dst, size_t dst_off,
}
while (len) {
res = splice(src->fd, srcpos, dst->fd, dstpos, len,
splice_flags);
res = splice(src->fd, srcpos, dst->fd, dstpos, len, splice_flags);
if (res == -1) {
if (copied)
break;
+54 -38
View File
@@ -249,6 +249,14 @@ fmp_avail_objs(fmp_t *fmp_)
return fmp_->avail_objs;
}
static
inline
uint64_t
fmp_objs_per_slab(fmp_t *fmp_)
{
return (fmp_->slab_size / fmp_->obj_size);
}
static
inline
uint64_t
@@ -256,15 +264,19 @@ fmp_objs_in_slab(fmp_t *fmp_,
void *slab_)
{
char *slab;
uint64_t objs_per_slab;
uint64_t objs_in_slab;
objs_in_slab = 0;
slab = (char*)slab_;
slab = (char*)slab_;
objs_in_slab = 0;
objs_per_slab = fmp_objs_per_slab(fmp_);
for(mem_stack_t *stack = fmp_->objs; stack != NULL; stack = stack->next)
{
char *obj = (char*)stack;
if((obj >= slab) && (obj < (slab + fmp_->slab_size)))
objs_in_slab++;
if(objs_in_slab >= objs_per_slab)
break;
}
return objs_in_slab;
@@ -276,17 +288,27 @@ void
fmp_remove_objs_in_slab(fmp_t *fmp_,
void *slab_)
{
char *slab = (char*)slab_;
mem_stack_t **p = &fmp_->objs;
char *slab;
uint64_t objs_per_slab;
uint64_t objs_in_slab;
mem_stack_t **p;
p = &fmp_->objs;
slab = (char*)slab_;
objs_in_slab = 0;
objs_per_slab = fmp_objs_per_slab(fmp_);
while((*p) != NULL)
{
char *obj = (char*)*p;
if((obj >= slab) && (obj < (slab + fmp_->slab_size)))
{
objs_in_slab++;
*p = (*p)->next;
fmp_->avail_objs--;
if(objs_in_slab >= objs_per_slab)
break;
continue;
}
@@ -297,47 +319,40 @@ fmp_remove_objs_in_slab(fmp_t *fmp_,
static
inline
int
fmp_gc(fmp_t *fmp_)
fmp_gc_slab(fmp_t *fmp_,
uint64_t slab_idx_)
{
int i;
int freed_slabs;
char *slab;
uint64_t objs_in_slab;
uint64_t objs_per_slab;
objs_per_slab = (fmp_->slab_size / fmp_->obj_size);
slab_idx_ = (slab_idx_ % kv_size(fmp_->slabs));
i = 0;
freed_slabs = 0;
while(i < kv_size(fmp_->slabs))
{
char *slab;
uint64_t objs_in_slab;
slab = kv_A(fmp_->slabs,slab_idx_);
slab = kv_A(fmp_->slabs,i);
objs_per_slab = fmp_objs_per_slab(fmp_);
objs_in_slab = fmp_objs_in_slab(fmp_,slab);
if(objs_in_slab != objs_per_slab)
return 0;
objs_in_slab = fmp_objs_in_slab(fmp_,slab);
if(objs_in_slab != objs_per_slab)
{
i++;
continue;
}
fmp_remove_objs_in_slab(fmp_,slab);
kv_delete(fmp_->slabs,slab_idx_);
fmp_slab_free_mmap(fmp_,slab);
fmp_remove_objs_in_slab(fmp_,slab);
kv_delete(fmp_->slabs,i);
fmp_slab_free_mmap(fmp_,slab);
freed_slabs++;
}
return freed_slabs;
return 1;
}
static
inline
uint64_t
fmp_objs_per_slab(fmp_t *fmp_)
int
fmp_gc(fmp_t *fmp_)
{
return (fmp_->slab_size / fmp_->obj_size);
uint64_t slab_idx;
slab_idx = rand();
return fmp_gc_slab(fmp_,slab_idx);
}
static
@@ -345,14 +360,15 @@ inline
double
fmp_slab_usage_ratio(fmp_t *fmp_)
{
double rv;
uint64_t objs_per_slab;
double avail_objs;
double objs_per_slab;
double nums_of_slabs;
avail_objs = fmp_->avail_objs;
objs_per_slab = fmp_objs_per_slab(fmp_);
nums_of_slabs = kv_size(fmp_->slabs);
rv = ((double)fmp_->avail_objs / (double)objs_per_slab);
return rv;
return (avail_objs / (objs_per_slab * nums_of_slabs));
}
static
+754 -905
View File
File diff suppressed because it is too large Load Diff
+14 -9
View File
@@ -11,23 +11,25 @@
#include "fuse.h"
#include "fuse_lowlevel.h"
#include "extern_c.h"
struct fuse_chan;
struct fuse_ll;
struct fuse_session
{
struct fuse_session_ops op;
int (*receive_buf)(struct fuse_session *se,
struct fuse_buf *buf,
struct fuse_chan *ch);
int (*receive_buf)(struct fuse_session *se, struct fuse_buf *buf,
struct fuse_chan **chp);
void (*process_buf)(void *data, const struct fuse_buf *buf,
void (*process_buf)(void *data,
const void *buf,
struct fuse_chan *ch);
void (*destroy)(void *data);
void *data;
volatile int exited;
struct fuse_chan *ch;
};
@@ -46,8 +48,7 @@ struct fuse_notify_req
void (*reply)(struct fuse_notify_req *,
fuse_req_t,
uint64_t,
const void *,
const struct fuse_buf *);
const void *);
struct fuse_notify_req *next;
struct fuse_notify_req *prev;
};
@@ -84,6 +85,8 @@ struct fuse_cmd
struct fuse_chan *ch;
};
EXTERN_C_BEGIN
struct fuse *fuse_new_common(struct fuse_chan *ch, struct fuse_args *args,
const struct fuse_operations *op,
size_t op_size);
@@ -111,3 +114,5 @@ struct fuse *fuse_setup_common(int argc, char *argv[],
int *fd);
int fuse_start_thread(pthread_t *thread_id, void *(*func)(void *), void *arg);
EXTERN_C_END
-103
View File
@@ -1,103 +0,0 @@
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB
*/
#include "fuse_lowlevel.h"
#include "fuse_kernel.h"
#include "fuse_i.h"
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <assert.h>
static int fuse_kern_chan_receive(struct fuse_chan **chp, char *buf,
size_t size)
{
struct fuse_chan *ch = *chp;
int err;
ssize_t res;
struct fuse_session *se = fuse_chan_session(ch);
assert(se != NULL);
restart:
res = read(fuse_chan_fd(ch), buf, size);
err = errno;
if (fuse_session_exited(se))
return 0;
if (res == -1) {
/* ENOENT means the operation was interrupted, it's safe
to restart */
if (err == ENOENT)
goto restart;
if (err == ENODEV) {
fuse_session_exit(se);
return 0;
}
/* Errors occurring during normal operation: EINTR (read
interrupted), EAGAIN (nonblocking I/O), ENODEV (filesystem
umounted) */
if (err != EINTR && err != EAGAIN)
perror("fuse: reading device");
return -err;
}
if ((size_t) res < sizeof(struct fuse_in_header)) {
fprintf(stderr, "short read on fuse device\n");
return -EIO;
}
return res;
}
static int fuse_kern_chan_send(struct fuse_chan *ch, const struct iovec iov[],
size_t count)
{
if (iov) {
ssize_t res = writev(fuse_chan_fd(ch), iov, count);
int err = errno;
if (res == -1) {
struct fuse_session *se = fuse_chan_session(ch);
assert(se != NULL);
/* ENOENT means the operation was interrupted */
if (!fuse_session_exited(se) && err != ENOENT)
perror("fuse: writing device");
return -err;
}
}
return 0;
}
static void fuse_kern_chan_destroy(struct fuse_chan *ch)
{
int fd = fuse_chan_fd(ch);
if (fd != -1)
close(fd);
}
struct fuse_chan *
fuse_kern_chan_new(int fd_)
{
long pagesize;
size_t bufsize;
struct fuse_chan_ops op =
{
.receive = fuse_kern_chan_receive,
.send = fuse_kern_chan_send,
.destroy = fuse_kern_chan_destroy,
};
pagesize = sysconf(_SC_PAGESIZE);
bufsize = ((FUSE_MAX_MAX_PAGES * pagesize) + 0x1000);
return fuse_chan_new(&op, fd_, bufsize, NULL);
}
@@ -6,6 +6,8 @@
See the file COPYING.LIB.
*/
#include "pool.hpp"
#include "fuse_i.h"
#include "fuse_kernel.h"
#include "fuse_lowlevel.h"
@@ -37,7 +39,6 @@ struct fuse_worker
struct fuse_mt
{
struct fuse_session *se;
struct fuse_chan *prevch;
struct fuse_worker main;
sem_t finish;
int exit;
@@ -66,6 +67,8 @@ static void list_del_worker(struct fuse_worker *w)
static int fuse_loop_start_thread(struct fuse_mt *mt);
thread_pool tp;
static
void*
fuse_do_work(void *data)
@@ -76,29 +79,34 @@ fuse_do_work(void *data)
while(!fuse_session_exited(mt->se))
{
int res;
struct fuse_buf fbuf;
struct fuse_chan *ch = mt->prevch;
struct fuse_buf fbuf = {0};
fbuf = (struct fuse_buf){ .mem = w->buf,
.size = w->bufsize };
fbuf.mem = (char*)malloc(w->bufsize);
fbuf.size = w->bufsize;
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
res = fuse_session_receive_buf(mt->se, &fbuf, &ch);
res = mt->se->receive_buf(mt->se,&fbuf,mt->se->ch);
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
if(res == -EINTR)
continue;
if(res <= 0) {
if(res < 0) {
fuse_session_exit(mt->se);
mt->error = -1;
if(res <= 0)
{
if(res < 0)
{
mt->se->exited = 1;
mt->error = -1;
}
break;
}
break;
}
if(mt->exit)
return NULL;
fuse_session_process_buf(mt->se, &fbuf, ch);
tp.enqueue_work([=] {
mt->se->process_buf(mt->se->data,fbuf.mem,mt->se->ch);
free(fbuf.mem);
});
}
sem_post(&mt->finish);
@@ -138,14 +146,14 @@ int fuse_start_thread(pthread_t *thread_id, void *(*func)(void *), void *arg)
static int fuse_loop_start_thread(struct fuse_mt *mt)
{
int res;
struct fuse_worker *w = malloc(sizeof(struct fuse_worker));
struct fuse_worker *w = (struct fuse_worker*)malloc(sizeof(struct fuse_worker));
if(!w) {
fprintf(stderr, "fuse: failed to allocate worker structure\n");
return -1;
}
memset(w, 0, sizeof(struct fuse_worker));
w->bufsize = fuse_chan_bufsize(mt->prevch);
w->buf = calloc(w->bufsize,1);
w->bufsize = fuse_chan_bufsize(mt->se->ch);
w->buf = (char*)calloc(w->bufsize,1);
w->mt = mt;
if(!w->buf) {
fprintf(stderr, "fuse: failed to allocate read buffer\n");
@@ -193,7 +201,6 @@ fuse_session_loop_mt(struct fuse_session *se_,
memset(&mt,0,sizeof(struct fuse_mt));
mt.se = se_;
mt.prevch = fuse_session_next_chan(se_,NULL);
mt.error = 0;
mt.main.thread_id = pthread_self();
mt.main.prev = mt.main.next = &mt.main;
File diff suppressed because it is too large Load Diff
+2 -92
View File
@@ -16,98 +16,8 @@
#include <pthread.h>
#include <assert.h>
struct procdata
{
struct fuse *f;
struct fuse_chan *prevch;
struct fuse_session *prevse;
fuse_processor_t proc;
void *data;
};
static void mt_session_proc(void *data, const char *buf, size_t len,
struct fuse_chan *ch)
{
struct procdata *pd = (struct procdata *) data;
struct fuse_cmd *cmd = *(struct fuse_cmd **) buf;
(void) len;
(void) ch;
pd->proc(pd->f, cmd, pd->data);
}
static void mt_session_exit(void *data, int val)
{
struct procdata *pd = (struct procdata *) data;
if (val)
fuse_session_exit(pd->prevse);
else
fuse_session_reset(pd->prevse);
}
static int mt_session_exited(void *data)
{
struct procdata *pd = (struct procdata *) data;
return fuse_session_exited(pd->prevse);
}
static int mt_chan_receive(struct fuse_chan **chp, char *buf, size_t size)
{
struct fuse_cmd *cmd;
struct procdata *pd = (struct procdata *) fuse_chan_data(*chp);
assert(size >= sizeof(cmd));
cmd = fuse_read_cmd(pd->f);
if (cmd == NULL)
return 0;
*(struct fuse_cmd **)buf = cmd;
return sizeof(cmd);
}
int fuse_loop_mt_proc(struct fuse *f, fuse_processor_t proc, void *data)
{
int res;
struct procdata pd;
struct fuse_session *prevse = fuse_get_session(f);
struct fuse_session *se;
struct fuse_chan *prevch = fuse_session_next_chan(prevse, NULL);
struct fuse_chan *ch;
struct fuse_session_ops sop = {
.exit = mt_session_exit,
.exited = mt_session_exited,
.process = mt_session_proc,
};
struct fuse_chan_ops cop = {
.receive = mt_chan_receive,
};
pd.f = f;
pd.prevch = prevch;
pd.prevse = prevse;
pd.proc = proc;
pd.data = data;
se = fuse_session_new(&sop, &pd);
if (se == NULL)
return -1;
ch = fuse_chan_new(&cop, fuse_chan_fd(prevch),
sizeof(struct fuse_cmd *), &pd);
if (ch == NULL) {
fuse_session_destroy(se);
return -1;
}
fuse_session_add_chan(se, ch);
res = fuse_session_loop_mt(se,
fuse_config_num_threads(f));
fuse_session_destroy(se);
return res;
}
int fuse_loop_mt(struct fuse *f)
int
fuse_loop_mt(struct fuse *f)
{
if (f == NULL)
return -1;
+114 -102
View File
@@ -8,23 +8,28 @@
#include "fuse_i.h"
#include "fuse_misc.h"
#include "fuse_kernel.h"
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <unistd.h>
#include <sys/uio.h>
struct fuse_chan
{
struct fuse_chan_ops op;
struct fuse_session *se;
int fd;
size_t bufsize;
void *data;
};
struct fuse_session *fuse_session_new(struct fuse_session_ops *op, void *data)
struct fuse_session *fuse_session_new(void *data,
void *receive_buf,
void *process_buf,
void *destroy)
{
struct fuse_session *se = (struct fuse_session *) malloc(sizeof(*se));
if (se == NULL) {
@@ -33,8 +38,10 @@ struct fuse_session *fuse_session_new(struct fuse_session_ops *op, void *data)
}
memset(se, 0, sizeof(*se));
se->op = *op;
se->data = data;
se->receive_buf = receive_buf;
se->process_buf = process_buf;
se->destroy = destroy;
return se;
}
@@ -57,79 +64,30 @@ void fuse_session_remove_chan(struct fuse_chan *ch)
}
}
struct fuse_chan *fuse_session_next_chan(struct fuse_session *se,
struct fuse_chan *ch)
void
fuse_session_destroy(struct fuse_session *se)
{
assert(ch == NULL || ch == se->ch);
if (ch == NULL)
return se->ch;
else
return NULL;
}
void fuse_session_process(struct fuse_session *se, const char *buf, size_t len,
struct fuse_chan *ch)
{
se->op.process(se->data, buf, len, ch);
}
void fuse_session_process_buf(struct fuse_session *se,
const struct fuse_buf *buf, struct fuse_chan *ch)
{
if (se->process_buf) {
se->process_buf(se->data, buf, ch);
} else {
assert(!(buf->flags & FUSE_BUF_IS_FD));
fuse_session_process(se->data, buf->mem, buf->size, ch);
}
}
int fuse_session_receive_buf(struct fuse_session *se, struct fuse_buf *buf,
struct fuse_chan **chp)
{
int res;
if (se->receive_buf) {
res = se->receive_buf(se, buf, chp);
} else {
res = fuse_chan_recv(chp, buf->mem, buf->size);
if (res > 0)
buf->size = res;
}
return res;
}
void fuse_session_destroy(struct fuse_session *se)
{
if (se->op.destroy)
se->op.destroy(se->data);
if (se->ch != NULL)
se->destroy(se->data);
if(se->ch != NULL)
fuse_chan_destroy(se->ch);
free(se);
}
void fuse_session_exit(struct fuse_session *se)
{
if (se->op.exit)
se->op.exit(se->data, 1);
se->exited = 1;
}
void fuse_session_reset(struct fuse_session *se)
{
if (se->op.exit)
se->op.exit(se->data, 0);
se->exited = 0;
}
int fuse_session_exited(struct fuse_session *se)
int
fuse_session_exited(struct fuse_session *se)
{
if (se->op.exited)
return se->op.exited(se->data);
else
return se->exited;
return se->exited;
}
void
fuse_session_exit(struct fuse_session *se_)
{
se_->exited = 1;
}
void *fuse_session_data(struct fuse_session *se)
@@ -137,30 +95,27 @@ void *fuse_session_data(struct fuse_session *se)
return se->data;
}
static struct fuse_chan *fuse_chan_new_common(struct fuse_chan_ops *op, int fd,
size_t bufsize, void *data)
struct fuse_chan *
fuse_chan_new(int fd,
size_t bufsize)
{
struct fuse_chan *ch = (struct fuse_chan *) malloc(sizeof(*ch));
if (ch == NULL) {
fprintf(stderr, "fuse: failed to allocate channel\n");
return NULL;
}
struct fuse_chan *ch;
ch = (struct fuse_chan*)malloc(sizeof(*ch));
if(ch == NULL)
{
fprintf(stderr, "fuse: failed to allocate channel\n");
return NULL;
}
memset(ch, 0, sizeof(*ch));
ch->op = *op;
ch->fd = fd;
ch->bufsize = bufsize;
ch->data = data;
return ch;
}
struct fuse_chan *fuse_chan_new(struct fuse_chan_ops *op, int fd,
size_t bufsize, void *data)
{
return fuse_chan_new_common(op, fd, bufsize, data);
}
int fuse_chan_fd(struct fuse_chan *ch)
{
return ch->fd;
@@ -178,40 +133,97 @@ size_t fuse_chan_bufsize(struct fuse_chan *ch)
return ch->bufsize;
}
void *fuse_chan_data(struct fuse_chan *ch)
{
return ch->data;
}
struct fuse_session *fuse_chan_session(struct fuse_chan *ch)
{
return ch->se;
}
int fuse_chan_recv(struct fuse_chan **chp, char *buf, size_t size)
int
fuse_chan_recv(struct fuse_chan *ch,
char *buf,
size_t size)
{
struct fuse_chan *ch = *chp;
int err;
ssize_t res;
struct fuse_session *se = fuse_chan_session(ch);
assert(se != NULL);
return ch->op.receive(chp, buf, size);
restart:
res = read(fuse_chan_fd(ch), buf, size);
err = errno;
if(fuse_session_exited(se))
return 0;
if(res == -1)
{
/* ENOENT means the operation was interrupted, it's safe
to restart */
if (err == ENOENT)
goto restart;
if(err == ENODEV)
{
se->exited = 1;
return 0;
}
/* Errors occurring during normal operation: EINTR (read
interrupted), EAGAIN (nonblocking I/O), ENODEV (filesystem
umounted) */
if(err != EINTR && err != EAGAIN)
perror("fuse: reading device");
return -err;
}
if((size_t) res < sizeof(struct fuse_in_header))
{
fprintf(stderr, "short read on fuse device\n");
return -EIO;
}
return res;
}
int fuse_chan_receive(struct fuse_chan *ch, char *buf, size_t size)
int
fuse_chan_send(struct fuse_chan *ch,
const struct iovec iov[],
size_t count)
{
int res;
if(!iov)
return 0;
res = fuse_chan_recv(&ch, buf, size);
return res >= 0 ? res : (res != -EINTR && res != -EAGAIN) ? -1 : 0;
int err;
ssize_t res;
res = writev(fuse_chan_fd(ch), iov, count);
err = errno;
if(res == -1)
{
struct fuse_session *se = fuse_chan_session(ch);
assert(se != NULL);
/* ENOENT means the operation was interrupted */
if(!fuse_session_exited(se) && err != ENOENT)
perror("fuse: writing device");
return -err;
}
return 0;
}
int fuse_chan_send(struct fuse_chan *ch, const struct iovec iov[], size_t count)
void
fuse_chan_destroy(struct fuse_chan *ch)
{
return ch->op.send(ch, iov, count);
}
int fd;
void fuse_chan_destroy(struct fuse_chan *ch)
{
fuse_session_remove_chan(ch);
if (ch->op.destroy)
ch->op.destroy(ch);
fd = fuse_chan_fd(ch);
if(fd != -1)
close(fd);
free(ch);
}
+15 -10
View File
@@ -40,8 +40,6 @@ static
const
struct fuse_opt fuse_helper_opts[] =
{
FUSE_HELPER_OPT("-d", foreground),
FUSE_HELPER_OPT("debug", foreground),
FUSE_HELPER_OPT("-f", foreground),
FUSE_HELPER_OPT("fsname=", nodefault_subtype),
FUSE_HELPER_OPT("subtype=", nodefault_subtype),
@@ -239,8 +237,10 @@ struct fuse_chan *
fuse_mount_common(const char *mountpoint_,
struct fuse_args *args_)
{
struct fuse_chan *ch;
int fd;
long bufsize;
long pagesize;
struct fuse_chan *ch;
/*
* Make sure file descriptors 0, 1 and 2 are open, otherwise chaos
@@ -257,7 +257,10 @@ fuse_mount_common(const char *mountpoint_,
if(fd == -1)
return NULL;
ch = fuse_kern_chan_new(fd);
pagesize = sysconf(_SC_PAGESIZE);
bufsize = ((FUSE_MAX_MAX_PAGES + 1) * pagesize);
ch = fuse_chan_new(fd,bufsize);
if(!ch)
fuse_kern_unmount(mountpoint_, fd);
@@ -286,11 +289,13 @@ void fuse_unmount(const char *mountpoint, struct fuse_chan *ch)
fuse_unmount_common(mountpoint, ch);
}
struct fuse *fuse_setup_common(int argc, char *argv[],
const struct fuse_operations *op,
size_t op_size,
char **mountpoint,
int *fd)
struct fuse *
fuse_setup_common(int argc,
char *argv[],
const struct fuse_operations *op,
size_t op_size,
char **mountpoint,
int *fd)
{
struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
struct fuse_chan *ch;
@@ -346,7 +351,7 @@ struct fuse *fuse_setup(int argc, char *argv[],
static void fuse_teardown_common(struct fuse *fuse, char *mountpoint)
{
struct fuse_session *se = fuse_get_session(fuse);
struct fuse_chan *ch = fuse_session_next_chan(se, NULL);
struct fuse_chan *ch = se->ch;
fuse_remove_signal_handlers(se);
fuse_unmount_common(mountpoint, ch);
fuse_destroy(fuse);
+16
View File
@@ -42,6 +42,22 @@ lfmp_init(lfmp_t *lfmp_,
pthread_mutex_init(&lfmp_->lock,NULL);
}
static
inline
void
lfmp_lock(lfmp_t *lfmp_)
{
pthread_mutex_lock(&lfmp_->lock);
}
static
inline
void
lfmp_unlock(lfmp_t *lfmp_)
{
pthread_mutex_unlock(&lfmp_->lock);
}
static
inline
uint64_t
+161
View File
@@ -0,0 +1,161 @@
#pragma once
#include <tuple>
#include <atomic>
#include <vector>
#include <thread>
#include <memory>
#include <future>
#include <utility>
#include <stdexcept>
#include <functional>
#include <type_traits>
#include "queue.hpp"
class simple_thread_pool
{
public:
explicit simple_thread_pool(std::size_t thread_count = std::thread::hardware_concurrency())
{
if(!thread_count)
throw std::invalid_argument("bad thread count! must be non-zero!");
auto worker = [this]()
{
while(true)
{
proc_t f;
if(!m_queue.pop(f))
break;
f();
}
};
m_threads.reserve(thread_count);
while(thread_count--)
m_threads.emplace_back(worker);
}
~simple_thread_pool()
{
m_queue.unblock();
for(auto& thread : m_threads)
thread.join();
}
template<typename F, typename... Args>
void enqueue_work(F&& f, Args&&... args)
{
m_queue.push([p = std::forward<F>(f), t = std::make_tuple(std::forward<Args>(args)...)]() { std::apply(p, t); });
}
template<typename F, typename... Args>
[[nodiscard]] auto enqueue_task(F&& f, Args&&... args) -> std::future<std::invoke_result_t<F, Args...>>
{
using task_return_type = std::invoke_result_t<F, Args...>;
using task_type = std::packaged_task<task_return_type()>;
auto task = std::make_shared<task_type>(std::bind(std::forward<F>(f), std::forward<Args>(args)...));
auto result = task->get_future();
m_queue.push([=]() { (*task)(); });
return result;
}
private:
using proc_t = std::function<void(void)>;
using queue_t = unbounded_queue<proc_t>;
queue_t m_queue;
using threads_t = std::vector<std::thread>;
threads_t m_threads;
};
class thread_pool
{
public:
explicit thread_pool(std::size_t thread_count = std::thread::hardware_concurrency())
: m_queues(thread_count), m_count(thread_count)
{
if(!thread_count)
throw std::invalid_argument("bad thread count! must be non-zero!");
auto worker = [this](auto i)
{
while(true)
{
proc_t f;
for(std::size_t n = 0; n < m_count * K; ++n)
if(m_queues[(i + n) % m_count].try_pop(f))
break;
if(!f && !m_queues[i].pop(f))
break;
f();
}
};
m_threads.reserve(thread_count);
for(std::size_t i = 0; i < thread_count; ++i)
m_threads.emplace_back(worker, i);
}
~thread_pool()
{
for(auto& queue : m_queues)
queue.unblock();
for(auto& thread : m_threads)
thread.join();
}
template<typename F, typename... Args>
void enqueue_work(F&& f, Args&&... args)
{
auto work = [p = std::forward<F>(f), t = std::make_tuple(std::forward<Args>(args)...)]() { std::apply(p, t); };
auto i = m_index++;
for(std::size_t n = 0; n < m_count * K; ++n)
if(m_queues[(i + n) % m_count].try_push(work))
return;
m_queues[i % m_count].push(std::move(work));
}
template<typename F, typename... Args>
[[nodiscard]] auto enqueue_task(F&& f, Args&&... args) -> std::future<std::invoke_result_t<F, Args...>>
{
using task_return_type = std::invoke_result_t<F, Args...>;
using task_type = std::packaged_task<task_return_type()>;
auto task = std::make_shared<task_type>(std::bind(std::forward<F>(f), std::forward<Args>(args)...));
auto work = [=]() { (*task)(); };
auto result = task->get_future();
auto i = m_index++;
for(auto n = 0; n < m_count * K; ++n)
if(m_queues[(i + n) % m_count].try_push(work))
return result;
m_queues[i % m_count].push(std::move(work));
return result;
}
private:
using proc_t = std::function<void(void)>;
using queue_t = unbounded_queue<proc_t>;
using queues_t = std::vector<queue_t>;
queues_t m_queues;
using threads_t = std::vector<std::thread>;
threads_t m_threads;
const std::size_t m_count;
std::atomic_uint m_index = 0;
inline static const unsigned int K = 2;
};
+256
View File
@@ -0,0 +1,256 @@
#pragma once
#include <mutex>
#include <queue>
#include <utility>
#include <stdexcept>
#include <condition_variable>
template<typename T>
class unbounded_queue
{
public:
explicit unbounded_queue(bool block = true)
: m_block{ block } {}
void push(const T& item)
{
{
std::scoped_lock guard(m_queue_lock);
m_queue.push(item);
}
m_condition.notify_one();
}
void push(T&& item)
{
{
std::scoped_lock guard(m_queue_lock);
m_queue.push(std::move(item));
}
m_condition.notify_one();
}
template<typename... Args>
void emplace(Args&&... args)
{
{
std::scoped_lock guard(m_queue_lock);
m_queue.emplace(std::forward<Args>(args)...);
}
m_condition.notify_one();
}
bool try_push(const T& item)
{
{
std::unique_lock lock(m_queue_lock, std::try_to_lock);
if(!lock)
return false;
m_queue.push(item);
}
m_condition.notify_one();
return true;
}
bool try_push(T&& item)
{
{
std::unique_lock lock(m_queue_lock, std::try_to_lock);
if(!lock)
return false;
m_queue.push(std::move(item));
}
m_condition.notify_one();
return true;
}
bool pop(T& item)
{
std::unique_lock guard(m_queue_lock);
m_condition.wait(guard, [&]() { return !m_queue.empty() || !m_block; });
if(m_queue.empty())
return false;
item = std::move(m_queue.front());
m_queue.pop();
return true;
}
bool try_pop(T& item)
{
std::unique_lock lock(m_queue_lock, std::try_to_lock);
if(!lock || m_queue.empty())
return false;
item = std::move(m_queue.front());
m_queue.pop();
return true;
}
std::size_t size() const
{
std::scoped_lock guard(m_queue_lock);
return m_queue.size();
}
bool empty() const
{
std::scoped_lock guard(m_queue_lock);
return m_queue.empty();
}
void block()
{
std::scoped_lock guard(m_queue_lock);
m_block = true;
}
void unblock()
{
{
std::scoped_lock guard(m_queue_lock);
m_block = false;
}
m_condition.notify_all();
}
bool blocking() const
{
std::scoped_lock guard(m_queue_lock);
return m_block;
}
private:
using queue_t = std::queue<T>;
queue_t m_queue;
bool m_block;
mutable std::mutex m_queue_lock;
std::condition_variable m_condition;
};
template<typename T>
class bounded_queue
{
public:
explicit bounded_queue(std::size_t max_size, bool block = true)
: m_block{ block }, m_max_size{ max_size }
{
if(!m_max_size)
throw std::invalid_argument("bad queue max-size! must be non-zero!");
}
bool push(const T& item)
{
{
std::unique_lock guard(m_queue_lock);
m_condition_push.wait(guard, [&]() { return m_queue.size() < m_max_size || !m_block; });
if(m_queue.size() == m_max_size)
return false;
m_queue.push(item);
}
m_condition_pop.notify_one();
return true;
}
bool push(T&& item)
{
{
std::unique_lock guard(m_queue_lock);
m_condition_push.wait(guard, [&]() { return m_queue.size() < m_max_size || !m_block; });
if(m_queue.size() == m_max_size)
return false;
m_queue.push(std::move(item));
}
m_condition_pop.notify_one();
return true;
}
template<typename... Args>
bool emplace(Args&&... args)
{
{
std::unique_lock guard(m_queue_lock);
m_condition_push.wait(guard, [&]() { return m_queue.size() < m_max_size || !m_block; });
if(m_queue.size() == m_max_size)
return false;
m_queue.emplace(std::forward<Args>(args)...);
}
m_condition_pop.notify_one();
return true;
}
bool pop(T& item)
{
{
std::unique_lock guard(m_queue_lock);
m_condition_pop.wait(guard, [&]() { return !m_queue.empty() || !m_block; });
if(m_queue.empty())
return false;
item = std::move(m_queue.front());
m_queue.pop();
}
m_condition_push.notify_one();
return true;
}
std::size_t size() const
{
std::scoped_lock guard(m_queue_lock);
return m_queue.size();
}
std::size_t capacity() const
{
return m_max_size;
}
bool empty() const
{
std::scoped_lock guard(m_queue_lock);
return m_queue.empty();
}
bool full() const
{
std::scoped_lock lock(m_queue_lock);
return m_queue.size() == capacity();
}
void block()
{
std::scoped_lock guard(m_queue_lock);
m_block = true;
}
void unblock()
{
{
std::scoped_lock guard(m_queue_lock);
m_block = false;
}
m_condition_push.notify_all();
m_condition_pop.notify_all();
}
bool blocking() const
{
std::scoped_lock guard(m_queue_lock);
return m_block;
}
private:
using queue_t = std::queue<T>;
queue_t m_queue;
bool m_block;
const std::size_t m_max_size;
mutable std::mutex m_queue_lock;
std::condition_variable m_condition_push;
std::condition_variable m_condition_pop;
};
+871 -967
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -42,7 +42,7 @@ Category::Base::to_string(void) const
{
std::set<std::string> rv;
for(auto func : funcs)
for(const auto func : funcs)
rv.insert(func->to_string());
return str::join(rv,',');
+6
View File
@@ -23,6 +23,8 @@ int
Func::Base::Action::from_string(const std::string &policyname_)
{
policy = Policies::Action::find(policyname_);
if(!policy)
return -EINVAL;
return 0;
}
@@ -37,6 +39,8 @@ int
Func::Base::Create::from_string(const std::string &policyname_)
{
policy = Policies::Create::find(policyname_);
if(!policy)
return -EINVAL;
return 0;
}
@@ -51,6 +55,8 @@ int
Func::Base::Search::from_string(const std::string &policyname_)
{
policy = Policies::Search::find(policyname_);
if(!policy)
return -EINVAL;
return 0;
}
+1 -1
View File
@@ -139,7 +139,7 @@ namespace l
return -errno;
if(symlinkify_ && symlinkify::can_be_symlink(*st_,symlinkify_timeout_))
st_->st_mode = symlinkify::convert(st_->st_mode);
symlinkify::convert(fullpath,st_);
fs::inode::calc(fusepath_,st_);
+16 -23
View File
@@ -62,8 +62,7 @@ namespace l
const string &newbasepath_,
const char *oldfusepath_,
const char *newfusepath_,
const string &newfusedirpath_,
struct stat *st_)
const string &newfusedirpath_)
{
int rv;
int error;
@@ -84,9 +83,6 @@ namespace l
rv = fs::link(oldfullpath,newfullpath);
}
if((rv == 0) && (st_->st_ino == 0))
rv = fs::lstat(oldfullpath,st_);
error = error::calc(rv,error,errno);
}
@@ -99,8 +95,7 @@ namespace l
const Policy::Action &actionFunc_,
const Branches &branches_,
const char *oldfusepath_,
const char *newfusepath_,
struct stat *st_)
const char *newfusepath_)
{
int rv;
string newfusedirpath;
@@ -119,8 +114,7 @@ namespace l
return l::link_create_path_loop(oldbasepaths,newbasepaths[0],
oldfusepath_,newfusepath_,
newfusedirpath,
st_);
newfusedirpath);
}
static
@@ -208,8 +202,7 @@ namespace l
cfg_->func.link.policy,
cfg_->branches,
oldpath_,
newpath_,
st_);
newpath_);
}
static
@@ -223,13 +216,10 @@ namespace l
int rv;
rv = l::link(cfg_,oldpath_,newpath_,st_);
if(rv < 0)
return rv;
timeouts_->entry = ((rv >= 0) ?
cfg_->cache_entry :
cfg_->cache_negative_entry);
timeouts_->attr = cfg_->cache_attr;
return rv;
return FUSE::getattr(newpath_,st_,timeouts_);
}
static
@@ -249,8 +239,9 @@ namespace l
if(rv == 0)
rv = FUSE::getattr(oldpath_,st_,timeouts_);
// Disable attr caching since we created a symlink but should be a regular.
timeouts_->attr = 0;
// Disable caching since we created a symlink but should be a regular.
timeouts_->attr = 0;
timeouts_->entry = 0;
return rv;
}
@@ -278,8 +269,9 @@ namespace l
if(rv == 0)
rv = FUSE::getattr(oldpath_,st_,timeouts_);
// Disable attr caching since we created a symlink but should be a regular.
timeouts_->attr = 0;
// Disable caching since we created a symlink but should be a regular.
timeouts_->attr = 0;
timeouts_->entry = 0;
return rv;
}
@@ -302,8 +294,9 @@ namespace l
if(rv == 0)
rv = FUSE::getattr(oldpath_,st_,timeouts_);
// Disable attr caching since we created a symlink but should be a regular.
timeouts_->attr = 0;
// Disable caching since we created a symlink but should be a regular.
timeouts_->attr = 0;
timeouts_->entry = 0;
return rv;
}
+43 -23
View File
@@ -17,7 +17,9 @@
#include "config.hpp"
#include "errno.hpp"
#include "fs_clonepath.hpp"
#include "fs_lstat.hpp"
#include "fs_path.hpp"
#include "fs_inode.hpp"
#include "fs_symlink.hpp"
#include "fuse_getattr.hpp"
#include "ugid.hpp"
@@ -59,6 +61,7 @@ namespace l
symlink_loop_core(const string &newbasepath_,
const char *target_,
const char *linkpath_,
struct stat *st_,
const int error_)
{
int rv;
@@ -67,6 +70,12 @@ namespace l
fullnewpath = fs::path::make(newbasepath_,linkpath_);
rv = fs::symlink(target_,fullnewpath);
if((rv != -1) && (st_ != NULL) && (st_->st_ino == 0))
{
fs::lstat(fullnewpath,st_);
if(st_->st_ino != 0)
fs::inode::calc(linkpath_,st_);
}
return error::calc(rv,error_,errno);
}
@@ -77,7 +86,8 @@ namespace l
const StrVec &newbasepaths_,
const char *target_,
const char *linkpath_,
const string &newdirpath_)
const string &newdirpath_,
struct stat *st_)
{
int rv;
int error;
@@ -92,6 +102,7 @@ namespace l
error = l::symlink_loop_core(newbasepaths_[i],
target_,
linkpath_,
st_,
error);
}
@@ -104,7 +115,8 @@ namespace l
const Policy::Create &createFunc_,
const Branches &branches_,
const char *target_,
const char *linkpath_)
const char *linkpath_,
struct stat *st_)
{
int rv;
string newdirpath;
@@ -122,39 +134,47 @@ namespace l
return -errno;
return l::symlink_loop(existingpaths[0],newbasepaths,
target_,linkpath_,newdirpath);
target_,linkpath_,newdirpath,st_);
}
}
namespace FUSE
{
int
symlink(const char *target_,
const char *linkpath_)
symlink(const char *target_,
const char *linkpath_,
struct stat *st_,
fuse_timeouts_t *timeouts_)
{
int rv;
Config::Read cfg;
const fuse_context *fc = fuse_get_context();
const ugid::Set ugid(fc->uid,fc->gid);
return l::symlink(cfg->func.getattr.policy,
cfg->func.symlink.policy,
cfg->branches,
target_,
linkpath_);
}
rv = l::symlink(cfg->func.getattr.policy,
cfg->func.symlink.policy,
cfg->branches,
target_,
linkpath_,
st_);
int
symlink(const char *target_,
const char *linkpath_,
struct stat *st_,
fuse_timeouts_t *timeout_)
{
int rv;
if(timeouts_ != NULL)
{
switch(cfg->follow_symlinks)
{
case FollowSymlinks::ENUM::NEVER:
timeouts_->entry = ((rv >= 0) ?
cfg->cache_entry :
cfg->cache_negative_entry);
timeouts_->attr = cfg->cache_attr;
break;
default:
timeouts_->entry = 0;
timeouts_->attr = 0;
break;
}
}
rv = FUSE::symlink(target_,linkpath_);
if(rv < 0)
return rv;
return FUSE::getattr(linkpath_,st_,timeout_);
return rv;
}
}
+2 -6
View File
@@ -22,13 +22,9 @@
namespace FUSE
{
int
symlink(const char *target,
const char *linkpath);
int
symlink(const char *target,
const char *linkpath,
struct stat *st,
fuse_timeouts_t *timeouts);
struct stat *st = NULL,
fuse_timeouts_t *timeouts = NULL);
}
+2 -3
View File
@@ -214,7 +214,6 @@
#include <compare>
#endif
#endif
#include <chrono>
#include <fstream>
#include <memory>
#include <stack>
@@ -265,7 +264,7 @@
// configure LWG conformance ()
#define LWG_2682_BEHAVIOUR
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// LWG #2395 makes crate_directory/create_directories not emit an error if there is a regular
// LWG #2395 makes create_directory/create_directories not emit an error if there is a regular
// file with that name, it is superseded by P1164R1, so only activate if really needed
// #define LWG_2935_BEHAVIOUR
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -3233,7 +3232,7 @@ GHC_INLINE path::impl_string_type::const_iterator path::iterator::increment(cons
// we can only sit on a slash if it is a network name or a root
if (i != _last && *i == preferred_separator) {
if (fromStart && !(i + 1 != _last && *(i + 1) == preferred_separator)) {
// leadind double slashes detected, treat this and the
// leading double slashes detected, treat this and the
// following until a slash as one unit
i = std::find(++i, _last, preferred_separator);
}
+6 -3
View File
@@ -66,7 +66,7 @@
#include "fuse_truncate.hpp"
#include "fuse_unlink.hpp"
#include "fuse_utimens.hpp"
#include "fuse_write_buf.hpp"
#include "fuse_write.hpp"
#include "fuse.h"
@@ -129,7 +129,7 @@ namespace l
ops_.truncate = FUSE::truncate;
ops_.unlink = FUSE::unlink;
ops_.utimens = FUSE::utimens;
ops_.write_buf = (nullrw_ ? FUSE::write_buf_null : FUSE::write_buf);
ops_.write = (nullrw_ ? FUSE::write_null : FUSE::write);
return;
}
@@ -164,7 +164,10 @@ namespace l
options::parse(&args,&errs);
if(errs.size())
std::cerr << errs << std::endl;
{
std::cerr << errs << std::endl;
return 1;
}
l::setup_resources();
l::get_fuse_operations(ops,cfg->nullrw);
+15
View File
@@ -73,6 +73,11 @@ namespace Policy
return (*impl)(branches_,fusepath_.c_str(),paths_);
}
operator bool() const
{
return (bool)impl;
}
private:
ActionImpl *impl;
};
@@ -134,6 +139,11 @@ namespace Policy
return (*impl)(branches_,fusepath_.c_str(),paths_);
}
operator bool() const
{
return (bool)impl;
}
private:
CreateImpl *impl;
};
@@ -188,6 +198,11 @@ namespace Policy
return (*impl)(branches_,fusepath_.c_str(),paths_);
}
operator bool() const
{
return (bool)impl;
}
private:
SearchImpl *impl;
};
+3 -1
View File
@@ -34,7 +34,9 @@ RND::RND()
gettimeofday(&tv,NULL);
G_SEED = ((tv.tv_sec << 32) | (tv.tv_usec));
G_SEED = tv.tv_sec;
G_SEED <<= 32;
G_SEED |= tv.tv_usec;
}
uint64_t
+9 -3
View File
@@ -21,6 +21,9 @@
#include <sys/stat.h>
#include <time.h>
#include <string>
namespace symlinkify
{
static
@@ -41,9 +44,12 @@ namespace symlinkify
static
inline
mode_t
convert(const mode_t mode_)
void
convert(const std::string &target_,
struct stat *st_)
{
return ((mode_ & ~S_IFMT) | S_IFLNK);
st_->st_mode = (((st_->st_mode & ~S_IFMT) | S_IFLNK) | 0777);
st_->st_size = target_.size();
st_->st_blocks = 0;
}
}
+1 -1
View File
@@ -3,7 +3,7 @@
#define wyhash_final_version
//defines that change behavior
#ifndef WYHASH_CONDOM
#define WYHASH_CONDOM 1 //0: read 8 bytes before and after boudaries, dangerous but fastest. 1: normal valid behavior 2: extra protection against entropy loss (probability=2^-63), aka. "blind multiplication"
#define WYHASH_CONDOM 1 //0: read 8 bytes before and after boundaries, dangerous but faster. 1: normal valid behavior 2: extra protection against entropy loss (probability=2^-63), aka. "blind multiplication"
#endif
#define WYHASH_32BIT_MUM 0 //faster on 32 bit system
//includes
+2 -2
View File
@@ -62,7 +62,7 @@
#define TEST_LIST const struct test_ test_list_[]
/* Macros for testing whether an unit test succeeds or fails. These macros
/* Macros for testing whether a unit test succeeds or fails. These macros
* can be used arbitrarily in functions implementing the unit tests.
*
* If any condition fails throughout execution of a test, the test fails.
@@ -245,7 +245,7 @@
#endif
/* Common test initialiation/clean-up
/* Common test initialization/clean-up
*
* In some test suites, it may be needed to perform some sort of the same
* initialization and/or clean-up in all the tests.