📄 fuse-bridge.c
字号:
/* Copyright (c) 2006, 2007, 2008 Z RESEARCH, Inc. <http://www.zresearch.com> This file is part of GlusterFS. GlusterFS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. GlusterFS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.*/#include <stdint.h>#include <signal.h>#include <pthread.h>#ifndef _CONFIG_H#define _CONFIG_H#include "config.h"#endif /* _CONFIG_H */#include "glusterfs.h"#include "logging.h"#include "xlator.h"#include "glusterfs.h"#include "defaults.h"#include "common-utils.h"#include <fuse/fuse_lowlevel.h>#include "fuse-extra.h"#include "list.h"#define BIG_FUSE_CHANNEL_SIZE 1048576struct fuse_private { int fd; struct fuse *fuse; struct fuse_session *se; struct fuse_chan *ch; char *mount_point; data_t *buf; pthread_t fuse_thread; uint32_t direct_io_mode; uint32_t entry_timeout; uint32_t attr_timeout;};typedef struct fuse_private fuse_private_t;#define FI_TO_FD(fi) ((fd_t *)((long)fi->fh))#define FUSE_FOP(state, ret, op_num, fop, args ...) \do { \ call_frame_t *frame = get_call_frame_for_req (state, 1); \ xlator_t *xl = frame->this->children ? \ frame->this->children->xlator : NULL; \ dict_t *refs = frame->root->req_refs; \ frame->root->state = state; \ frame->op = op_num; \ STACK_WIND (frame, ret, xl, xl->fops->fop, args); \ dict_unref (refs); \} while (0)#define FUSE_FOP_NOREPLY(state, op_num, fop, args ...) \do { \ call_frame_t *_frame = get_call_frame_for_req (state, 0); \ xlator_t *xl = _frame->this->children->xlator; \ _frame->root->req_refs = NULL; \ _frame->op = op_num; \ STACK_WIND (_frame, fuse_nop_cbk, xl, xl->fops->fop, args); \} while (0)typedef struct { loc_t loc; inode_t *parent; inode_t *inode; char *name;} fuse_loc_t;typedef struct { void *pool; xlator_t *this; inode_table_t *itable; fuse_loc_t fuse_loc; fuse_loc_t fuse_loc2; fuse_req_t req; int32_t flags; off_t off; size_t size; unsigned long nlookup; fd_t *fd; dict_t *dict; char *name; char is_revalidate;} fuse_state_t;static voidloc_wipe (loc_t *loc){ if (loc->inode) { inode_unref (loc->inode); loc->inode = NULL; } if (loc->path) { freee (loc->path); loc->path = NULL; } if (loc->parent) { inode_unref (loc->parent); loc->parent = NULL; }}static inode_t *dummy_inode (inode_table_t *table){ inode_t *dummy; dummy = calloc (1, sizeof (*dummy)); dummy->table = table; INIT_LIST_HEAD (&dummy->list); INIT_LIST_HEAD (&dummy->inode_hash); INIT_LIST_HEAD (&dummy->fds); INIT_LIST_HEAD (&dummy->dentry.name_hash); INIT_LIST_HEAD (&dummy->dentry.inode_list); dummy->ref = 1; dummy->ctx = get_new_dict (); LOCK_INIT (&dummy->lock); return dummy;}static voidfuse_loc_wipe (fuse_loc_t *fuse_loc){ loc_wipe (&fuse_loc->loc); if (fuse_loc->name) { freee (fuse_loc->name); fuse_loc->name = NULL; } if (fuse_loc->inode) { inode_unref (fuse_loc->inode); fuse_loc->inode = NULL; } if (fuse_loc->parent) { inode_unref (fuse_loc->parent); fuse_loc->parent = NULL; }}static voidfree_state (fuse_state_t *state){ fuse_loc_wipe (&state->fuse_loc); fuse_loc_wipe (&state->fuse_loc2); if (state->dict) { dict_unref (state->dict); state->dict = (void *)0xaaaaeeee; } if (state->name) { freee (state->name); state->name = NULL; }#ifdef DEBUG memset (state, 0x90, sizeof (*state));#endif freee (state); state = NULL;}static int32_tfuse_nop_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret, int32_t op_errno){ if (frame->root->state) free_state (frame->root->state); frame->root->state = EEEEKS; STACK_DESTROY (frame->root); return 0;}fuse_state_t *state_from_req (fuse_req_t req){ fuse_state_t *state; xlator_t *this = fuse_req_userdata (req); state = (void *)calloc (1, sizeof (*state)); state->pool = this->ctx->pool; state->itable = this->itable; state->req = req; state->this = this; return state;}static call_frame_t *get_call_frame_for_req (fuse_state_t *state, char d){ call_pool_t *pool = state->pool; fuse_req_t req = state->req; const struct fuse_ctx *ctx = NULL; call_ctx_t *cctx = NULL; xlator_t *this = NULL; fuse_private_t *priv = NULL; cctx = calloc (1, sizeof (*cctx)); cctx->frames.root = cctx; if (req) { ctx = fuse_req_ctx(req); cctx->uid = ctx->uid; cctx->gid = ctx->gid; cctx->pid = ctx->pid; cctx->unique = req_callid (req); } if (req) { this = fuse_req_userdata (req); cctx->frames.this = this; priv = this->private; } else { cctx->frames.this = state->this; } if (d) { cctx->req_refs = dict_ref (get_new_dict ()); dict_set (cctx->req_refs, NULL, priv->buf); cctx->req_refs->is_locked = 1; } cctx->pool = pool; LOCK (&pool->lock); list_add (&cctx->all_frames, &pool->all_frames); UNLOCK (&pool->lock); cctx->frames.type = GF_OP_TYPE_FOP_REQUEST; return &cctx->frames;}static voidfuse_loc_fill (fuse_loc_t *fuse_loc, fuse_state_t *state, ino_t ino, const char *name){ size_t n; inode_t *inode, *parent = NULL; /* resistance against multiple invocation of loc_fill not to get reference leaks via inode_search() */ inode = fuse_loc->inode; if (!inode) { inode = inode_search (state->itable, ino, name); } fuse_loc->inode = inode; if (name) { if (!fuse_loc->name) fuse_loc->name = strdup (name); parent = fuse_loc->parent; if (!parent) { if (inode) parent = inode_parent (inode, ino); else parent = inode_search (state->itable, ino, NULL); } } fuse_loc->parent = parent; if (inode) { fuse_loc->loc.inode = inode_ref (inode); fuse_loc->loc.ino = inode->ino; } if (name) { n = inode_path (parent, name, NULL, 0) + 1; fuse_loc->loc.path = calloc (1, n); inode_path (parent, name, (char *)fuse_loc->loc.path, n); } else { n = inode_path (inode, NULL, NULL, 0) + 1; fuse_loc->loc.path = calloc (1, n); inode_path (inode, NULL, (char *)fuse_loc->loc.path, n); } }static int32_tfuse_lookup_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret, int32_t op_errno, inode_t *inode, struct stat *stat, dict_t *dict);static int32_tfuse_entry_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret, int32_t op_errno, inode_t *inode, struct stat *buf){ fuse_state_t *state; fuse_req_t req; struct fuse_entry_param e = {0, }; fuse_private_t *priv = this->private; state = frame->root->state; req = state->req; if (!op_ret) { if (inode->ino == 1) buf->st_ino = 1; } if (!op_ret && inode && inode->ino && buf && inode->ino != buf->st_ino) { /* temporary workaround to handle AFR returning differnt inode number */ gf_log ("glusterfs-fuse", GF_LOG_WARNING, "%"PRId64": (%d) %s => inode number changed %"PRId64" -> %"PRId64, frame->root->unique, frame->op, state->fuse_loc.loc.path, inode->ino, buf->st_ino); inode_unref (state->fuse_loc.loc.inode); state->fuse_loc.loc.inode = dummy_inode (state->itable); state->is_revalidate = 2; STACK_WIND (frame, fuse_lookup_cbk, FIRST_CHILD (this), FIRST_CHILD (this)->fops->lookup, &state->fuse_loc.loc, 0); return 0; } if (op_ret == 0) { ino_t ino = buf->st_ino; inode_t *fuse_inode; gf_log ("glusterfs-fuse", GF_LOG_DEBUG, "%"PRId64": (%d) %s => %"PRId64, frame->root->unique, frame->op, state->fuse_loc.loc.path, ino); try_again: fuse_inode = inode_update (state->itable, state->fuse_loc.parent, state->fuse_loc.name, buf); if (fuse_inode->ctx) { /* if the inode was already in the hash, checks to flush out old name hashes */ if ((fuse_inode->st_mode ^ buf->st_mode) & S_IFMT) { gf_log ("glusterfs-fuse", GF_LOG_WARNING, "%"PRId64": (%d) %s => %"PRId64" Rehashing %x/%x", frame->root->unique, frame->op, state->fuse_loc.loc.path, ino, (S_IFMT & buf->st_ino), (S_IFMT & fuse_inode->st_mode)); fuse_inode->st_mode = buf->st_mode; inode_unhash_name (state->itable, fuse_inode); inode_unref (fuse_inode); goto try_again; } if (buf->st_nlink == 1 || S_ISDIR (buf->st_mode)) { /* no other name hashes should exist */ if (!list_empty (&fuse_inode->dentry.inode_list)) { gf_log ("glusterfs-fuse", GF_LOG_WARNING, "%"PRId64": (%d) %s => %"PRId64" Rehashing because st_nlink less than dentry maps", frame->root->unique, frame->op, state->fuse_loc.loc.path, ino); inode_unhash_name (state->itable, fuse_inode); inode_unref (fuse_inode); goto try_again; } if ((state->fuse_loc.parent != fuse_inode->dentry.parent) || ( state->fuse_loc.name && fuse_inode->dentry.name && strcmp (state->fuse_loc.name, fuse_inode->dentry.name))) { gf_log ("glusterfs-fuse", GF_LOG_WARNING, "%"PRId64": (%d) %s => %"PRId64" Rehashing because single st_nlink does not match dentry map", frame->root->unique, frame->op, state->fuse_loc.loc.path, ino); inode_unhash_name (state->itable, fuse_inode); inode_unref (fuse_inode); goto try_again; } } } if ((fuse_inode->ctx != inode->ctx) && list_empty (&fuse_inode->fds)) { dict_t *swap = inode->ctx; inode->ctx = fuse_inode->ctx; fuse_inode->ctx = swap; fuse_inode->generation = inode->generation; fuse_inode->st_mode = buf->st_mode; } inode_lookup (fuse_inode); inode_unref (fuse_inode); /* TODO: make these timeouts configurable (via meta?) */ e.ino = fuse_inode->ino;#ifdef GF_DARWIN_HOST_OS e.generation = 0;#else e.generation = buf->st_ctime;#endif e.entry_timeout = priv->entry_timeout; e.attr_timeout = priv->attr_timeout; e.attr = *buf; e.attr.st_blksize = BIG_FUSE_CHANNEL_SIZE; if (state->fuse_loc.parent) fuse_reply_entry (req, &e); else fuse_reply_attr (req, buf, priv->attr_timeout); } else { if (state->is_revalidate == -1 && op_errno == ENOENT) { gf_log ("glusterfs-fuse", GF_LOG_DEBUG, "%"PRId64": (%d) %s => -1 (%d)", frame->root->unique, frame->op, state->fuse_loc.loc.path, op_errno); } else { gf_log ("glusterfs-fuse", GF_LOG_ERROR, "%"PRId64": (%d) %s => -1 (%d)", frame->root->unique, frame->op, state->fuse_loc.loc.path, op_errno); } if (state->is_revalidate == 1) { inode_unref (state->fuse_loc.loc.inode); state->fuse_loc.loc.inode = dummy_inode (state->itable); state->is_revalidate = 2; STACK_WIND (frame, fuse_lookup_cbk, FIRST_CHILD (this), FIRST_CHILD (this)->fops->lookup, &state->fuse_loc.loc, 0); return 0; } fuse_reply_err (req, op_errno); } free_state (state); STACK_DESTROY (frame->root); return 0;}static int32_tfuse_lookup_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret, int32_t op_errno, inode_t *inode, struct stat *stat, dict_t *dict){ fuse_entry_cbk (frame, cookie, this, op_ret, op_errno, inode, stat); return 0;}static voidfuse_lookup (fuse_req_t req, fuse_ino_t par, const char *name){ fuse_state_t *state; state = state_from_req (req); fuse_loc_fill (&state->fuse_loc, state, par, name); if (!state->fuse_loc.loc.inode) { gf_log ("glusterfs-fuse", GF_LOG_DEBUG, "%"PRId64": LOOKUP %s", req_callid (req), state->fuse_loc.loc.path); state->fuse_loc.loc.inode = dummy_inode (state->itable); /* to differntiate in entry_cbk what kind of call it is */ state->is_revalidate = -1; } else { gf_log ("glusterfs-fuse", GF_LOG_DEBUG, "%"PRId64": LOOKUP %s(%"PRId64")", req_callid (req), state->fuse_loc.loc.path, state->fuse_loc.loc.inode->ino); state->is_revalidate = 1; } FUSE_FOP (state, fuse_lookup_cbk, GF_FOP_LOOKUP, lookup, &state->fuse_loc.loc, 0);}static voidfuse_forget (fuse_req_t req, fuse_ino_t ino, unsigned long nlookup){ inode_t *fuse_inode; fuse_state_t *state; if (ino == 1) { fuse_reply_none (req); return; } state = state_from_req (req); fuse_inode = inode_search (state->itable, ino, NULL); inode_forget (fuse_inode, nlookup); inode_unref (fuse_inode); free_state (state); fuse_reply_none (req);}static int32_tfuse_attr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret, int32_t op_errno, struct stat *buf){ fuse_state_t *state; fuse_req_t req; fuse_private_t *priv = this->private; state = frame->root->state; req = state->req; if (op_ret == 0) { gf_log ("glusterfs-fuse", GF_LOG_DEBUG, "%"PRId64": (%d) %s => %"PRId64, frame->root->unique, frame->op, state->fuse_loc.loc.path ? state->fuse_loc.loc.path : "ERR", buf->st_ino); /* TODO: make these timeouts configurable via meta */ /* TODO: what if the inode number has changed by now */ buf->st_blksize = BIG_FUSE_CHANNEL_SIZE; fuse_reply_attr (req, buf, priv->attr_timeout); } else { gf_log ("glusterfs-fuse", GF_LOG_ERROR, "%"PRId64": (%d) %s => -1 (%d)", frame->root->unique, frame->op, state->fuse_loc.loc.path ? state->fuse_loc.loc.path : "ERR", op_errno); fuse_reply_err (req, op_errno); } free_state (state); STACK_DESTROY (frame->root); return 0;}static voidfuse_getattr (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi){ fuse_state_t *state; state = state_from_req (req); if (ino == 1) { fuse_loc_fill (&state->fuse_loc, state, ino, NULL); if (state->fuse_loc.loc.inode) state->is_revalidate = 1; else state->is_revalidate = -1; FUSE_FOP (state, fuse_lookup_cbk, GF_FOP_LOOKUP, lookup, &state->fuse_loc.loc, 0); return; } fuse_loc_fill (&state->fuse_loc, state, ino, NULL); if (!state->fuse_loc.loc.inode) { gf_log ("glusterfs-fuse", GF_LOG_ERROR, "%"PRId64": GETATTR %"PRId64" (%s) (fuse_loc_fill() returned NULL inode)", req_callid (req), (int64_t)ino, state->fuse_loc.loc.path); fuse_reply_err (req, EINVAL); return; } if (list_empty (&state->fuse_loc.loc.inode->fds) || S_ISDIR (state->fuse_loc.loc.inode->st_mode)) { gf_log ("glusterfs-fuse", GF_LOG_DEBUG, "%"PRId64": GETATTR %"PRId64" (%s)", req_callid (req), (int64_t)ino, state->fuse_loc.loc.path); FUSE_FOP (state, fuse_attr_cbk, GF_FOP_STAT, stat, &state->fuse_loc.loc); } else { fd_t *fd = list_entry (state->fuse_loc.loc.inode->fds.next, fd_t, inode_list); gf_log ("glusterfs-fuse", GF_LOG_DEBUG, "%"PRId64": FGETATTR %"PRId64" (%s/%p)", req_callid (req), (int64_t)ino, state->fuse_loc.loc.path, fd); FUSE_FOP (state,fuse_attr_cbk, GF_FOP_FSTAT, fstat, fd); }}static int32_tfuse_fd_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret, int32_t op_errno, fd_t *fd){ fuse_state_t *state; fuse_req_t req; fuse_private_t *priv = this->private; state = frame->root->state; req = state->req; fd = state->fd; if (op_ret >= 0) { struct fuse_file_info fi = {0, }; LOCK (&fd->inode->lock); list_add (&fd->inode_list, &fd->inode->fds); UNLOCK (&fd->inode->lock); fi.fh = (unsigned long) fd; fi.flags = state->flags;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -