• 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
new caching behavior in 10.8?
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

new caching behavior in 10.8?


  • Subject: new caching behavior in 10.8?
  • From: Mike Shal <email@hidden>
  • Date: Fri, 14 Dec 2012 17:35:52 -0500

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
/*
  FUSE: Filesystem in Userspace
  Copyright (C) 2001-2007  Miklos Szeredi <email@hidden>

  This program can be distributed under the terms of the GNU GPL.
  See the file COPYING.

  gcc -Wall `pkg-config fuse --cflags --libs` fusexmp.c -o fusexmp
*/

#define FUSE_USE_VERSION 26

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#ifdef linux
/* For pread()/pwrite() */
#define _XOPEN_SOURCE 500
#endif

#include <fuse.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
#include <errno.h>
#include <sys/time.h>
#ifdef HAVE_SETXATTR
#include <sys/xattr.h>
#endif

static int xmp_getattr(const char *path, struct stat *stbuf)
{
	int res;

	res = lstat(path, stbuf);
	if (res == -1)
		return -errno;

	return 0;
}

static int xmp_access(const char *path, int mask)
{
	int res;

	res = access(path, mask);
	if (res == -1)
		return -errno;

	return 0;
}

static int xmp_readlink(const char *path, char *buf, size_t size)
{
	int res;

	res = readlink(path, buf, size - 1);
	if (res == -1)
		return -errno;

	buf[res] = '\0';
	return 0;
}


static int xmp_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
		       off_t offset, struct fuse_file_info *fi)
{
	DIR *dp;
	struct dirent *de;

	(void) offset;
	(void) fi;

	dp = opendir(path);
	if (dp == NULL)
		return -errno;

	while ((de = readdir(dp)) != NULL) {
		struct stat st;
		memset(&st, 0, sizeof(st));
		st.st_ino = de->d_ino;
		st.st_mode = de->d_type << 12;
		if (filler(buf, de->d_name, &st, 0))
			break;
	}

	closedir(dp);
	return 0;
}

static int xmp_mknod(const char *path, mode_t mode, dev_t rdev)
{
	int res;

	/* On Linux this could just be 'mknod(path, mode, rdev)' but this
	   is more portable */
	if (S_ISREG(mode)) {
		res = open(path, O_CREAT | O_EXCL | O_WRONLY, mode);
		if (res >= 0)
			res = close(res);
	} else if (S_ISFIFO(mode))
		res = mkfifo(path, mode);
	else
		res = mknod(path, mode, rdev);
	if (res == -1)
		return -errno;

	return 0;
}

static int xmp_mkdir(const char *path, mode_t mode)
{
	int res;

	res = mkdir(path, mode);
	if (res == -1)
		return -errno;

	return 0;
}

static int xmp_unlink(const char *path)
{
	int res;

	res = unlink(path);
	if (res == -1)
		return -errno;

	return 0;
}

static int xmp_rmdir(const char *path)
{
	int res;

	res = rmdir(path);
	if (res == -1)
		return -errno;

	return 0;
}

static int xmp_symlink(const char *from, const char *to)
{
	int res;

	res = symlink(from, to);
	if (res == -1)
		return -errno;

	return 0;
}

static int xmp_rename(const char *from, const char *to)
{
	int res;

	res = rename(from, to);
	if (res == -1)
		return -errno;

	return 0;
}

static int xmp_link(const char *from, const char *to)
{
	int res;

	res = link(from, to);
	if (res == -1)
		return -errno;

	return 0;
}

static int xmp_chmod(const char *path, mode_t mode)
{
	int res;

	res = chmod(path, mode);
	if (res == -1)
		return -errno;

	return 0;
}

static int xmp_chown(const char *path, uid_t uid, gid_t gid)
{
	int res;

	res = lchown(path, uid, gid);
	if (res == -1)
		return -errno;

	return 0;
}

static int xmp_truncate(const char *path, off_t size)
{
	int res;

	res = truncate(path, size);
	if (res == -1)
		return -errno;

	return 0;
}

static int xmp_utimens(const char *path, const struct timespec ts[2])
{
	int res;
	struct timeval tv[2];

	tv[0].tv_sec = ts[0].tv_sec;
	tv[0].tv_usec = ts[0].tv_nsec / 1000;
	tv[1].tv_sec = ts[1].tv_sec;
	tv[1].tv_usec = ts[1].tv_nsec / 1000;

	res = utimes(path, tv);
	if (res == -1)
		return -errno;

	return 0;
}

