New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How can I tell that readdirplus is working? #235

Closed
paradigm opened this Issue Feb 11, 2018 · 1 comment

Comments

Projects
None yet
2 participants
@paradigm
Copy link

paradigm commented Feb 11, 2018

From what I understand, readdirplus allows calls to readdir() to also include stat information which will be cached. Thus, one ls -l command will not require context switching into libfuse userland for each and every file's stat information. Given this, I would expect there to be fewer LOOKUPs generated with ls -l and find when a libfuse program is running with -d, fewer calls to getattr(), and improved find times. However, I'm not seeing a difference. It is not clear to me if I am misunderstanding readdirplus, misusing fuse, or there's a bug.

Using:

  • libfuse 3.2.1, compiled from source
  • Linux 4.9.0 (from Debian Stretch)

Using passthrough_fh.c as a reference, I run:

mkdir -p /example
touch /example/{foo,bar,baz}
./passthrough_fh -d /dev/shm/passothrough

then in another terminal:

ls -l ./test/example/

passthrough_fh prints:

FUSE library version: 3.2.1
nullpath_ok: 0
unique: 1, opcode: INIT (26), nodeid: 0, insize: 56, pid: 0
INIT: 7.26
flags=0x001ffffb
max_readahead=0x00020000
   INIT: 7.26
   flags=0x0000f439
   max_readahead=0x00020000
   max_write=0x00020000
   max_background=0
   congestion_threshold=0
   time_gran=1
   unique: 1, success, outsize: 80
unique: 2, opcode: LOOKUP (1), nodeid: 1, insize: 48, pid: 20375
LOOKUP /example
getattr[NULL] /example
   NODEID: 2
   unique: 2, success, outsize: 144
unique: 3, opcode: GETATTR (3), nodeid: 2, insize: 56, pid: 20375
getattr[NULL] /example
   unique: 3, success, outsize: 120
unique: 4, opcode: LOOKUP (1), nodeid: 1, insize: 48, pid: 20375
LOOKUP /example
getattr[NULL] /example
   NODEID: 2
   unique: 4, success, outsize: 144
unique: 5, opcode: GETXATTR (22), nodeid: 2, insize: 65, pid: 20375
   unique: 5, error: -38 (Function not implemented), outsize: 16
unique: 6, opcode: LOOKUP (1), nodeid: 1, insize: 48, pid: 20375
LOOKUP /example
getattr[NULL] /example
   NODEID: 2
   unique: 6, success, outsize: 144
unique: 7, opcode: LOOKUP (1), nodeid: 1, insize: 48, pid: 20375
LOOKUP /example
getattr[NULL] /example
   NODEID: 2
   unique: 7, success, outsize: 144
unique: 8, opcode: OPENDIR (27), nodeid: 2, insize: 48, pid: 20375
opendir flags: 0x18800 /example
   opendir[39812704] flags: 0x18800 /example
   unique: 8, success, outsize: 32
unique: 9, opcode: GETATTR (3), nodeid: 2, insize: 56, pid: 20375
getattr[NULL] /example
   unique: 9, success, outsize: 120
unique: 10, opcode: READDIRPLUS (44), nodeid: 2, insize: 80, pid: 20375
readdirplus[39812704] from 0
   unique: 10, success, outsize: 816
unique: 11, opcode: LOOKUP (1), nodeid: 1, insize: 48, pid: 20375
LOOKUP /example
getattr[NULL] /example
   NODEID: 2
   unique: 11, success, outsize: 144
unique: 12, opcode: LOOKUP (1), nodeid: 2, insize: 44, pid: 20375
LOOKUP /example/bar
getattr[NULL] /example/bar
   NODEID: 3
   unique: 12, success, outsize: 144
unique: 13, opcode: GETATTR (3), nodeid: 3, insize: 56, pid: 20375
getattr[NULL] /example/bar
   unique: 13, success, outsize: 120
