BeeGFS源码分析2-客户端概要分析

  BeeGFS的客户端是由一个内核模块和两个系统服务组成的,这里我们主要分析内核模块。内核模块主要实现了一个Linux的文件系统,因此注册了一个文件系统类型。因为BeeGFS的目录树解析,是在父目录DEntry里找子目录或文件DEntry,逐级迭代完成的,因此在Mount文件系统时,需要从管理节点获取根元数据节点的ID,然后再向根元数据节点查询根目录的DEntry的信息,为后续的目录解析打下基础。
  
  注册文件系统类型
  
  init_fhgfs_client
  
  内核模块初始化:
  
  // fhgfs_client_module\source\program\Main.c
  
  #define BEEGFS_LICENSE "GPL v2"
  
  static int __init init_fhgfs_client(void)
  
  {
  
  #define fail_to(target, msg) \
  
  do { \
  
  printk_fhgfs(KERN_WARNING, msg "\n"); \
  
  goto target; \
  
  } while (0)
  
  if (!beegfs_fault_inject_init() )
  
  fail_to(fail_fault, "could not register fault-injection debugfs dentry");
  
  if (!beegfs_native_init() )
  
  fail_to(fail_native, "could not allocate emergency pools");
  
  if (!FhgfsOpsCommKit_initEmergencyPools() )
  
  fail_to(fail_commkitpools, "could not allocate emergency pools");
  
  if (!SocketTk_initOnce() )
  
  fail_to(fail_socket, "SocketTk initialization failed");
  
  if (!FhgfsOps_initInodeCache() )
  
  fail_to(fail_inode, "Inode cache initialization failed");
  
  if (!RWPagesWork_initworkQueue() )
  
  fail_to(fail_rwpages, "Page work queue registration failed");
  
  if (!FhgfsOpsRemoting_initMsgBufCache() )
  
  fail_to(fail_msgbuf, "Message cache initialization failed");
  
  if (!FhgfsOpsPages_initPageListVecCache() )
  
  fail_to(fail_pagelists, "PageVec cache initialization failed");
  
  if (FhgfsOps_registerFilesystem(www.yuechaoyule.com) )
  
  fail_to(fail_register, "File system registration failed");
  
  ProcFs_createGeneralDir();
  
  printk_fhgfs(KERN_INFO, "File system registered. Type: %s. Version: %s\n",
  
  BEEGFS_MODULE_NAME_STR, App_getVersionStr(www.zheshengyuLe.com) );
  
  return 0;
  
  fail_register:
  
  FhgfsOpsPages_destroyPageListVecCache();
  
  fail_pagelists:
  
  FhgfsOpsRemoting_destroyMsgBufCache();
  
  fail_msgbuf:
  
  RWPagesWork_destroyWorkQueue();
  
  fail_rwpages:
  
  FhgfsOps_destroyInodeCache();
  
  fail_inode:
  
  SocketTk_uninitOnce();
  
  fail_socket:
  
  FhgfsOpsCommKit_releaseEmergencyPools();
  
  fail_commkitpools:
  
  beegfs_native_release(www.dfyldl.com);
  
  fail_native:
  
  beegfs_fault_inject_release();
  
  fail_fault:
  
  return -EPERM;
  
  }
  
  static void __exit exit_fhgfs_client(void)
  
  {
  
  ProcFs_removeGeneralDir();
  
  BUG_ON(FhgfsOps_unregisterFilesystem() );
  
  FhgfsOpsPages_destroyPageListVecCache();
  
  FhgfsOpsRemoting_destroyMsgBufCache();
  
  RWPagesWork_destroyWorkQueue();
  
  FhgfsOps_destroyInodeCache();
  
  SocketTk_uninitOnce();
  
  FhgfsOpsCommKit_releaseEmergencyPools();
  
  beegfs_native_release();
  
  beegfs_fault_inject_release(www.dfyelept.com);
  
  printk_fhgfs(KERN_INFO, "BeeGFS client unloaded.\n"www.htaizx2012.com);
  
  }
  
  module_init(init_fhgfs_client)
  
  module_exit(exit_fhgfs_client)
  
  MODULE_LICENSE(BEEGFS_LICENSE);
  
  MODULE_DESCRIPTION("BeeGFS parallel file system client (http://www.beegfs.com)");
  
  MODULE_AUTHOR("Fraunhofer ITWM, CC-HPC");
  
  FhgfsOps_registerFilesystem
  
  初始化时,向内核注册BeeGFS文件系统类型:
  
  // fhgfs_client_module\source\filesystem\FhgfsOpsSuper.c
  
  static struct file_system_type fhgfs_fs_www.htaizx2012.com type =
  
  {
  
  .name = BEEGFS_MODULE_NAME_STR,
  
  .owner = THIS_MODULE,
  
  .kill_sb = FhgfsOps_killSB,
  
  //.fs_flags = FS_BINARY_MOUNTDATA,www.wanxinylegw.com // not required currently
  
  #ifdef KERNEL_HAS_GET_SB_NODEV
  
  .get_sb = FhgfsOps_getSB,
  
  #else
  
  .mount = FhgfsOps_mount, // basically the same thing as get_sb before
  
  #endif
  
  };
  
  int FhgfsOps_registerFilesystem(void)
  
  {
  
  return register_filesystem(&fhgfs_fs_type);
  
  }
  
  挂载文件系统
  
  FhgfsOps_mount
  
  Mount文件系统时,间接调用FhgfsOps_fillSuper来填充文件系统超级块。
  
  // fhgfs_client_module\source\filesystem\FhgfsOps_versions.c
  
  #ifdef KERNEL_HAS_GET_SB_NODEV
  
  int FhgfsOps_getSB(struct file_system_type *fs_type,
  
  int flags, const char *dev_name, void *data, struct vfsmount *mnt)
  
  {
  
  return get_sb_nodev(fs_type, flags, data, FhgfsOps_fillSuper, mnt);
  
  }
  
  #else
  
  /* kernel 2.6.39 switched from get_sb() to mount(), which provides similar functionality from our point of view. */
  
  struct dentry* FhgfsOps_mount(struct file_system_type *fs_type,
  
  int flags, const char *dev_name, void *data)
  
  {
  
  return mount_nodev(fs_type, flags, data, FhgfsOps_fillSuper);
  
  }
  
  #endif // LINUX_VERSION_CODE
  
  FhgfsOps_fillSuper
  
  初始化文件系统实例的超级块,并初始化根目录的inode,此时ID只是简单的初始化为0,后面会更新成真正的ID:
  
  // fhgfs_client_module\source\filesystem\FhgfsOpsSuper.c
  
  /**
  
  * Fill the file system superblock (vfs object)
  
  */
  
  int FhgfsOps_fillSuper(struct super_block* sb, void* rawMountOptions, int silent)
  
  {
  
  App* app = NULL;
  
  Config* cfg = NULL;
  
  struct inode* rootInode;
  
  struct dentry* rootDentry;
  
  struct kstat kstat;
  
  EntryInfo entryInfo;
  
  FhgfsIsizeHints iSizeHints;
  
  // init per-mount app object
  
  if(__FhgfsOps_constructFsInfo(sb, rawMountOptions) )
  
  return -ECANCELED;
  
  app = FhgfsOps_getApp(sb);
  
  cfg = App_getConfig(app);
  
  // set up super block data
  
  sb->s_maxbytes = MAX_LFS_FILESIZE;
  
  sb->s_blocksize = PAGE_SIZE;
  
  sb->s_blocksize_bits = PAGE_SHIFT;
  
  sb->s_magic = BEEGFS_MAGIC;
  
  sb->s_op = &fhgfs_super_ops;
  
  sb->s_time_gran = 1000000000; // granularity of c/m/atime in ns
  
  sb->s_flags |= MS_NODIRATIME;
  
  if (Config_getSysXAttrsEnabled(cfg ) )
  
  sb->s_xattr = fhgfs_xattr_handlers_noacl; // handle only user xattrs
  
  #ifdef KERNEL_HAS_POSIX_GET_ACL
  
  if (Config_getSysACLsEnabled(cfg) )
  
  {
  
  sb->s_xattr = fhgfs_xattr_handlers; // replace with acl-capable xattr handlers
  
  sb->s_flags |= MS_POSIXACL;
  
  }
  
  #endif // KERNEL_HAS_POSIX_GET_ACL
  
  /* MS_ACTIVE is rather important as it marks the super block being successfully initialized and
  
  * allows the vfs to keep important inodes in the cache. However, it seems it is already
  
  * initialized in vfs generic mount functions.
  
  sb->s_flags |= MS_ACTIVE; // used in iput_final() */
  
  // NFS kernel export is probably not worth the backport efforts for kernels before 2.6.29
  
  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
  
  sb->s_export_op = &fhgfs_export_ops;
  
  #endif
  
  #if defined(KERNEL_HAS_SB_BDI)
  
  sb->s_bdi = FhgfsOps_getBdi(sb);
  
  #endif
  
  // init root inode
  
  memset(&kstat, 0, sizeof(struct kstat) );
  
  kstat.ino = BEEGFS_INODE_ROOT_INO;
  
  kstat.mode = S_IFDIR | 0777; // allow access for everyone
  
  kstat.atime = kstat.mtime = kstat.ctime = current_fs_time(sb);
  
  kstat.uid = FhgfsCommon_getCurrentKernelUserID();
  
  kstat.gid = FhgfsCommon_getCurrentKernelGroupID();
  
  kstat.blksize = Config_getTuneInodeBlockSize(cfg);
  
  kstat.nlink = 1;
  
  // root entryInfo is always updated when someone asks for it (so we just set dummy values here)
  
  EntryInfo_init(&entryInfo, NodeOrGroup_fromGroup(0), StringTk_strDup(""), StringTk_strDup(""),
  
  StringTk_strDup(""), DirEntryType_DIRECTORY, 0);
  
  rootInode = __FhgfsOps_newInode(sb, &kstat, 0, &entryInfo, &iSizeHints);
  
  if(!rootInode || IS_ERR(rootInode) )
  
  {
  
  __FhgfsOps_destructFsInfo(sb);
  
  return IS_ERR(rootInode) ? PTR_ERR(rootInode) : -ENOMEM;
  
  }
  
  rootDentry = d_make_root(rootInode);
  
  if(!rootDentry)
  
  {
  
  __FhgfsOps_destructFsInfo(sb);
  
  return -ENOMEM;
  
  }
  
  #ifdef KERNEL_HAS_S_D_OP
  
  // linux 2.6.38 switched from individual per-dentry to defaul superblock d_ops.
  
  /* note: Only set default dentry operations here, as we don't want those OPs set for the root
  
  * dentry. In fact, setting as before would only slow down everything a bit, due to
  
  * useless revalidation of our root dentry. */
  
  sb->s_d_op = &fhgfs_dentry_ops;
  
  #endif // KERNEL_HAS_S_D_OP
  
  rootDentry->d_time = jiffies;
  
  sb->s_root = rootDentry;
  
  return 0;
  
  }
  
  初始化文件系统
  
  __FhgfsOps_constructFsInfo
  
  申请内存,构造文件系统基本数据结构:
  
  // fhgfs_client_module\source\filesystem\FhgfsOpsSuper.c
  
  /**
  
  * Initialize sb->s_fs_info
  
  *
  
  * @return 0 on success, negative linux error code otherwise
  
  */
  
  int __FhgfsOps_constructFsInfo(struct super_block* sb, void* rawMountOptions)
  
  {
  
  int res;
  
  int appRes;
  
  App* app;
  
  Logger* log;
  
  #if defined(KERNEL_HAS_SB_BDI) && !defined(KERNEL_HAS_SUPER_SETUP_BDI_NAME)
  
  struct backing_dev_info* bdi;
  
  #endif
  
  // use kzalloc to also zero the bdi
  
  FhgfsSuperBlockInfo* sbInfo = kzalloc(sizeof(FhgfsSuperBlockInfo), GFP_KERNEL);
  
  if (!sbInfo)
  
  {
  
  printk_fhgfs_debug(KERN_INFO, "Failed to allocate memory for FhgfsSuperBlockInfo");
  
  sb->s_fs_info = NULL;
  
  return -ENOMEM;
  
  }
  
  sb->s_fs_info = sbInfo;
  
  appRes = __FhgfsOps_initApp(sb, rawMountOptions);
  
  if(appRes)
  
  {
  
  printk_fhgfs_debug(KERN_INFO, "Failed to initialize App object");
  
  res = -EINVAL;
  
  goto outFreeSB;
  
  }
  
  app = FhgfsOps_getApp(sb);
  
  log = App_getLogger(app);
  
  IGNORE_UNUSED_VARIABLE(log);
  
  #if defined(KERNEL_HAS_SB_BDI)
  
  #if defined(KERNEL_HAS_SUPER_SETUP_BDI_NAME) && !defined(KERNEL_HAS_BDI_SETUP_AND_REGISTER)
  
  {
  
  static atomic_long_t bdi_seq = ATOMIC_LONG_INIT(0);
  
  res = super_setup_bdi_name(sb, BEEGFS_MODULE_NAME_STR "-%ld",
  
  atomic_long_inc_return(&bdi_seq));
  
  }
  
  #else
  
  bdi = &sbInfo->bdi;
  
  /* NOTE: The kernel expects a fully initialized bdi structure, so at a minimum it has to be
  
  * allocated by kzalloc() or memset(bdi, 0, sizeof(*bdi)).
  
  * we don't set the congest_* callbacks (like every other filesystem) because those are
  
  * intended for dm and md.
  
  */
  
  bdi->ra_pages = BEEGFS_DEFAULT_READAHEAD_PAGES;
  
  #if defined(KERNEL_HAS_BDI_CAP_MAP_COPY)
  
  res = bdi_setup_and_register(bdi, BEEGFS_MODULE_NAME_STR, BDI_CAP_MAP_COPY);
  
  #else
  
  res = bdi_setup_and_register(bdi, BEEGFS_MODULE_NAME_STR);
  
  #endif
  
  #endif
  
  if (res)
  
  {
  
  Logger_logFormatted(log, 2, __func__, "Failed to init super-block (bdi) information: %d",
  
  res);
  
  __FhgfsOps_uninitApp(app);
  
  goto outFreeSB;
  
  }
  
  #endif
  
  // set root inode attribs to uninit'ed
  
  FhgfsOps_setHasRootEntryInfo(sb, false);
  
  FhgfsOps_setIsRootInited(sb, false);
  
  printk_fhgfs(KERN_INFO, "BeeGFS mount ready.\n");
  
  return 0; // all ok, res should be 0 here
  
  outFreeSB:
  
  kfree(sbInfo);
  
  sb->s_fs_info = NULL;
  
  return res;
  
  }
  
  __FhgfsOps_initApp
  
  解析参数,继续初始化:
  
  // fhgfs_client_module\source\filesystem\FhgfsOpsSuper.c
  
  /**
  
  * Creates and initializes the per-mount application object.
  
  */
  
  int __FhgfsOps_initApp(struct super_block* sb, char* rawMountOptions)
  
  {
  
  MountConfig* mountConfig;
  
  bool parseRes;
  
  App* app;
  
  int appRes;
  
  // create mountConfig (parse from mount options)
  
  mountConfig = MountConfig_construct();
  
  parseRes = MountConfig_parseFromRawOptions(mountConfig, rawMountOptions);
  
  if(!parseRes)
  
  {
  
  MountConfig_destruct(mountConfig);
  
  return APPCODE_INVALID_CONFIG;
  
  }
  
  //printk_fhgfs(KERN_INFO, "Initializing App...\n"); // debug in
  
  app = FhgfsOps_getApp(sb);
  
  App_init(app, mountConfig);
  
  appRes = App_run(app);
  
  if(appRes != APPCODE_NO_ERROR)
  
  { // error occurred => clean up
  
  printk_fhgfs_debug(KERN_INFO, "Stopping App...\n");
  
  App_stop(app);
  
  printk_fhgfs_debug(KERN_INFO, "Cleaning up...\n");
  
  App_uninit(app);
  
  printk_fhgfs_debug(KERN_INFO, "App unitialized.\n");
  
  return appRes;
  
  }
  
  ProcFs_createEntries(app);
  
  return appRes;
  
  }
  
  App_run
  
  初始化客户端基本组件:
  
  // fhgfs_client_module\source\app\App.c
  
  int App_run(App* this)
  
  {
  
  // init data objects & storage
  
  if(!__App_initDataObjects(this, this->mountConfig) )
  
  {
  
  printk_fhgfs(KERN_WARNING,
  
  "Configuration error: Initialization of common objects failed. "
  
  "(Log file may provide additional information.)\n");
  
  this->appResult = APPCODE_INVALID_CONFIG;
  
  return this->appResult;
  
  }
  
  if(!__App_initInodeOperations(this) )
  
  {
  
  printk_fhgfs(KERN_WARNING, "Initialization of inode operations failed.");
  
  this->appResult = APPCODE_INITIALIZATION_ERROR;
  
  return this->appResult;
  
  }
  
  if(!__App_initStorage(this) )
  
  {
  
  printk_fhgfs(KERN_WARNING, "Configuration error: Initialization of storage failed\n");
  
  this->appResult = APPCODE_INVALID_CONFIG;
  
  return this->appResult;
  
  }
  
  // init components
  
  if(!__App_initComponents(this) )
  
  {
  
  printk_fhgfs(KERN_WARNING, "Component initialization error. "
  
  "(Log file may provide additional information.)\n");
  
  this->appResult = APPCODE_INITIALIZATION_ERROR;
  
  return this->appResult;
  
  }
  
  __App_logInfos(this);
  
  // start components
  
  __App_startComponents(this);
  
  // Note: We wait some ms for the node downloads here because the kernel would like to
  
  // check the properties of the root directory directly after mount.
  
  InternodeSyncer_waitForMgmtInit(this->internodeSyncer, 1000);
  
  if(!__App_mountServerCheck(this) )
  
  { // mount check failed => cancel mount
  
  printk_fhgfs(KERN_WARNING, "Mount sanity check failed. Canceling mount. "
  
  "(Log file may provide additional information. Check can be disabled with "
  
  "sysMountSanityCheckMS=0 in the config file.)\n");
  
  this->appResult = APPCODE_INITIALIZATION_ERROR;
  
  return this->appResult;
  
  }
  
  // mark: mount succeeded if we got here!
  
  return this->appResult;
  
  }
  
  __App_initInodeOperations
  
  初始化inode基本操作,以备后面新建inode时使用:
  
  // fhgfs_client_module\source\app\App.c
  
  /**
  
  * Initialized the inode_operations structs depending on what features have been enabled in
  
  * the config.
  
  */
  
  bool __App_initInodeOperations(App* this)
  
  {
  
  Config* cfg = App_getConfig(this);
  
  this->fileInodeOps = os_kzalloc(sizeof(struct inode_operations) );
  
  this->symlinkInodeOps = os_kzalloc(sizeof(struct inode_operations) );
  
  this->dirInodeOps = os_kzalloc(sizeof(struct inode_operations) );
  
  this->specialInodeOps = os_kzalloc(sizeof(struct inode_operations) );
  
  if (!this->fileInodeOps || !this->symlinkInodeOps ||
  
  !this->dirInodeOps || !this->specialInodeOps)
  
  {
  
  SAFE_KFREE(this->fileInodeOps);
  
  SAFE_KFREE(this->symlinkInodeOps);
  
  SAFE_KFREE(this->dirInodeOps);
  
  SAFE_KFREE(this->specialInodeOps);
  
  return false;
  
  }
  
  this->fileInodeOps->getattr = FhgfsOps_getattr;
  
  this->fileInodeOps->permission = FhgfsOps_permission;
  
  this->fileInodeOps->setattr = FhgfsOps_setattr;
  
  #ifdef KERNEL_HAS_GENERIC_READLINK
  
  this->symlinkInodeOps->readlink = generic_readlink; // default is fine for us currently
  
  #endif
  
  #ifdef KERNEL_HAS_GET_LINK
  
  this->symlinkInodeOps->get_link = FhgfsOps_get_link;
  
  #else
  
  this->symlinkInodeOps->follow_link = FhgfsOps_follow_link;
  
  this->symlinkInodeOps->put_link = FhgfsOps_put_link;
  
  #endif
  
  this->symlinkInodeOps->getattr = FhgfsOps_getattr;
  
  this->symlinkInodeOps->permission = FhgfsOps_permission;
  
  this->symlinkInodeOps->setattr = FhgfsOps_setattr;
  
  #ifdef KERNEL_HAS_ATOMIC_OPEN
  
  #ifdef BEEGFS_ENABLE_ATOMIC_OPEN
  
  this->dirInodeOps->atomic_open = FhgfsOps_atomicOpen;
  
  #endif // BEEGFS_ENABLE_ATOMIC_OPEN
  
  #endif
  
  this->dirInodeOps->lookup = FhgfsOps_lookupIntent;
  
  this->dirInodeOps->create = FhgfsOps_createIntent;
  
  this->dirInodeOps->link = FhgfsOps_link;
  
  this->dirInodeOps->unlink = FhgfsOps_unlink;
  
  this->dirInodeOps->mknod = FhgfsOps_mknod;
  
  this->dirInodeOps->symlink = FhgfsOps_symlink;
  
  this->dirInodeOps->mkdir = FhgfsOps_mkdir;
  
  this->dirInodeOps->rmdir = FhgfsOps_rmdir;
  
  this->dirInodeOps->rename = FhgfsOps_rename;
  
  this->dirInodeOps->getattr = FhgfsOps_getattr;
  
  this->dirInodeOps->permission = FhgfsOps_permission;
  
  this->dirInodeOps->setattr = FhgfsOps_setattr;
  
  this->specialInodeOps->setattr = FhgfsOps_setattr;
  
  if (Config_getSysXAttrsEnabled(cfg) )
  
  {
  
  this->fileInodeOps->listxattr = FhgfsOps_listxattr;
  
  this->dirInodeOps->listxattr = FhgfsOps_listxattr;
  
  #ifdef KERNEL_HAS_GENERIC_GETXATTR
  
  this->fileInodeOps->getxattr = generic_getxattr;
  
  this->fileInodeOps->removexattr = FhgfsOps_removexattr;
  
  this->fileInodeOps->setxattr = generic_setxattr;
  
  this->dirInodeOps->getxattr = generic_getxattr;
  
  this->dirInodeOps->removexattr = FhgfsOps_removexattr;
  
  this->dirInodeOps->setxattr = generic_setxattr;
  
  #endif
  
  if (Config_getSysACLsEnabled(cfg) )
  
  {
  
  #ifdef KERNEL_HAS_POSIX_GET_ACL
  
  this->fileInodeOps->get_acl = FhgfsOps_get_acl;
  
  this->dirInodeOps->get_acl = FhgfsOps_get_acl;
  
  // Note: symlinks don't have ACLs
  
  #ifdef KERNEL_HAS_SET_ACL
  
  this->fileInodeOps->set_acl = FhgfsOps_set_acl;
  
  this->dirInodeOps->set_acl = FhgfsOps_set_acl;
  
  #endif // LINUX_VERSION_CODE
  
  #else
  
  Logger_logErr(this->logger, "Init inode operations",
  
  "ACLs activated in config, but not supported on this kernel version.");
  
  return false;
  
  #endif // KERNEL_HAS_POSIX_GET_ACL
  
  }
  
  }
  
  return true;
  
  }
  
  创建和初始化Inode
  
  由FhgfsOps_fillSuper函数初始化调用。
  
  __FhgfsOps_newInode
  
  创建新的Inode时,会调用此函数,根据父目录的DEntry信息(其中保存有父目录所在的元数据节点ID,以及目录ID),访问相应的元数据节点进行子目录或者文件的操作:
  
  // fhgfs_client_module\source\filesystem\FhgfsOpsInode.h
  
  /**
  
  * See __FhgfsOps_newInodeWithParentID for details. This is just a wrapper function.
  
  */
  
  struct inode* __FhgfsOps_newInode(struct super_block* sb, struct kstat* kstat, dev_t dev,
  
  EntryInfo* entryInfo, FhgfsIsizeHints* iSizeHints)
  
  {
  
  return __FhgfsOps_newInodeWithParentID(sb, kstat, dev, entryInfo, (NumNodeID){0}, iSizeHints);
  
  }
  
  /**
  
  * Creates a new inode, inits it from the kstat, inits the ops (depending on the mode)
  
  * and hashes it.
  
  *
  
  * Note: Make sure everything is set in the kstat _before_ you call this, because we hash
  
  * the inode in here (so it can be found and accessed by others when this method returns).
  
  * Note: Consider using the _instantiateInode()-wrapper instead of calling this directly for new
  
  * files/dirs.
  
  *
  
  * @param kstat must have a valid .ino (inode number)
  
  * @param dev set to 0 if not required (only used for special files)
  
  * @param entryInfoPtr contained strings will just be moved to the new inode or free'd in case of an
  
  * error (or cached inode), so don't access the given entryInfoPtr anymore after calling this.
  
  * @param parentNodeID: usually 0, except for NFS export callers, which needs it to connect dentries
  
  * with their parents. By default dentries are connected to their parents, so usually this
  
  * is not required (nfs is an exception).
  
  * @return NULL if not successful
  
  */
  
  struct inode* __FhgfsOps_newInodeWithParentID(struct super_block* sb, struct kstat* kstat,
  
  dev_t dev, EntryInfo* entryInfo, NumNodeID parentNodeID, FhgfsIsizeHints* iSizeHints)
  
  {
  
  App* app = FhgfsOps_getApp(sb);
  
  Config* cfg = App_getConfig(app);
  
  FhgfsInode* fhgfsInode;
  
  FhgfsInodeComparisonInfo comparisonInfo =
  
  {
  
  .inodeHash = kstat->ino, // pre-set by caller
  
  .entryID = entryInfo->entryID,
  
  };
  
  // check inode cache for an existing inode with this ID (and get it) or allocate a new one
  
  struct inode* inode = iget5_locked(sb, kstat->ino,
  
  __FhgfsOps_compareInodeID, __FhgfsOps_initNewInodeDummy, &comparisonInfo);
  
  if(unlikely(!inode || IS_ERR(inode) ) )
  
  goto cleanup_entryInfo; // allocation of new inode failed
  
  fhgfsInode = BEEGFS_INODE(inode);
  
  if( !(inode->i_state & I_NEW) )
  
  { // Found an existing inode, which is possibly actively used. We still need to update it.
  
  FhgfsInode_entryInfoWriteLock(fhgfsInode); // LOCK EntryInfo
  
  FhgfsInode_updateEntryInfoUnlocked(fhgfsInode, entryInfo);
  
  FhgfsInode_entryInfoWriteUnlock(fhgfsInode); // UNLOCK EntryInfo
  
  spin_lock(&inode->i_lock);
  
  __FhgfsOps_applyStatDataToInodeUnlocked(kstat, iSizeHints, inode); // already locked
  
  Time_setToNow(&fhgfsInode->dataCacheTime);
  
  spin_unlock(&inode->i_lock);
  
  goto outNoCleanUp; // we found a matching existing inode => no init needed
  
  }
  
  fhgfsInode->parentNodeID = parentNodeID;
  
  /* note: new inodes are protected by the I_NEW flag from access by other threads until we
  
  * call unlock_new_inode(). */
  
  // init this fresh new inode...
  
  // no one can access inode yet => unlocked
  
  __FhgfsOps_applyStatDataToInodeUnlocked(kstat, iSizeHints, inode);
  
  inode->i_ino = kstat->ino; // pre-set by caller
  
  inode->i_flags |= S_NOATIME | S_NOCMTIME; // timestamps updated by server
  
  mapping_set_gfp_mask(&inode->i_data, GFP_USER); // avoid highmem for page cache pages
  
  // move values (no actual string copy)
  
  fhgfsInode->entryInfo = *entryInfo;
  
  switch (kstat->mode & S_IFMT)
  
  {
  
  case S_IFREG: // regular file
  
  {
  
  if(Config_getTuneFileCacheTypeNum(cfg) == FILECACHETYPE_Native)
  
  {
  
  inode->i_fop = &fhgfs_file_native_ops;
  
  inode->i_data.a_ops = &fhgfs_addrspace_native_ops;
  
  }
  
  else
  
  if(Config_getTuneFileCacheTypeNum(cfg) == FILECACHETYPE_Paged)
  
  { // with pagecache
  
  inode->i_fop = &fhgfs_file_pagecache_ops;
  
  inode->i_data.a_ops = &fhgfs_address_pagecache_ops;
  
  }
  
  else
  
  { // no pagecache (=> either none or buffered cache)
  
  inode->i_fop = &fhgfs_file_buffered_ops;
  
  inode->i_data.a_ops = &fhgfs_address_ops;
  
  }
  
  #ifdef KERNEL_HAS_ADDRESS_SPACE_BDI
  
  inode->i_data.backing_dev_info = FhgfsOps_getBdi(sb);
  
  #endif
  
  inode->i_op = App_getFileInodeOps(app);
  
  } break;
  
  case S_IFDIR: // directory
  
  {
  
  inode->i_op = App_getDirInodeOps(app);
  
  inode->i_fop = &fhgfs_dir_ops;
  
  } break;
  
  case S_IFLNK: // symlink
  
  {
  
  inode->i_op = App_getSymlinkInodeOps(app);
  
  } break;
  
  default: // pipes and other special files
  
  {
  
  inode->i_op = App_getSpecialInodeOps(app);
  
  init_special_inode(inode, kstat->mode, dev);
  
  } break;
  
  }
  
  unlock_new_inode(inode); // remove I_NEW flag, so the inode can be accessed by others
  
  return inode;
  
  // error occured
  
  cleanup_entryInfo:
  
  EntryInfo_uninit(entryInfo);
  
  // found an existing inode
  
  outNoCleanUp:
  
  return inode;
  
  }
  
  App_getFileInodeOps
  
  最后根据文件类型,赋予之前初始化好的inode操作指针:
  
  // fhgfs_client_module\source\app\App.h
  
  struct inode_operations* App_getFileInodeOps(App* this)
  
  {
  
  return this->fileInodeOps;
  
  }
  
  struct inode_operations* App_getSymlinkInodeOps(App* this)
  
  {
  
  return this->symlinkInodeOps;
  
  }
  
  struct inode_operations* App_getDirInodeOps(App* this)
  
  {
  
  return this->dirInodeOps;
  
  }
  
  struct inode_operations* App_getSpecialInodeOps(App* this)
  
  {
  
  return this->specialInodeOps;

转载于:https://www.cnblogs.com/qwangxiao/p/11162963.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值