⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fuse-bridge.c

📁 分布式文件系统
💻 C
📖 第 1 页 / 共 4 页
字号:
/*   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 + -