10#define FUSE_USE_VERSION 30 
   15#include <fuse_config.h> 
   16#include <fuse_lowlevel.h> 
   32#include <linux/limits.h> 
   36#define FILE_NAME "write_me" 
   49#define WRITE_SYSCALLS 64 
   52    { t, offsetof(struct options, p), 1 } 
   53static const struct fuse_opt option_spec[] = {
 
   54    OPTION(
"writeback_cache", writeback),
 
   55    OPTION(
"--data-size=%d", data_size),
 
   56    OPTION(
"--delay_ms=%d", delay_ms),
 
   60static atomic_int write_cnt;
 
   62pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
 
   63pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
 
   64static int write_start, write_done;
 
   70    if(options.writeback) {
 
   76static int tfs_stat(
fuse_ino_t ino, 
struct stat *stbuf) {
 
   78    if (ino == FUSE_ROOT_ID) {
 
   79        stbuf->st_mode = S_IFDIR | 0755;
 
   83    else if (ino == FILE_INO) {
 
   84        stbuf->st_mode = S_IFREG | 0222;
 
   98    memset(&e, 0, 
sizeof(e));
 
  102    else if (strcmp(name, FILE_NAME) == 0)
 
  107    if (tfs_stat(e.ino, &e.attr) != 0)
 
  122    memset(&stbuf, 0, 
sizeof(stbuf));
 
  123    if (tfs_stat(ino, &stbuf) != 0)
 
  131    if (ino == FUSE_ROOT_ID)
 
  134        assert(ino == FILE_INO);
 
  136        fi->
noflush = !options.writeback && options.delay_ms &&
 
  137                      (fi->
flags & O_ACCMODE) == O_RDONLY;
 
  144    (void) fi; (void) buf; (void) off;
 
  147    assert(ino == FILE_INO);
 
  148    expected = options.data_size;
 
  149    if(options.writeback)
 
  154   if(size != expected && !options.writeback)
 
  155       fprintf(stderr, 
"ERROR: Expected %zd bytes, got %zd\n!",
 
  161    if (options.delay_ms) {
 
  162        pthread_mutex_lock(&lock);
 
  164        pthread_cond_signal(&cond);
 
  165        pthread_mutex_unlock(&lock);
 
  167        usleep(options.delay_ms * 1000);
 
  169        pthread_mutex_lock(&lock);
 
  171        pthread_cond_signal(&cond);
 
  172        pthread_mutex_unlock(&lock);
 
  180    .lookup     = tfs_lookup,
 
  181    .getattr    = tfs_getattr,
 
  186static void* close_rofd(
void *data) {
 
  187    int rofd = (int)(
long) data;
 
  190    pthread_mutex_lock(&lock);
 
  191    while (!write_start && !write_done)
 
  192        pthread_cond_wait(&cond, &lock);
 
  193    pthread_mutex_unlock(&lock);
 
  196    printf(
"rofd closed. write_start: %d write_done: %d\n", write_start, write_done);
 
  200        fprintf(stderr, 
"ERROR: close(rofd) blocked on write!\n");
 
  205static void* run_fs(
void *data) {
 
  206    struct fuse_session *se = (
struct fuse_session*) data;
 
  211static void test_fs(
char *mountpoint) {
 
  212    char fname[PATH_MAX];
 
  214    const size_t iosize = options.data_size;
 
  215    const size_t dsize = options.data_size * WRITE_SYSCALLS;
 
  217    pthread_t rofd_thread;
 
  222    assert((fd = open(
"/dev/urandom", O_RDONLY)) != -1);
 
  223    assert(read(fd, buf, dsize) == dsize);
 
  226    assert(snprintf(fname, PATH_MAX, 
"%s/" FILE_NAME,
 
  228    fd = open(fname, O_WRONLY);
 
  234    if (options.delay_ms) {
 
  236        rofd = open(fname, O_RDONLY);
 
  237        assert(pthread_create(&rofd_thread, NULL, close_rofd, (
void *)(
long)rofd) == 0);
 
  239        usleep(options.delay_ms * 1000);
 
  242    for (
int cnt = 0; cnt < WRITE_SYSCALLS; cnt++) {
 
  243        assert(pwrite(fd, buf + off, iosize, off) == iosize);
 
  245        assert(off <= dsize);
 
  250    if (options.delay_ms) {
 
  251        printf(
"rwfd closed. write_start: %d write_done: %d\n", write_start, write_done);
 
  252        assert(pthread_join(rofd_thread, NULL) == 0);
 
  256int main(
int argc, 
char *argv[]) {
 
  258    struct fuse_session *se;
 
  263    assert(fuse_parse_cmdline(&args, &fuse_opts) == 0);
 
  267    se = fuse_session_new(&args, &tfs_oper,
 
  268                          sizeof(tfs_oper), NULL);
 
  275    assert(pthread_create(&fs_thread, NULL, run_fs, (
void *)se) == 0);
 
  278    test_fs(fuse_opts.mountpoint);
 
  279    free(fuse_opts.mountpoint);
 
  284    assert(pthread_join(fs_thread, NULL) == 0);
 
  286    assert(got_write == 1);
 
  296    if (options.writeback)
 
  297        assert(write_cnt < WRITE_SYSCALLS);
 
  299        assert(write_cnt == WRITE_SYSCALLS);
 
  304    printf(
"Test completed successfully.\n");
 
int fuse_set_signal_handlers(struct fuse_session *se)
void fuse_remove_signal_handlers(struct fuse_session *se)
void fuse_session_destroy(struct fuse_session *se)
int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *fi)
void fuse_session_exit(struct fuse_session *se)
int fuse_reply_err(fuse_req_t req, int err)
struct fuse_req * fuse_req_t
int fuse_session_loop(struct fuse_session *se)
int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
void fuse_session_unmount(struct fuse_session *se)
int fuse_reply_write(fuse_req_t req, size_t count)
int fuse_session_mount(struct fuse_session *se, const char *mountpoint)
int fuse_reply_attr(fuse_req_t req, const struct stat *attr, double attr_timeout)
int fuse_opt_add_arg(struct fuse_args *args, const char *arg)
void fuse_opt_free_args(struct fuse_args *args)
int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
#define FUSE_ARGS_INIT(argc, argv)
#define FUSE_CAP_WRITEBACK_CACHE
void(* init)(void *userdata, struct fuse_conn_info *conn)