Browse Source

improve nodeid generation

* Change fuse_ino_t to uint64_t
* Change id generation to 64bit
* Randomize generation value (should help with NFS)
pull/675/head
Antonio SJ Musumeci 5 years ago
parent
commit
08e1bef5a9
  1. 2
      libfuse/Makefile
  2. 14
      libfuse/include/fuse_lowlevel.h
  3. 236
      libfuse/lib/fuse.c

2
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)

14
libfuse/include/fuse_lowlevel.h

@ -25,12 +25,13 @@
#include "fuse_common.h"
#include <utime.h>
#include <fcntl.h>
#include <sys/types.h>
#include <stdint.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <utime.h>
#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

236
libfuse/lib/fuse.c

@ -19,25 +19,26 @@
#include "fuse_compat.h"
#include "fuse_kernel.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdbool.h>
#include <unistd.h>
#include <time.h>
#include <assert.h>
#include <dlfcn.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <errno.h>
#include <signal.h>
#include <dlfcn.h>
#include <assert.h>
#include <poll.h>
#include <signal.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/file.h>
#include <sys/mman.h>
#include <sys/param.h>
#include <sys/uio.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <sys/file.h>
#include <sys/uio.h>
#include <time.h>
#include <unistd.h>
#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;

Loading…
Cancel
Save