/* fuse fs的hash函数 */ static unsigned int name_hash(struct fuse *f, fuse_ino_t parent, const char *name) { unsigned int hash = *name;
if (hash) for (name += 1; *name != '\0'; name++) hash = (hash << 5) - hash + *name;
return (hash + parent) % f->name_table_size; }
/* 通过名字hash查找node信息*/ static struct node *lookup_node(struct fuse *f, fuse_ino_t parent, const char *name) { size_t hash = name_hash(f, parent, name); struct node *node;
for (node = f->name_table[hash]; node != NULL; node = node->name_next) if (node->parent->nodeid == parent && strcmp(node->name, name) == 0) return node;
return NULL; }
/* 通过nodeid查找node信息*/ static struct node *get_node_nocheck(struct fuse *f, fuse_ino_t nodeid) { size_t hash = nodeid % f->id_table_size; struct node *node;
for (node = f->id_table[hash]; node != NULL; node = node->id_next) if (node->nodeid == nodeid) return node;
return NULL; }
/* 通过某一个目录项,你想递归获取全局路径 */ static int try_get_path(struct fuse *f, fuse_ino_t nodeid, const char *name, char **path, struct node **wnodep, int ticket) { unsigned bufsize = 256; char *buf; char *s; struct node *node; struct node *wnode = NULL; int err;
*path = NULL;
buf = malloc(bufsize); if (buf == NULL) return -ENOMEM;
s = buf + bufsize - 1; *s = '\0';
if (name != NULL) { s = add_name(&buf, &bufsize, s, name); err = -ENOMEM; if (s == NULL) goto out_free; }
if (wnodep) { assert(ticket); wnode = lookup_node(f, nodeid, name); if (wnode) { if (wnode->treelock != 0 || (wnode->ticket && wnode->ticket != ticket)) { if (!wnode->ticket) wnode->ticket = ticket; err = -EAGAIN; goto out_free; } wnode->treelock = -1; wnode->ticket = 0; } }
/* 逆向遍历目录树,获取目录项的全局路径 */ err = 0; for (node = get_node(f, nodeid); node->nodeid != FUSE_ROOT_ID; node = node->parent) { err = -ENOENT; if (node->name == NULL || node->parent == NULL) goto out_unlock;
err = -ENOMEM; /* 长度不够将自动扩张,默认申请长度为256 */ s = add_name(&buf, &bufsize, s, node->name); if (s == NULL) goto out_unlock;
if (ticket) { err = -EAGAIN; if (node->treelock == -1 || (node->ticket && node->ticket != ticket)) goto out_unlock;
node->treelock++; node->ticket = 0; } }
if (s[0]) memmove(buf, s, bufsize - (s - buf)); else strcpy(buf, "/");
*path = buf; if (wnodep) *wnodep = wnode;
return 0;
out_unlock: if (ticket) unlock_path(f, nodeid, wnode, node, ticket); out_free: free(buf);
return err; }
/* 获取下一个nodeid */ static fuse_ino_t next_id(struct fuse *f) { do { f->ctr = (f->ctr + 1) & 0xffffffff; if (!f->ctr) f->generation ++; /* 如果32bit数以用完,将generation加1 */ } while (f->ctr == 0 || f->ctr == FUSE_UNKNOWN_INO || get_node_nocheck(f, f->ctr) != NULL); return f->ctr; }
/* 获取目录项的fuse_entry_param信息,如果目录项不存在则新建,并加入hash表 lookup、mknod、create等都调用了该方法 */ static int lookup_path(struct fuse *f, fuse_ino_t nodeid, const char *name, const char *path, struct fuse_entry_param *e, struct fuse_file_info *fi) { int res;
memset(e, 0, sizeof(struct fuse_entry_param)); /* 从这里可以看出 如果getattr接口返回错误,则整个过程将会出现问题,故在实现getattr时,即使获取不到文件的信息,也要填充entry的信息 */ if (fi) res = fuse_fs_fgetattr(f->fs, path, &e->attr, fi); else res = fuse_fs_getattr(f->fs, path, &e->attr); if (res == 0) { struct node *node;
node = find_node(f, nodeid, name); if (node == NULL) res = -ENOMEM; else { /* 如果分配子目录项不成功,则返回父目录的信息 */ e->ino = node->nodeid; e->generation = node->generation; e->entry_timeout = f->conf.entry_timeout; e->attr_timeout = f->conf.attr_timeout; if (f->conf.auto_cache) { pthread_mutex_lock(&f->lock); 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); } } return res; }
static struct node *find_node(struct fuse *f, fuse_ino_t parent, const char *name) { struct node *node;
pthread_mutex_lock(&f->lock); if (!name) node = get_node(f, parent); else node = lookup_node(f, parent, name); if (node == NULL) { node = (struct node *) calloc(1, sizeof(struct node)); if (node == NULL) goto out_err;
if (f->conf.noforget) node->nlookup = 1; node->refctr = 1; node->nodeid = next_id(f); /* 选择下一个使用的nodeid */ node->generation = f->generation; node->open_count = 0; node->is_hidden = 0; node->treelock = 0; node->ticket = 0; if (hash_name(f, node, parent, name) == -1) { /* 加入路径名hash表 */ free(node); node = NULL; goto out_err; } hash_id(f, node); /* 加入nodeid hash表 */ } node->nlookup ++; out_err: pthread_mutex_unlock(&f->lock); return node; }
|