Nikolaus Rath <[email protected]> writes:
> Julian Seward <[email protected]> writes:
>>> My guess would be that stat64 is not marked as a system call that can
>>> block and that it needs the MayBlock flag adding.
>>
>> Yes, that could be it.  I guess, normally, a stat64 (etc) call is
>> completed eventually by the kernel, without the need for any other
>> thread to run.  But in this case a stat64 call might somehow require
>> some other thread to progress.  
>>
>> Nikolaus, try adding
>>
>>   *flags |= SfMayBlock;
>>
>> to PRE(sys_stat64) in syswrap-x86-linux.c (I assume this is
>> 32-bit x86).  Does that help?
>
>
> No, I'm afraid it's still blocking in the same call.


The devil's in the detail. I had to write a minimal example and observe
it mysteriously working before I looked closely enough, but I finally
noticed that the call is *l*stat, and not stat. After adding the flag to
sys_lstat64 the problem is fixed.

Is there any chance of getting the flag added in valgrind by default, or
would that hurt performance too much?


I'm attaching my minimal example anyway, maybe it's useful for someone
at some point.


Best,

   -Nikolaus

-- 
 »Time flies like an arrow, fruit flies like a Banana.«

  PGP fingerprint: 5B93 61F8 4EA2 E279 ABF6  02CF A9AD B7F8 AE4E 425C
