From 08e1bef5a9fbcfabc74f2d5ac0abdc44c4426ae2 Mon Sep 17 00:00:00 2001 From: Antonio SJ Musumeci Date: Mon, 30 Sep 2019 18:45:58 -0400 Subject: [PATCH] improve nodeid generation * Change fuse_ino_t to uint64_t * Change id generation to 64bit * Randomize generation value (should help with NFS) --- libfuse/Makefile | 2 +- libfuse/include/fuse_lowlevel.h | 14 +- libfuse/lib/fuse.c | 236 +++++++++++++++++++------------- 3 files changed, 151 insertions(+), 101 deletions(-) diff --git a/libfuse/Makefile b/libfuse/Makefile index 15f77146..ce7b0178 100644 --- a/libfuse/Makefile +++ b/libfuse/Makefile @@ -1,4 +1,4 @@ -VERSION = "2.9.7-mergerfs_2.28.0" +VERSION = "2.9.7-mergerfs_2.29.0" OPTS = -O2 ifeq ($(DEBUG),1) diff --git a/libfuse/include/fuse_lowlevel.h b/libfuse/include/fuse_lowlevel.h index f76faa32..bed7afd9 100644 --- a/libfuse/include/fuse_lowlevel.h +++ b/libfuse/include/fuse_lowlevel.h @@ -25,12 +25,13 @@ #include "fuse_common.h" -#include #include -#include +#include #include #include +#include #include +#include #ifdef __cplusplus extern "C" { @@ -44,7 +45,7 @@ extern "C" { #define FUSE_ROOT_ID 1 /** Inode number type */ -typedef unsigned long fuse_ino_t; +typedef uint64_t fuse_ino_t; /** Request pointer type */ typedef struct fuse_req *fuse_req_t; @@ -88,7 +89,8 @@ struct fuse_entry_param { * it as an error. * */ - unsigned long generation; + uint64_t generation; + /** Inode attributes. * @@ -122,7 +124,7 @@ struct fuse_ctx { }; struct fuse_forget_data { - uint64_t ino; + fuse_ino_t ino; uint64_t nlookup; }; @@ -233,7 +235,7 @@ struct fuse_lowlevel_ops { * @param ino the inode number * @param nlookup the number of lookups to forget */ - void (*forget) (fuse_req_t req, fuse_ino_t ino, unsigned long nlookup); + void (*forget) (fuse_req_t req, fuse_ino_t ino, uint64_t nlookup); /** * Get file attributes diff --git a/libfuse/lib/fuse.c b/libfuse/lib/fuse.c index 9a031450..39cb42ea 100644 --- a/libfuse/lib/fuse.c +++ b/libfuse/lib/fuse.c @@ -19,25 +19,26 @@ #include "fuse_compat.h" #include "fuse_kernel.h" -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include #include #include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include -#include #include -#include -#include +#include +#include +#include #define FUSE_NODE_SLAB 1 @@ -47,7 +48,7 @@ #define FUSE_DEFAULT_INTR_SIGNAL SIGUSR1 -#define FUSE_UNKNOWN_INO 0xffffffff +#define FUSE_UNKNOWN_INO UINT64_MAX #define OFFSET_MAX 0x7fffffffffffffffLL #define NODE_TABLE_MIN_SIZE 8192 @@ -122,25 +123,26 @@ struct node_slab { int used; }; -struct fuse { - struct fuse_session *se; - struct node_table name_table; - struct node_table id_table; - struct list_head lru_table; - fuse_ino_t ctr; - unsigned int generation; - unsigned int hidectr; - pthread_mutex_t lock; - struct fuse_config conf; - int intr_installed; - struct fuse_fs *fs; - int nullpath_ok; - int utime_omit_ok; - struct lock_queue_element *lockq; - int pagesize; - struct list_head partial_slabs; - struct list_head full_slabs; - pthread_t prune_thread; +struct fuse +{ + struct fuse_session *se; + struct node_table name_table; + struct node_table id_table; + struct list_head lru_table; + fuse_ino_t ctr; + uint64_t generation; + unsigned int hidectr; + pthread_mutex_t lock; + struct fuse_config conf; + int intr_installed; + struct fuse_fs *fs; + int nullpath_ok; + int utime_omit_ok; + struct lock_queue_element *lockq; + int pagesize; + struct list_head partial_slabs; + struct list_head full_slabs; + pthread_t prune_thread; }; struct lock { @@ -157,7 +159,7 @@ struct node struct node *name_next; struct node *id_next; fuse_ino_t nodeid; - unsigned int generation; + uint64_t generation; int refctr; struct node *parent; char *name; @@ -396,15 +398,21 @@ static struct node *get_node_nocheck(struct fuse *f, fuse_ino_t nodeid) return NULL; } -static struct node *get_node(struct fuse *f, fuse_ino_t nodeid) +static +struct node* +get_node(struct fuse *f, + const fuse_ino_t nodeid) { - struct node *node = get_node_nocheck(f, nodeid); - if (!node) { - fprintf(stderr, "fuse internal error: node %llu not found\n", - (unsigned long long) nodeid); - abort(); - } - return node; + struct node *node = get_node_nocheck(f, nodeid); + + if(!node) + { + fprintf(stderr, "fuse internal error: node %llu not found\n", + (unsigned long long) nodeid); + abort(); + } + + return node; } static void curr_time(struct timespec *now); @@ -705,15 +713,33 @@ static void unref_node(struct fuse *f, struct node *node) delete_node(f, node); } -static fuse_ino_t next_id(struct fuse *f) +static +uint64_t +rand64(void) { - do { - f->ctr = (f->ctr + 1) & 0xffffffff; - if (!f->ctr) - f->generation ++; - } while (f->ctr == 0 || f->ctr == FUSE_UNKNOWN_INO || - get_node_nocheck(f, f->ctr) != NULL); - return f->ctr; + uint64_t rv; + + rv = rand(); + rv <<= 32; + rv |= rand(); + + return rv; +} + +static +fuse_ino_t +next_id(struct fuse *f) +{ + do + { + f->ctr = ((f->ctr + 1) & UINT64_MAX); + if(f->ctr == 0) + f->generation++; + } while((f->ctr == 0) || + (f->ctr == FUSE_UNKNOWN_INO) || + (get_node_nocheck(f, f->ctr) != NULL)); + + return f->ctr; } static struct node *lookup_node(struct fuse *f, fuse_ino_t parent, @@ -1182,42 +1208,51 @@ static void free_path2(struct fuse *f, fuse_ino_t nodeid1, fuse_ino_t nodeid2, free(path2); } -static void forget_node(struct fuse *f, fuse_ino_t nodeid, uint64_t nlookup) +static +void +forget_node(struct fuse *f, + const fuse_ino_t nodeid, + const uint64_t nlookup) { - struct node *node; - if (nodeid == FUSE_ROOT_ID) - return; - pthread_mutex_lock(&f->lock); - node = get_node(f, nodeid); + struct node *node; - /* - * Node may still be locked due to interrupt idiocy in open, - * create and opendir - */ - while (node->nlookup == nlookup && node->treelock) { - struct lock_queue_element qe = { - .nodeid1 = nodeid, - }; + if(nodeid == FUSE_ROOT_ID) + return; - debug_path(f, "QUEUE PATH (forget)", nodeid, NULL, false); - queue_path(f, &qe); + pthread_mutex_lock(&f->lock); + node = get_node(f, nodeid); - do { - pthread_cond_wait(&qe.cond, &f->lock); - } while (node->nlookup == nlookup && node->treelock); + /* + * Node may still be locked due to interrupt idiocy in open, + * create and opendir + */ + while(node->nlookup == nlookup && node->treelock) + { + struct lock_queue_element qe = { + .nodeid1 = nodeid, + }; - dequeue_path(f, &qe); - debug_path(f, "DEQUEUE_PATH (forget)", nodeid, NULL, false); - } + debug_path(f, "QUEUE PATH (forget)", nodeid, NULL, false); + queue_path(f, &qe); - assert(node->nlookup >= nlookup); - node->nlookup -= nlookup; - if (!node->nlookup) { - unref_node(f, node); - } else if (lru_enabled(f) && node->nlookup == 1) { - set_forget_time(f, node); - } - pthread_mutex_unlock(&f->lock); + do + { + pthread_cond_wait(&qe.cond, &f->lock); + } + while((node->nlookup == nlookup) && node->treelock); + + dequeue_path(f, &qe); + debug_path(f, "DEQUEUE_PATH (forget)", nodeid, NULL, false); + } + + assert(node->nlookup >= nlookup); + node->nlookup -= nlookup; + if(!node->nlookup) + unref_node(f, node); + else if(lru_enabled(f) && node->nlookup == 1) + set_forget_time(f, node); + + pthread_mutex_unlock(&f->lock); } static void unlink_node(struct fuse *f, struct node *node) @@ -2390,9 +2425,12 @@ static int lookup_path(struct fuse *f, fuse_ino_t nodeid, update_stat(node, &e->attr); pthread_mutex_unlock(&f->lock); set_stat(f, e->ino, &e->attr); - if (f->conf.debug) - fprintf(stderr, " NODEID: %lu\n", - (unsigned long) e->ino); + if(f->conf.debug) + fprintf(stderr, + " NODEID: %llu\n" + " GEN: %llu\n", + (unsigned long long)e->ino, + (unsigned long long)e->generation); } } return res; @@ -2586,19 +2624,28 @@ static void fuse_lib_lookup(fuse_req_t req, fuse_ino_t parent, reply_entry(req, &e, err); } -static void do_forget(struct fuse *f, fuse_ino_t ino, uint64_t nlookup) +static +void +do_forget(struct fuse *f, + const fuse_ino_t ino, + const uint64_t nlookup) { - if (f->conf.debug) - fprintf(stderr, "FORGET %llu/%llu\n", (unsigned long long)ino, - (unsigned long long) nlookup); - forget_node(f, ino, nlookup); + if(f->conf.debug) + fprintf(stderr, + "FORGET %llu/%llu\n", + (unsigned long long)ino, + (unsigned long long)nlookup); + forget_node(f, ino, nlookup); } -static void fuse_lib_forget(fuse_req_t req, fuse_ino_t ino, - unsigned long nlookup) +static +void +fuse_lib_forget(fuse_req_t req, + const fuse_ino_t ino, + const uint64_t nlookup) { - do_forget(req_fuse(req), ino, nlookup); - fuse_reply_none(req); + do_forget(req_fuse(req), ino, nlookup); + fuse_reply_none(req); } static void fuse_lib_forget_multi(fuse_req_t req, size_t count, @@ -4669,9 +4716,10 @@ struct fuse *fuse_new_common(struct fuse_chan *ch, struct fuse_args *args, } /* Trace topmost layer by default */ + srand(time(NULL)); f->fs->debug = f->conf.debug; f->ctr = 0; - f->generation = 0; + f->generation = rand64(); if (node_table_init(&f->name_table) == -1) goto out_free_session;