BeeGFS原始碼分析2-客戶端概要分析
阿新 • • 發佈:2019-07-10
註冊檔案系統型別
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() ) 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() ); 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(); 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(); printk_fhgfs(KERN_INFO, "BeeGFS client unloaded.\n"); } 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_type = { .name = BEEGFS_MODULE_NAME_STR, .owner = THIS_MODULE, .kill_sb = FhgfsOps_killSB, //.fs_flags = FS_BINARY_MOUNTDATA, // 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->special