Date: Fri, 25 Mar 2016 19:53:34 -0400 (EDT) From: Rick Macklem <rmacklem@uoguelph.ca> To: Hiroshi Nishida <nishida@asusa.net> Cc: freebsd-fs@freebsd.org Subject: Re: Problem with FUSE + fts Message-ID: <1294209833.31699182.1458950014610.JavaMail.zimbra@uoguelph.ca> In-Reply-To: <56F42EF4.5000505@asusa.net> References: <56F42EF4.5000505@asusa.net>
next in thread | previous in thread | raw e-mail | index | archive | help
Hiroshi Nishida wrote: > Hi, > > I found a weird error with FUSE + fts_read(). > Every time a command like find, rm -r that calls fts_read() is used for a > FUSE mounted filesystem, it outputs "XXX: No such file or directory" errors > for some (not all) files/directories. > I think I see the same thing when doing an "rm -r" on a fuse/GlusterFS volume. To be honest, I just add a "-f" to the command to shut it up and then it deleted the tree. I think, in general, what readdir() returns after an entry is unlink'd is undefined behaviour. As such, the safe way to delete all of a directory is something like: - in a loop until readdir() returns EOF - opendir() - readdir() the first entry - unlink() that entry - closedir() --> So that all you ever do is readdir() the first entry after an opendir(). However few, if any, apps do this and loop on readdir(), unlink() instead. >From my limited experience with fuse, the directory offset is an index (which isn't monotonically increasing for GlusterFS) and those indexes only work while the directory is open. I think that in Linux, an opendir(), readdir() reads an entire directory into storage maintained by the libc functions and then readdir() returns subsequent entries without doing a kernel syscall. As such, deletion of entries that, in turn, change directory offsets in the file system, don't affect this. In FreeBSD, this (reading the entire directory when opened) is done for "unionfs", but not otherwise. --> This causes grief for NFS, due to directory offsets (called cookies in NFS) change when entries are deleted. --> It is also the case that many (including Linux, I think) return these "cookies" in their "struct dirent", but FreeBSD does not. I have been tempted to enable "read the entire directory on opendir()" for other file system types, but the downside is that apps. will use memory for this (possibly lots for large directories). Since most use UFS or ZFS and don't see problems, I haven't tried to make a case for this change. (I may try if I find that this change fixes fuse.) If you don't mind rebuilding libc from sources, take a look at opendir.c and readdir.c (I can't remember exactly how it is done, but you should find where it chooses to read the entire directory upon opendir or the first readdir) and you could try enabling that for fuse. The directory offset problem is a thorny one, but will at least be partially fixed by a new "struct dirent" with a d_off field in it. This has to be done someday to make ino_t 64bits anyhow. *** If you see this for cases other than "rm -r", such as "ls -lR", then all of the above is bogus. Another issue (which I doubt is causing this) is that FreeBSD has a 32bit ino_t but fuse uses a 64bit inode#, so the FreeBSD fuse interface ends up truncating the high order 32bits off. (GlusterFS uses more than 32bits, but the high order bits are invariant, so it doesn't break things.) Hope this somehow helps, rick > In /usr/src/lib/libc/gen/fts.c, there is fts_safe_changedir(FTS *, FTSENT *, > int, char *) and the error seems to occur there in the following way: > > FTS *sp; > FTSENT *p = sp->fts_cur; // Current node > DIR *dirp = opendir2(p->fts_accpath, oflag); // Open dir > int fd = _dirfd(dirp); // File descriptor of dirp > struct stat sb; _fstat(fd, &sb); // fstat current node through fd > > p->fts_ino != sb.st_ino // This happens for some reason...... and sets errno > = ENOENT > > When the error happens, p->fts_ino always has a small number and sb.st_ino > has a great number like: > p->fts_ino = 13, sb.st_ino = 54136 > > So, a new inode number seems to be allocated to sb.st_ino though the node > already has an inode number. > > I would appreciate hearing any feedback on this, though I already posted > fuse-devel ML and haven't received any helpful responses yet. > The problem seems to be particular to FreeBSD because I don't get any errors > with Ubuntu. > > The sample FUSE program is located at > https://github.com/scopedog/FUSE-Test > > and fts.c is also located under freebsd and ubuntu dirs (interestingly, fts.c > of FreeBSD and Ubuntu are almost identical). > > Thank you. > > -- > Hiroshi Nishida > nishida@asusa.net > _______________________________________________ > freebsd-fs@freebsd.org mailing list > https://lists.freebsd.org/mailman/listinfo/freebsd-fs > To unsubscribe, send any mail to "freebsd-fs-unsubscribe@freebsd.org" >
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?1294209833.31699182.1458950014610.JavaMail.zimbra>