|
@ -54,7 +54,8 @@ |
|
|
|
|
|
|
|
|
#define NODE_TABLE_MIN_SIZE 8192 |
|
|
#define NODE_TABLE_MIN_SIZE 8192 |
|
|
|
|
|
|
|
|
struct fuse_config { |
|
|
|
|
|
|
|
|
struct fuse_config |
|
|
|
|
|
{ |
|
|
unsigned int uid; |
|
|
unsigned int uid; |
|
|
unsigned int gid; |
|
|
unsigned int gid; |
|
|
unsigned int umask; |
|
|
unsigned int umask; |
|
@ -70,14 +71,16 @@ struct fuse_config { |
|
|
int threads; |
|
|
int threads; |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
struct fuse_fs { |
|
|
|
|
|
|
|
|
struct fuse_fs |
|
|
|
|
|
{ |
|
|
struct fuse_operations op; |
|
|
struct fuse_operations op; |
|
|
void *user_data; |
|
|
void *user_data; |
|
|
int compat; |
|
|
int compat; |
|
|
int debug; |
|
|
int debug; |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
struct lock_queue_element { |
|
|
|
|
|
|
|
|
struct lock_queue_element |
|
|
|
|
|
{ |
|
|
struct lock_queue_element *next; |
|
|
struct lock_queue_element *next; |
|
|
pthread_cond_t cond; |
|
|
pthread_cond_t cond; |
|
|
fuse_ino_t nodeid1; |
|
|
fuse_ino_t nodeid1; |
|
@ -94,7 +97,8 @@ struct lock_queue_element { |
|
|
bool done : 1; |
|
|
bool done : 1; |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
struct node_table { |
|
|
|
|
|
|
|
|
struct node_table |
|
|
|
|
|
{ |
|
|
struct node **array; |
|
|
struct node **array; |
|
|
size_t use; |
|
|
size_t use; |
|
|
size_t size; |
|
|
size_t size; |
|
@ -108,12 +112,14 @@ struct node_table { |
|
|
#define list_entry(ptr, type, member) \ |
|
|
#define list_entry(ptr, type, member) \ |
|
|
container_of(ptr, type, member) |
|
|
container_of(ptr, type, member) |
|
|
|
|
|
|
|
|
struct list_head { |
|
|
|
|
|
|
|
|
struct list_head |
|
|
|
|
|
{ |
|
|
struct list_head *next; |
|
|
struct list_head *next; |
|
|
struct list_head *prev; |
|
|
struct list_head *prev; |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
struct node_slab { |
|
|
|
|
|
|
|
|
struct node_slab |
|
|
|
|
|
{ |
|
|
struct list_head list; /* must be the first member */ |
|
|
struct list_head list; /* must be the first member */ |
|
|
struct list_head freelist; |
|
|
struct list_head freelist; |
|
|
int used; |
|
|
int used; |
|
@ -139,7 +145,8 @@ struct fuse |
|
|
pthread_t prune_thread; |
|
|
pthread_t prune_thread; |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
struct lock { |
|
|
|
|
|
|
|
|
struct lock |
|
|
|
|
|
{ |
|
|
int type; |
|
|
int type; |
|
|
off_t start; |
|
|
off_t start; |
|
|
off_t end; |
|
|
off_t end; |
|
@ -171,7 +178,8 @@ struct node |
|
|
#define TREELOCK_WRITE -1 |
|
|
#define TREELOCK_WRITE -1 |
|
|
#define TREELOCK_WAIT_OFFSET INT_MIN |
|
|
#define TREELOCK_WAIT_OFFSET INT_MIN |
|
|
|
|
|
|
|
|
struct node_lru { |
|
|
|
|
|
|
|
|
struct node_lru |
|
|
|
|
|
{ |
|
|
struct node node; |
|
|
struct node node; |
|
|
struct list_head lru; |
|
|
struct list_head lru; |
|
|
struct timespec forget_time; |
|
|
struct timespec forget_time; |
|
@ -184,7 +192,8 @@ struct fuse_dh |
|
|
fuse_dirents_t d; |
|
|
fuse_dirents_t d; |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
struct fuse_context_i { |
|
|
|
|
|
|
|
|
struct fuse_context_i |
|
|
|
|
|
{ |
|
|
struct fuse_context ctx; |
|
|
struct fuse_context ctx; |
|
|
fuse_req_t req; |
|
|
fuse_req_t req; |
|
|
}; |
|
|
}; |
|
@ -193,18 +202,25 @@ static pthread_key_t fuse_context_key; |
|
|
static pthread_mutex_t fuse_context_lock = PTHREAD_MUTEX_INITIALIZER; |
|
|
static pthread_mutex_t fuse_context_lock = PTHREAD_MUTEX_INITIALIZER; |
|
|
static int fuse_context_ref; |
|
|
static int fuse_context_ref; |
|
|
|
|
|
|
|
|
static void init_list_head(struct list_head *list) |
|
|
|
|
|
|
|
|
static |
|
|
|
|
|
void |
|
|
|
|
|
init_list_head(struct list_head *list) |
|
|
{ |
|
|
{ |
|
|
list->next = list; |
|
|
list->next = list; |
|
|
list->prev = list; |
|
|
list->prev = list; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static int list_empty(const struct list_head *head) |
|
|
|
|
|
|
|
|
static |
|
|
|
|
|
int |
|
|
|
|
|
list_empty(const struct list_head *head) |
|
|
{ |
|
|
{ |
|
|
return head->next == head; |
|
|
return head->next == head; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static void list_add(struct list_head *new, struct list_head *prev, |
|
|
|
|
|
|
|
|
static |
|
|
|
|
|
void |
|
|
|
|
|
list_add(struct list_head *new, |
|
|
|
|
|
struct list_head *prev, |
|
|
struct list_head *next) |
|
|
struct list_head *next) |
|
|
{ |
|
|
{ |
|
|
next->prev = new; |
|
|
next->prev = new; |
|
@ -213,17 +229,28 @@ static void list_add(struct list_head *new, struct list_head *prev, |
|
|
prev->next = new; |
|
|
prev->next = new; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static inline void list_add_head(struct list_head *new, struct list_head *head) |
|
|
|
|
|
|
|
|
static |
|
|
|
|
|
inline |
|
|
|
|
|
void |
|
|
|
|
|
list_add_head(struct list_head *new, |
|
|
|
|
|
struct list_head *head) |
|
|
{ |
|
|
{ |
|
|
list_add(new, head, head->next); |
|
|
list_add(new, head, head->next); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static inline void list_add_tail(struct list_head *new, struct list_head *head) |
|
|
|
|
|
|
|
|
static |
|
|
|
|
|
inline |
|
|
|
|
|
void |
|
|
|
|
|
list_add_tail(struct list_head *new, |
|
|
|
|
|
struct list_head *head) |
|
|
{ |
|
|
{ |
|
|
list_add(new, head->prev, head); |
|
|
list_add(new, head->prev, head); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static inline void list_del(struct list_head *entry) |
|
|
|
|
|
|
|
|
static |
|
|
|
|
|
inline |
|
|
|
|
|
void |
|
|
|
|
|
list_del(struct list_head *entry) |
|
|
{ |
|
|
{ |
|
|
struct list_head *prev = entry->prev; |
|
|
struct list_head *prev = entry->prev; |
|
|
struct list_head *next = entry->next; |
|
|
struct list_head *next = entry->next; |
|
@ -232,17 +259,25 @@ static inline void list_del(struct list_head *entry) |
|
|
prev->next = next; |
|
|
prev->next = next; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static inline int lru_enabled(struct fuse *f) |
|
|
|
|
|
|
|
|
static |
|
|
|
|
|
inline |
|
|
|
|
|
int |
|
|
|
|
|
lru_enabled(struct fuse *f) |
|
|
{ |
|
|
{ |
|
|
return f->conf.remember > 0; |
|
|
return f->conf.remember > 0; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static struct node_lru *node_lru(struct node *node) |
|
|
|
|
|
|
|
|
static |
|
|
|
|
|
struct |
|
|
|
|
|
node_lru* |
|
|
|
|
|
node_lru(struct node *node) |
|
|
{ |
|
|
{ |
|
|
return (struct node_lru*)node; |
|
|
return (struct node_lru*)node; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static size_t get_node_size(struct fuse *f) |
|
|
|
|
|
|
|
|
static |
|
|
|
|
|
size_t |
|
|
|
|
|
get_node_size(struct fuse *f) |
|
|
{ |
|
|
{ |
|
|
if (lru_enabled(f)) |
|
|
if (lru_enabled(f)) |
|
|
return sizeof(struct node_lru); |
|
|
return sizeof(struct node_lru); |
|
@ -251,17 +286,23 @@ static size_t get_node_size(struct fuse *f) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
#ifdef FUSE_NODE_SLAB |
|
|
#ifdef FUSE_NODE_SLAB |
|
|
static struct node_slab *list_to_slab(struct list_head *head) |
|
|
|
|
|
|
|
|
static |
|
|
|
|
|
struct node_slab* |
|
|
|
|
|
list_to_slab(struct list_head *head) |
|
|
{ |
|
|
{ |
|
|
return (struct node_slab *) head; |
|
|
return (struct node_slab *) head; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static struct node_slab *node_to_slab(struct fuse *f, struct node *node) |
|
|
|
|
|
|
|
|
static |
|
|
|
|
|
struct node_slab* |
|
|
|
|
|
node_to_slab(struct fuse *f, struct node *node) |
|
|
{ |
|
|
{ |
|
|
return (struct node_slab *) (((uintptr_t) node) & ~((uintptr_t) f->pagesize - 1)); |
|
|
return (struct node_slab *) (((uintptr_t) node) & ~((uintptr_t) f->pagesize - 1)); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static int alloc_slab(struct fuse *f) |
|
|
|
|
|
|
|
|
static |
|
|
|
|
|
int |
|
|
|
|
|
alloc_slab(struct fuse *f) |
|
|
{ |
|
|
{ |
|
|
void *mem; |
|
|
void *mem; |
|
|
struct node_slab *slab; |
|
|
struct node_slab *slab; |
|
@ -293,7 +334,9 @@ static int alloc_slab(struct fuse *f) |
|
|
return 0; |
|
|
return 0; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static struct node *alloc_node(struct fuse *f) |
|
|
|
|
|
|
|
|
static |
|
|
|
|
|
struct node* |
|
|
|
|
|
alloc_node(struct fuse *f) |
|
|
{ |
|
|
{ |
|
|
struct node_slab *slab; |
|
|
struct node_slab *slab; |
|
|
struct list_head *node; |
|
|
struct list_head *node; |
|
@ -316,7 +359,10 @@ static struct node *alloc_node(struct fuse *f) |
|
|
return (struct node *) node; |
|
|
return (struct node *) node; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static void free_slab(struct fuse *f, struct node_slab *slab) |
|
|
|
|
|
|
|
|
static |
|
|
|
|
|
void |
|
|
|
|
|
free_slab(struct fuse *f, |
|
|
|
|
|
struct node_slab *slab) |
|
|
{ |
|
|
{ |
|
|
int res; |
|
|
int res; |
|
|
|
|
|
|
|
@ -326,7 +372,10 @@ static void free_slab(struct fuse *f, struct node_slab *slab) |
|
|
fprintf(stderr, "fuse warning: munmap(%p) failed\n", slab); |
|
|
fprintf(stderr, "fuse warning: munmap(%p) failed\n", slab); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static void free_node_mem(struct fuse *f, struct node *node) |
|
|
|
|
|
|
|
|
static |
|
|
|
|
|
void |
|
|
|
|
|
free_node_mem(struct fuse *f, |
|
|
|
|
|
struct node *node) |
|
|
{ |
|
|
{ |
|
|
struct node_slab *slab = node_to_slab(f, node); |
|
|
struct node_slab *slab = node_to_slab(f, node); |
|
|
struct list_head *n = (struct list_head *) node; |
|
|
struct list_head *n = (struct list_head *) node; |
|
@ -343,19 +392,27 @@ static void free_node_mem(struct fuse *f, struct node *node) |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
#else |
|
|
#else |
|
|
static struct node *alloc_node(struct fuse *f) |
|
|
|
|
|
|
|
|
static |
|
|
|
|
|
struct node* |
|
|
|
|
|
alloc_node(struct fuse *f) |
|
|
{ |
|
|
{ |
|
|
return (struct node *) calloc(1, get_node_size(f)); |
|
|
return (struct node *) calloc(1, get_node_size(f)); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static void free_node_mem(struct fuse *f, struct node *node) |
|
|
|
|
|
|
|
|
static |
|
|
|
|
|
void |
|
|
|
|
|
free_node_mem(struct fuse *f, |
|
|
|
|
|
struct node *node) |
|
|
{ |
|
|
{ |
|
|
(void) f; |
|
|
(void) f; |
|
|
free(node); |
|
|
free(node); |
|
|
} |
|
|
} |
|
|
#endif |
|
|
#endif |
|
|
|
|
|
|
|
|
static size_t id_hash(struct fuse *f, fuse_ino_t ino) |
|
|
|
|
|
|
|
|
static |
|
|
|
|
|
size_t |
|
|
|
|
|
id_hash(struct fuse *f, |
|
|
|
|
|
fuse_ino_t ino) |
|
|
{ |
|
|
{ |
|
|
uint64_t hash = ((uint32_t) ino * 2654435761U) % f->id_table.size; |
|
|
uint64_t hash = ((uint32_t) ino * 2654435761U) % f->id_table.size; |
|
|
uint64_t oldhash = hash % (f->id_table.size / 2); |
|
|
uint64_t oldhash = hash % (f->id_table.size / 2); |
|
@ -366,7 +423,10 @@ static size_t id_hash(struct fuse *f, fuse_ino_t ino) |
|
|
return hash; |
|
|
return hash; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static struct node *get_node_nocheck(struct fuse *f, fuse_ino_t nodeid) |
|
|
|
|
|
|
|
|
static |
|
|
|
|
|
struct node* |
|
|
|
|
|
get_node_nocheck(struct fuse *f, |
|
|
|
|
|
fuse_ino_t nodeid) |
|
|
{ |
|
|
{ |
|
|
size_t hash = id_hash(f, nodeid); |
|
|
size_t hash = id_hash(f, nodeid); |
|
|
struct node *node; |
|
|
struct node *node; |
|
@ -399,14 +459,19 @@ static void curr_time(struct timespec *now); |
|
|
static double diff_timespec(const struct timespec *t1, |
|
|
static double diff_timespec(const struct timespec *t1, |
|
|
const struct timespec *t2); |
|
|
const struct timespec *t2); |
|
|
|
|
|
|
|
|
static void remove_node_lru(struct node *node) |
|
|
|
|
|
|
|
|
static |
|
|
|
|
|
void |
|
|
|
|
|
remove_node_lru(struct node *node) |
|
|
{ |
|
|
{ |
|
|
struct node_lru *lnode = node_lru(node); |
|
|
struct node_lru *lnode = node_lru(node); |
|
|
list_del(&lnode->lru); |
|
|
list_del(&lnode->lru); |
|
|
init_list_head(&lnode->lru); |
|
|
init_list_head(&lnode->lru); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static void set_forget_time(struct fuse *f, struct node *node) |
|
|
|
|
|
|
|
|
static |
|
|
|
|
|
void |
|
|
|
|
|
set_forget_time(struct fuse *f, |
|
|
|
|
|
struct node *node) |
|
|
{ |
|
|
{ |
|
|
struct node_lru *lnode = node_lru(node); |
|
|
struct node_lru *lnode = node_lru(node); |
|
|
|
|
|
|
|
@ -429,7 +494,9 @@ free_node(struct fuse *f_, |
|
|
free_node_mem(f_,node_); |
|
|
free_node_mem(f_,node_); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static void node_table_reduce(struct node_table *t) |
|
|
|
|
|
|
|
|
static |
|
|
|
|
|
void |
|
|
|
|
|
node_table_reduce(struct node_table *t) |
|
|
{ |
|
|
{ |
|
|
size_t newsize = t->size / 2; |
|
|
size_t newsize = t->size / 2; |
|
|
void *newarray; |
|
|
void *newarray; |
|
@ -445,7 +512,9 @@ static void node_table_reduce(struct node_table *t) |
|
|
t->split = t->size / 2; |
|
|
t->split = t->size / 2; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static void remerge_id(struct fuse *f) |
|
|
|
|
|
|
|
|
static |
|
|
|
|
|
void |
|
|
|
|
|
remerge_id(struct fuse *f) |
|
|
{ |
|
|
{ |
|
|
struct node_table *t = &f->id_table; |
|
|
struct node_table *t = &f->id_table; |
|
|
int iter; |
|
|
int iter; |
|
@ -471,7 +540,9 @@ static void remerge_id(struct fuse *f) |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static void unhash_id(struct fuse *f, struct node *node) |
|
|
|
|
|
|
|
|
static |
|
|
|
|
|
void |
|
|
|
|
|
unhash_id(struct fuse *f, struct node *node) |
|
|
{ |
|
|
{ |
|
|
struct node **nodep = &f->id_table.array[id_hash(f, node->nodeid)]; |
|
|
struct node **nodep = &f->id_table.array[id_hash(f, node->nodeid)]; |
|
|
|
|
|
|
|
|