static int xmp_open(const char *path, struct fuse_file_info *fi)
{
	int res;

	res = open(path, fi->flags);
	if (res == -1)
		return -errno;

	close(res);
	return 0;
}

static int xmp_read(const char *path, char *buf, size_t size, off_t offset,
		    struct fuse_file_info *fi)
{
	int fd;
	int res;

	(void) fi;
	fd = open(path, O_RDONLY);
	if (fd == -1)
		return -errno;

	res = pread(fd, buf, size, offset);
	if (res == -1)
		res = -errno;

	close(fd);
	return res;
}

static int xmp_write(const char *path, const char *buf, size_t size,
		     off_t offset, struct fuse_file_info *fi)
{
	int fd;
	int res;

	(void) fi;
	fd = open(path, O_WRONLY);
	if (fd == -1)
		return -errno;

	res = pwrite(fd, buf, size, offset);
	if (res == -1)
		res = -errno;

	close(fd);
	return res;
}

static int xmp_statfs(const char *path, struct statvfs *stbuf)
{
	int res;

	res = statvfs(path, stbuf);
	if (res == -1)
		return -errno;

	return 0;
}

static int xmp_release(const char *path, struct fuse_file_info *fi)
{
	/* Just a stub.	 This method is optional and can safely be left
	   unimplemented */

	(void) path;
	(void) fi;
	return 0;
}

static int xmp_fsync(const char *path, int isdatasync,
		     struct fuse_file_info *fi)
{
	/* Just a stub.	 This method is optional and can safely be left
	   unimplemented */

	(void) path;
	(void) isdatasync;
	(void) fi;
	return 0;
}

#ifdef HAVE_SETXATTR
/* xattr operations are optional and can safely be left unimplemented */
static int xmp_setxattr(const char *path, const char *name, const char *value,
			size_t size, int flags)
{
	int res = lsetxattr(path, name, value, size, flags);
	if (res == -1)
		return -errno;
	return 0;
}

static int xmp_getxattr(const char *path, const char *name, char *value,
			size_t size)
{
	int res = lgetxattr(path, name, value, size);
	if (res == -1)
		return -errno;
	return res;
}

static int xmp_listxattr(const char *path, char *list, size_t size)
{
	int res = llistxattr(path, list, size);
	if (res == -1)
		return -errno;
	return res;
}

static int xmp_removexattr(const char *path, const char *name)
{
	int res = lremovexattr(path, name);
	if (res == -1)
		return -errno;
	return 0;
}
#endif /* HAVE_SETXATTR */

static struct fuse_operations xmp_oper = {
	.getattr	= xmp_getattr,
	.access		= xmp_access,
	.readlink	= xmp_readlink,
	.readdir	= xmp_readdir,
	.mknod		= xmp_mknod,
	.mkdir		= xmp_mkdir,
	.symlink	= xmp_symlink,
	.unlink		= xmp_unlink,
	.rmdir		= xmp_rmdir,
	.rename		= xmp_rename,
	.link		= xmp_link,
	.chmod		= xmp_chmod,
	.chown		= xmp_chown,
	.truncate	= xmp_truncate,
	.utimens	= xmp_utimens,
	.open		= xmp_open,
	.read		= xmp_read,
	.write		= xmp_write,
	.statfs		= xmp_statfs,
	.release	= xmp_release,
	.fsync		= xmp_fsync,
#ifdef HAVE_SETXATTR
	.setxattr	= xmp_setxattr,
	.getxattr	= xmp_getxattr,
	.listxattr	= xmp_listxattr,
	.removexattr	= xmp_removexattr,
#endif
};

int main(int argc, char *argv[])
{
	umask(0);
	return fuse_main(argc, argv, &xmp_oper, NULL);
}
 _______________________________________________
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: FSE_ARG_INT64 argument in fsevent
  • Next by Date: LSItemInfoFlags bit #35 - what is it?
  • Previous by thread: Re: FSE_ARG_INT64 argument in fsevent
  • Next by thread: LSItemInfoFlags bit #35 - what is it?
  • Index(es):
    • Date
    • Thread