/*
  FUSE: Filesystem in Userspace
  Copyright (C) 2001-2007  Miklos Szeredi <[email protected]>

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

  Modified by Nikolaus Rath to demonstrate deadlocking when running
  under Valgrind.

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

#define FUSE_USE_VERSION 26

#include <fuse_lowlevel.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>
#include <assert.h>

static const char *hello_str = "Hello World!\n";
static const char *hello_name = "hello";
static char *mountpoint;

static int hello_stat(fuse_ino_t ino, struct stat *stbuf)
{
	stbuf->st_ino = ino;
	switch (ino) {
	case 1:
		stbuf->st_mode = S_IFDIR | 0755;
		stbuf->st_nlink = 2;
		break;

	case 2:
		stbuf->st_mode = S_IFREG | 0444;
		stbuf->st_nlink = 1;
		stbuf->st_size = strlen(hello_str);
		break;

	default:
		return -1;
	}
	return 0;
}

static void hello_ll_getattr(fuse_req_t req, fuse_ino_t ino,
			     struct fuse_file_info *fi)
{
	struct stat stbuf;

	(void) fi;

	memset(&stbuf, 0, sizeof(stbuf));
	if (hello_stat(ino, &stbuf) == -1)
		fuse_reply_err(req, ENOENT);
	else
		fuse_reply_attr(req, &stbuf, 1.0);
}

static void hello_ll_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
{
	struct fuse_entry_param e;

	if (parent != 1 || strcmp(name, hello_name) != 0)
		fuse_reply_err(req, ENOENT);
	else {
		memset(&e, 0, sizeof(e));
		e.ino = 2;
		e.attr_timeout = 1.0;
		e.entry_timeout = 1.0;
		hello_stat(e.ino, &e.attr);

		fuse_reply_entry(req, &e);
	}
}

struct dirbuf {
	char *p;
	size_t size;
};

static void dirbuf_add(fuse_req_t req, struct dirbuf *b, const char *name,
		       fuse_ino_t ino)
{
	struct stat stbuf;
	size_t oldsize = b->size;
	b->size += fuse_add_direntry(req, NULL, 0, name, NULL, 0);
	b->p = (char *) realloc(b->p, b->size);
	memset(&stbuf, 0, sizeof(stbuf));
	stbuf.st_ino = ino;
	fuse_add_direntry(req, b->p + oldsize, b->size - oldsize, name, &stbuf,
			  b->size);
}

#define min(x, y) ((x) < (y) ? (x) : (y))

static int reply_buf_limited(fuse_req_t req, const char *buf, size_t bufsize,
			     off_t off, size_t maxsize)
{
	if (off < bufsize)
		return fuse_reply_buf(req, buf + off,
				      min(bufsize - off, maxsize));
	else
		return fuse_reply_buf(req, NULL, 0);
}

static void hello_ll_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
			     off_t off, struct fuse_file_info *fi)
{
	(void) fi;

	if (ino != 1)
		fuse_reply_err(req, ENOTDIR);
	else {
		struct dirbuf b;

		memset(&b, 0, sizeof(b));
		dirbuf_add(req, &b, ".", 1);
		dirbuf_add(req, &b, "..", 1);
		dirbuf_add(req, &b, hello_name, 2);
		reply_buf_limited(req, b.p, b.size, off, size);
		free(b.p);
	}
}

void hello_ll_opendir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
{
	fuse_reply_err(req, ENOSYS);
}

static void hello_ll_open(fuse_req_t req, fuse_ino_t ino,
			  struct fuse_file_info *fi)
{
	if (ino != 2)
		fuse_reply_err(req, EISDIR);
	else if ((fi->flags & 3) != O_RDONLY)
		fuse_reply_err(req, EACCES);
	else
		fuse_reply_open(req, fi);
}

static void hello_ll_read(fuse_req_t req, fuse_ino_t ino, size_t size,
			  off_t off, struct fuse_file_info *fi)
{
	(void) fi;

	assert(ino == 2);
	reply_buf_limited(req, hello_str, strlen(hello_str), off, size);
}

static struct fuse_lowlevel_ops hello_ll_oper = {
	.lookup		= hello_ll_lookup,
	.getattr	= hello_ll_getattr,
	.readdir	= hello_ll_readdir,
	.open		= hello_ll_open,
	.read		= hello_ll_read,
	.opendir    = hello_ll_opendir,
};

void *StatMountpoint(void *data)
{
    struct stat buf;
    sleep(5);
    printf("Calling stat(%s)\n", mountpoint);
    if (lstat(mountpoint, &buf) != 0) {
        perror("stat failed");
    }
    
    pthread_exit(NULL);
}

void *RunFUSE(void *data)
{
    struct fuse_args *args;
    struct fuse_chan *ch;
    struct fuse_session *se;

    args = (struct fuse_args*) data;

    if ((ch = fuse_mount(mountpoint, args)) != NULL) {
        se = fuse_lowlevel_new(args, &hello_ll_oper,
                               sizeof(hello_ll_oper), NULL);
        if (se != NULL) {
            if (fuse_set_signal_handlers(se) != -1) {
                fuse_session_add_chan(se, ch);
                fuse_session_loop_mt(se);
                fuse_remove_signal_handlers(se);
                fuse_session_remove_chan(ch);
            }
            fuse_session_destroy(se);
        }
        fuse_unmount(mountpoint, ch);
    }
    pthread_exit(NULL);
}


int main(int argc, char *argv[])
{
	struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
	int rc;
        pthread_t thread;

	if (fuse_parse_cmdline(&args, &mountpoint, NULL, NULL) != 0) {
            printf("fuse_parse_cmdline failed.\n");
            return 1;
        }
        
        rc = pthread_create(&thread, NULL, RunFUSE, (void *)&args);
        if (rc){
            printf("ERROR; return code from pthread_create() is %d\n", rc);
            return 1;
        }

        rc = pthread_create(&thread, NULL, StatMountpoint, NULL);
        if (rc){
            printf("ERROR; return code from pthread_create() is %d\n", rc);
            return 1;
        }
        pthread_exit(NULL);
}
------------------------------------------------------------------------------
Gaining the trust of online customers is vital for the success of any company
that requires sensitive data to be transmitted over the Web.   Learn how to 
best implement a security strategy that keeps consumers' information secure 
and instills the confidence they need to proceed with transactions.
http://p.sf.net/sfu/oracle-sfdevnl 
_______________________________________________
Valgrind-users mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/valgrind-users

Reply via email to