• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: new caching behavior in 10.8?
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: new caching behavior in 10.8?


  • Subject: Re: new caching behavior in 10.8?
  • From: Mike Shal <email@hidden>
  • Date: Tue, 27 Aug 2013 09:23:41 -0400

On Fri, Jan 4, 2013 at 9:54 AM, Mike Shal <email@hidden> wrote:
On Fri, Dec 14, 2012 at 5:35 PM, Mike Shal <email@hidden> wrote:
> Hello,
>
> I am trying to use FUSE in OSX 10.8 (currently Fuse4x, though I see
> the same behavior in OSXFUSE). I posted this in the OSXFUSE mailing
> list as well, but maybe someone here has an idea. Basically I am
> seeing what I think is some new caching behavior in 10.8 that wasn't
> present in 10.7 and earlier. As a test I am using fusexmp.c, which is
> just a loopback filesystem that comes with fuse (attached).
>
> In 10.7, I can do the following:
>
> (terminal A) ./fusexmp -d tmp
> (terminal B) cd tmp/Users/me/
> (terminal B) gcc ok.c
> (terminal B) cd /Users/me
> (terminal B) ./a.out
> Hello!
>
> Where /Users/me/ok.c contains:
> #include <stdio.h>
>
> int main(void)
> {
>         printf("Hello!\n");
>         return 0;
> }
>
> The debug in terminal A from FUSE shows that the WRITE occurs before
> the gcc command returns to the shell:
>
> mknod /Users/marf/a.out 0100755 0x0 umask=0135000
> getattr /Users/marf/a.out
>    NODEID: 31
>    unique: 1, success, outsize: 160
> unique: 2, opcode: LOOKUP (1), nodeid: 29, insize: 48
> LOOKUP /Users/marf/._a.out
> getattr /Users/marf/._a.out
>    unique: 2, error: -2 (No such file or directory), outsize: 16
> unique: 0, opcode: GETATTR (3), nodeid: 31, insize: 56
> getattr /Users/marf/a.out
>    unique: 0, success, outsize: 136
> unique: 1, opcode: OPEN (14), nodeid: 31, insize: 48
> open flags: 0x1 /Users/marf/a.out
>    open[0] flags: 0x1 /Users/marf/a.out
>    unique: 1, success, outsize: 32
> unique: 2, opcode: WRITE (16), nodeid: 31, insize: 8768
> write[0] 8688 bytes to 0 flags: 0x0
>    write[0] 8688 bytes to 0
>    unique: 2, success, outsize: 24
>
> However, repeating the same test (same fusexmp.c, ok.c, and Fuse4X
> 0.9.2) in 10.8 shows:
>
> ...
> (terminal B) ./a.out
> -bash: ./a.out: cannot execute binary file
>
> This is strange, since the gcc process has long since quit. Using od shows:
>
> $ od -t x1 a.out
> 0000000    00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
> *
> 0021060
>
> In contrast to 10.7 where I see the WRITE call during the gcc process,
> in 10.8 I don't see the WRITE call until the unmount:
>
> unique: 5, opcode: OPEN (14), nodeid: 29, insize: 48
> open flags: 0x2 /Users/marf/a.out
>    open[0] flags: 0x2 /Users/marf/a.out
>    unique: 5, success, outsize: 32
> unique: 0, opcode: WRITE (16), nodeid: 29, insize: 8832
> write[0] 8752 bytes to 0 flags: 0x0
>    write[0] 8752 bytes to 0
>    unique: 0, success, outsize: 24
>
> Note that I *can* run ./a.out inside the FUSE fs, but not in the fs
> where it was actually written. I can only run it in the real fs after
> unmounting FUSE. Anyone know what might have changed in 10.8 to cause
> this? Is there a mount option or something I can pass in when creating
> the FUSE fs to disable this behavior?
>
> In my actual program I synchronize several separate processes to run
> in different virtual directories that all map to the same underlying
> filesystem. One process may write to a file (like a.out here), and
> another process tries to read from it using a different path. This
> works in 10.7 (as well as Linux), but not in 10.8.
>
> Thanks,
> -Mike

Hey all,

Anyone have any ideas here? Is there a new caching behavior or
something in 10.8 that would cause files written through FUSE to not
actually go to the backing filesystem until FUSE is unmounted? And is
there a way to disable that (with a mount option, perhaps?)


We debugged this a bit on the OSXFuse mailing list, but I wanted to close the loop here as well in case anyone comes across it while searching. Apparently the issue in clang/gcc is that the linker was using mmap to write out the file, which seems to be specific to an older clang version. This one does not work:

Apple clang version 4.1 (tags/Apple/clang-421.11.66) (based on LLVM 3.1svn)

But this one works fine:

Apple LLVM version 4.2 (clang-425.0.28) (based on LLVM 3.2svn)

As a simple way to reproduce the issue without gcc/clang, these two simple programs can show the difference. When the first one is executed inside a FUSE fs, the write callback in FUSE is called immediately, so the output.txt file is available in the main filesystem when the program quits without unmounting the FUSE fs.

// Test program 1: output.txt works as expected outside of FUSE
#include <stdio.h>
#include <fcntl.h>

int main(void)
{
        int fd;
        fd = open("output.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666);
        if(fd < 0) {
                perror("output.txt");
                return -1;
        }
        write(fd, "hey there\n", 10);
        close(fd);
        return 0;
}

In the second program, we add in ftruncate()/mmap() and then write the data through the map. Here the data is cached somewhere, and never sent to the filesystem until the fs is unmounted. From outside of FUSE, the file appears to be 10 bytes of all 0's (due to the ftruncate). The data written through the map is not available. I would have expected the filesystem to get the write call when the file is closed (but be cached at the disk layer - I'm not interested in syncing to disk). This mimics what the older 3.1 version of clang does while linking:

// Test program 2: newoutput.txt is all 0-bytes when viewed from outside
// of FUSE until the FUSE fs is unmounted
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <sys/mman.h>

int main(void)
{
        int fd;
        void *map;
        char data[] = "hey there\n";

        fd = open("newoutput.txt", O_RDWR | O_CREAT | O_TRUNC, 0666);
        if(fd < 0) {
                perror("newoutput.txt");
                return -1;
        }
        if(ftruncate(fd, sizeof(data)) < 0) {
                perror("ftruncate");
                return -1;
        }
        map = mmap(NULL, sizeof(data), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
        if(map == MAP_FAILED) {
                perror("mmap");
                return -1;
        }

        memcpy(map, data, sizeof(data));
        close(fd);
        return 0;
}

Fortunately the original issue (running gcc successfully through FUSE) can be fixed by upgrading to clang 3.2. However, I still have no idea how to disable the mmap caching behavior, so if any other tools use the access pattern in the second example, they will likely fail in the same way.

-Mike
 _______________________________________________
Do not post admin requests to the list. They will be ignored.
Filesystem-dev mailing list      (email@hidden)
Help/Unsubscribe/Update your Subscription:

This email sent to email@hidden

  • Prev by Date: Re: Determine if a file system supports files > 4GB
  • Previous by thread: Re: Determine if a file system supports files > 4GB
  • Index(es):
    • Date
    • Thread