unique: 14, opcode: LOOKUP (1), nodeid: 1, insize: 48, pid: 20375
LOOKUP /example
getattr[NULL] /example
   NODEID: 2
   unique: 14, success, outsize: 144
unique: 15, opcode: LOOKUP (1), nodeid: 2, insize: 44, pid: 20375
LOOKUP /example/baz
getattr[NULL] /example/baz
   NODEID: 4
   unique: 15, success, outsize: 144
unique: 16, opcode: GETATTR (3), nodeid: 4, insize: 56, pid: 20375
getattr[NULL] /example/baz
   unique: 16, success, outsize: 120
unique: 17, opcode: LOOKUP (1), nodeid: 1, insize: 48, pid: 20375
LOOKUP /example
getattr[NULL] /example
   NODEID: 2
   unique: 17, success, outsize: 144
unique: 18, opcode: LOOKUP (1), nodeid: 2, insize: 44, pid: 20375
LOOKUP /example/foo
getattr[NULL] /example/foo
   NODEID: 5
   unique: 18, success, outsize: 144
unique: 19, opcode: GETATTR (3), nodeid: 5, insize: 56, pid: 20375
getattr[NULL] /example/foo
   unique: 19, success, outsize: 120
unique: 20, opcode: READDIRPLUS (44), nodeid: 2, insize: 80, pid: 20375
readdirplus[39812704] from 9223372036854775807
   unique: 20, success, outsize: 16
unique: 21, opcode: RELEASEDIR (29), nodeid: 2, insize: 64, pid: 0
releasedir[39812704] flags: 0x0
   unique: 21, success, outsize: 16

I would have expected, were readdirplus working, that the LOOKUP lines corresponding to foo, bar, and baz would be absent.

I modified passthrough_fh to include an indication if it is trying to use readdirplus:

  static int xmp_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
  		       off_t offset, struct fuse_file_info *fi,
  		       enum fuse_readdir_flags flags)
  {
+ 	printf("using readdirplus: %d\n", flags & FUSE_READDIR_PLUS);
  	struct xmp_dirp *d = get_dirp(fi);

and to indicate if it's actually calling the underlying getattr()

  static int xmp_getattr(const char *path, struct stat *stbuf,
  			struct fuse_file_info *fi)
  {
+ 	printf("calling getattr for %s\n", path);
  	int res;

Then rebuilt and ran:

./passthrough_fh -f /dev/shm/passothrough

then ran the ls -l example above. The modified passthrough_fh printed:

calling getattr for /example
calling getattr for /example
calling getattr for /example
calling getattr for /example
calling getattr for /example
calling getattr for /example
using readdirplus: 1
calling getattr for /example
calling getattr for /example/bar
calling getattr for /example/bar
calling getattr for /example
calling getattr for /example/baz
calling getattr for /example/baz
calling getattr for /example
calling getattr for /example/foo
calling getattr for /example/foo
using readdirplus: 1

If the kernel did not want to use readdirplus, I would have expected flags & FUSE_READDIR_PLUS to be 0, and thus it does seem like readdirplus is being requested.

Were readdirplus working, I would have expected the getattr calls for foo, bar, and baz to be absent and the preceding readdir() would have populated those values.

Past releases of libfuse apparently supported a -o readirplus=(yes|no|auto) that may have been useful for testing here, but 3.2.1 does not appear to do so.

I have also tried modifying xmp_readdir in various ways to try and disable readirplus (e.g. placing flags=0; at the very beginning), performing quick and dirty benchmarks with find with and without the modification. I saw no meaningful difference, although my testing methodology may have been flawed.

What am I missing here?

@Nikratio

This comment has been minimized.

Copy link
Contributor

Nikratio commented Feb 12, 2018

Thanks for the report! This is currently being discussed on the libfuse mailing list, could you join the discussion over there? See the thread around https://sourceforge.net/p/fuse/mailman/fuse-devel/thread/878tcgxvp2.fsf%40vostro.rath.org/#msg36209107

@Nikratio Nikratio closed this Feb 12, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment