New upstream version 8.1.0

This commit is contained in:
geos_one
2025-08-10 01:34:16 +02:00
commit c891bb7105
4398 changed files with 838833 additions and 0 deletions

35
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@@ -0,0 +1,35 @@
---
name: Bug report
about: Create a report to help us improve BeeGFS
title: ''
labels: bug, new
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is, which component (mgmtd, meta, storage, client, others or any combination) is affected and what effects (error messages, performance degradation, crashes, ...) can be observed.
**Describe the system**
A short description of the system BeeGFS is running on that covers all information relevant to the issue. For example (but not limited to):
1. Number and type of BeeGFS services and their distribution across physical machines
2. Information about the network interconnect (technology, protocols, topology)
3. Information about underlying file systems and storage hardware
4. Operating system and proprietary driver information (versions, RDMA drivers)
5. Software that is accessing BeeGFS
**To Reproduce**
Steps to reproduce the behavior:
1. Set configuration option "x" to "y" for component "c"
2. Start component "c" on machine "m"
3. Run application "a" with parameters "p"
4. Observe behavior "b"
**Expected behavior**
A clear and concise description of what you expected to happen.
**Log messages, error outputs**
If available, add relevant log files (anonymize if necessary), error messages, `perf` measurements, `strace` outputs, core dumps and everything else you have collected and can share publicly.
**Additional context**
Add any other context not covered above.

View File

@@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest a feature or improvement for BeeGFS
title: ''
labels: enhancement, new
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context about the feature request here.

1
BUILD.txt Symbolic link
View File

@@ -0,0 +1 @@
README.md

140
CMakeLists.txt Normal file
View File

@@ -0,0 +1,140 @@
cmake_minimum_required(VERSION 3.7)
project(
BeeGFS
LANGUAGES CXX C
)
set(BEEGFS_VERSION "" CACHE STRING "Defaults to current git version.")
if(BEEGFS_VERSION STREQUAL "")
execute_process(
COMMAND git describe --match *.* --abbrev=10
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
OUTPUT_VARIABLE BEEGFS_VERSION_FROM_GIT
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if(BEEGFS_VERSION_FROM_GIT STREQUAL "")
message(FATAL_ERROR "Cannot determine BeeGFS version. Specify with `cmake -DBEEGFS_VERSION=...`")
endif()
set(BEEGFS_VERSION ${BEEGFS_VERSION_FROM_GIT} CACHE STRING "Defaults to current git version" FORCE)
endif()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DBEEGFS_VERSION=\\\"${BEEGFS_VERSION}\\\"")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DBEEGFS_VERSION=\\\"${BEEGFS_VERSION}\\\"")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wunused-variable -Woverloaded-virtual -Wno-unused-parameter -Wuninitialized -Wno-missing-field-initializers")
set(BEEGFS_DEBUG OFF CACHE BOOL "Build with debug information.")
if(BEEGFS_DEBUG)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DBEEGFS_DEBUG=1 -Werror")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DBEEGFS_DEBUG=1")
endif()
set(BEEGFS_INSTRUMENTATION "" CACHE STRING "Instrumentation for testing.")
if(BEEGFS_INSTRUMENTATION STREQUAL "")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3")
elseif(BEEGFS_INSTRUMENTATION STREQUAL "coverage")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --coverage -O0")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --coverage -O0")
elseif(BEEGFS_INSTRUMENTATION STREQUAL "address")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -O0")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0")
elseif(BEEGFS_INSTRUMENTATION STREQUAL "thread")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=thread")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=thread -O0")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0")
elseif(BEEGFS_INSTRUMENTATION STREQUAL "undefined")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=undefined")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined -O0")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0")
elseif(BEEGFS_INSTRUMENTATION STREQUAL "iwyu")
if(NOT DEFINED CMAKE_CXX_INCLUDE_WHAT_YOU_USE)
set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE "include-what-you-use")
endif()
list(APPEND CMAKE_CXX_INCLUDE_WHAT_YOU_USE "-Xiwyu" "--mapping_file=${CMAKE_SOURCE_DIR}/iwyu-mappings.imp")
else()
message(FATAL_ERROR "Invalid instrumentation.")
endif()
set(BEEGFS_SKIP_TESTS OFF CACHE BOOL "Skip building and running tests.")
set(BEEGFS_SKIP_CLIENT OFF CACHE BOOL "Skip building the kernel module.")
set(BEEGFS_KERNELDIR "" CACHE PATH "Path to kernel for kernel module (optional).")
set(BEEGFS_OFEDDIR "" CACHE PATH "Path to OFED for kernel module (optional).")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ggdb3")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ggdb3")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lrt")
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
include_directories(common/source)
include_directories(SYSTEM thirdparty/source/boost)
include_directories(SYSTEM thirdparty/source/nu/include)
include_directories(thirdparty/source/gtest/googletest/include)
if(NOT BEEGFS_SKIP_TESTS)
enable_testing()
option(INSTALL_GMOCK OFF)
option(INSTALL_GTEST OFF)
add_subdirectory("thirdparty/source/gtest")
endif()
set(CMAKE_INSTALL_PREFIX "/")
add_subdirectory("beeond")
# add_subdirectory("client_devel")
# add_subdirectory("client_module")
add_subdirectory("common")
add_subdirectory("event_listener")
add_subdirectory("fsck")
add_subdirectory("meta")
add_subdirectory("mon")
add_subdirectory("storage")
add_subdirectory("utils")
add_custom_target(
dkms-install
COMMAND dkms install "beegfs/${BEEGFS_VERSION}"
)
add_custom_target(
dkms-uninstall
COMMAND dkms remove "beegfs/${BEEGFS_VERSION}" --all
)
### Packaging settings ###
set(CPACK_PACKAGE_CONTACT "BeeGFS Maintainers <packages@beegfs.com>")
set(CPACK_PACKAGE_VENDOR "ThinkparQ GmbH")
string(REGEX REPLACE "^([^.]+)\\.([^-]+)-([^-]+)(-.*)?$" "\\1" CPACK_PACKAGE_VERSION_MAJOR "${BEEGFS_VERSION}")
string(REGEX REPLACE "^([^.]+)\\.([^-]+)-([^-]+)(-.*)?$" "\\2" CPACK_PACKAGE_VERSION_MINOR "${BEEGFS_VERSION}")
string(REGEX REPLACE "^([^.]+)\\.([^-]+)-([^-]+)(-.*)?$" "\\3" CPACK_PACKAGE_VERSION_PATCH "${BEEGFS_VERSION}")
set(CPACK_PACKAGING_INSTALL_PREFIX "/")
# silence cpack warnings about non relocatable package.
set(CPACK_PACKAGE_RELOCATABLE OFF)
set(CPACK_GENERATOR "DEB" "RPM")
# enable creation of separate packages
set(CPACK_DEB_COMPONENT_INSTALL ON)
set(CPACK_RPM_COMPONENT_INSTALL ON)
set(CPACK_STRIP_FILES OFF)
# cpack tries to create these directories with nonstandard /
# conflicting permissions in some versions. solve by assuming that
# these directories already exist.
set(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION "/sbin;/usr/sbin")
include(CPack)

118
CODE_OF_CONDUCT.md Normal file
View File

@@ -0,0 +1,118 @@
# BeeGFS Code of Conduct
## Our Pledge
We as BeeGFS contributors and maintainers pledge to make participation in our community a
harassment-free experience for everyone, regardless of age, body size, visible or invisible
disability, ethnicity, sex characteristics, gender identity and expression, level of experience,
education, socio-economic status, nationality, personal appearance, race, caste, color, religion, or
sexual identity and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and
healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes, and learning from the
experience
* Focusing on what is best not just for us as individuals, but for the overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email address, without their
explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting
## Enforcement Responsibilities
The BeeGFS community managers are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in response to any behavior
that they deem inappropriate, threatening, offensive, or harmful.
The BeeGFS community managers have the right and responsibility to remove, edit, or reject comments,
commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of
Conduct, and will communicate reasons for moderation decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when an individual is
officially representing the community in public spaces. Examples of representing our community
include using an official email address, posting via an official social media account, or acting as
an appointed representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community
managers responsible for enforcement at
[community-managers@thinkparq.com](mailto:community-managers@thinkparq.com). All complaints will be
reviewed and investigated promptly and fairly.
All community managers are obligated to respect the privacy and security of the reporter of any
incident.
## Enforcement Guidelines
Community managers will follow these Community Impact Guidelines in determining the consequences for
any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or
unwelcome in the community.
**Consequence**: A private, written warning from community managers, providing clarity around the
nature of the violation and an explanation of why the behavior was inappropriate. A public apology
may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series of actions.
**Consequence**: A warning with consequences for continued behavior. No interaction with the people
involved, including unsolicited interaction with those enforcing the Code of Conduct, for a
specified period of time. This includes avoiding interactions in community spaces as well as
external channels like social media. Violating these terms may lead to a temporary or permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including sustained inappropriate
behavior.
**Consequence**: A temporary ban from any sort of interaction or public communication with the
community for a specified period of time. No public or private interaction with the people involved,
including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this
period. Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community standards, including
sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement
of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.1, available at
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder][Mozilla
CoC].
For answers to common questions about this code of conduct, see the FAQ at
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
[https://www.contributor-covenant.org/translations][translations].
[homepage]: https://www.contributor-covenant.org
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
[Mozilla CoC]: https://github.com/mozilla/diversity
[FAQ]: https://www.contributor-covenant.org/faq
[translations]: https://www.contributor-covenant.org/translations

66
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,66 @@
# Contributing <!-- omit in toc -->
Thank you for your interest in contributing to `beegfs`! 🎉
We appreciate that you want to take the time to contribute. Please follow these steps before
submitting your PR.
# Contents <!-- omit in toc -->
- [ThinkParQ Contributor License Agreement (CLA)](#thinkparq-contributor-license-agreement-cla)
- [Creating a Pull Request](#creating-a-pull-request)
- [Our Commitment](#our-commitment)
# ThinkParQ Contributor License Agreement (CLA)
Before contributions can be accepted we must have a signed CLA on file for all contributor(s):
* Download and fill out and sign the ThinkParQ CLA found at:
https://www.beegfs.io/docs/ThinkParQ_CLA.pdf.
* Email your signed copy to <info@thinkparq.com>.
# Creating a Pull Request
1. Please search [existing issues](https://github.com/ThinkParQ/beegfs/issues) to determine if an
issue already exists for what you intend to contribute.
2. If the issue does not exist, [create a new
one](https://github.com/ThinkParQ/beegfs/issues/new) that explains the bug or feature request.
* Let us know in the issue that you plan on creating a pull request for it. This helps us to keep
track of the pull request and avoid any duplicate efforts.
3. Before creating a pull request, write up a brief proposal in the issue describing what your
change would be and how it would work so that others can comment.
* It's better to wait for feedback from the maintainers before writing code. We don't have an
SLA for our feedback, but we will do our best to respond in a timely manner (at a minimum, to
give you an idea if you're on the right track and that you should proceed, or not).
4. When ready refer to the guidelines and process for submitting a [Pull
Request](https://github.com/ThinkParQ/beegfs-go/wiki/Pull-Requests).
# Our Commitment
While we truly appreciate your efforts on pull requests and will accept contributions as often as we
can, we **cannot** commit to accepting all PRs. Here are a few reasons why a PR may be rejected:
* There are many factors involved in integrating new code into this project including:
* Adding appropriate unit and end-to-end test coverage for new/changed functionality.
* Ensuring adherence with ThinkParQ and industry standards around security and licensing.
* Validating new functionality doesn't raise long-term maintainability and/or supportability
concerns.
* Verifying changes fit with the current and/or planned architecture.
* etc.
In other words, while your bug fix or feature may be perfect as a standalone patch, we have to
ensure the changes also work in all use cases, supported, configurations, and across our support
matrix.
* The BeeGFS development team must plan resources to integrate your code into our code base and CI
platform, and depending on the complexity of your PR, we may or may not have the resources
available to make it happen in a timely fashion. We'll do our best, but typically the earliest
changes can be merged into the master branch is with our next formal release, unless they resolve
a critical bug or security vulnerability.
* Sometimes a PR doesn't fit into our future plans or conflicts with other items on the roadmap.
It's possible that a PR you submit doesn't align with our upcoming plans, thus we won't be able to
use it. It's not personal and why we highly recommend submitting an issue with your proposed
changes so we can provide feedback before you expend significant effort on development.
Thank you for considering to contribute to `beegfs`!

48
LICENSE.txt Normal file
View File

@@ -0,0 +1,48 @@
BeeGFS END USER LICENSE AGREEMENT
=================================
Copyright (c) 2009 Fraunhofer ITWM, 2022 ThinkParQ GmbH
Use of the provided software and libraries is governed by the BeeGFS End User License Agreement
found at https://www.beegfs.io/docs/BeeGFS_EULA.txt.
THIRD PARTY LICENSES
====================
Paul Hsieh OLD BSD license
--------------------------
The files `common/source/common/toolkit/BufferTk.cpp` and `client_module/source/common/toolkit/
HashTk.c` contain a hash implementation distributed under the following license:
Copyright (c) 2010, Paul Hsieh All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted
provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list of
conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this list of
conditions and the following disclaimer in the documentation and/or other materials provided
with the distribution.
Neither my name, Paul Hsieh, nor the names of any other contributors to the code use may
be used to endorse or promote products derived from this software without specific prior
written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR SEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING ANY
WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
See http://www.azillionmonkeys.com/qed/hash.html and http://www.azillionmonkeys.com/qed/weblicense.html.
Other third party code
----------------------
The directory `thirdparty` contains code distributed under the terms of the included license files.

198
Makefile Normal file
View File

@@ -0,0 +1,198 @@
# all variables used by package builds must be exported.
export BEEGFS_DEBUG
export USER_CXXFLAGS
export USER_LDFLAGS
export BEEGFS_DEBUG_RDMA
export BEEGFS_DEBUG_IP
export KDIR
export KSRCDIR
BEEGFS_THIRDPARTY_OPTIONAL =
export BEEGFS_THIRDPARTY_OPTIONAL
WITHOUT_COMM_DEBUG = true
# if version is not set, derive from current git.
# debian epoch for unversioned builds (usually dev builds) is 19 because it was 18 previously.
# versioned builds (usually from tags) are set to epoch 20, allowing upgrades from all previous versions.
ifndef BEEGFS_VERSION
BEEGFS_VERSION := $(shell git describe --tags --match '*.*' --abbrev=10)
BEEGFS_EPOCH := 19
else
BEEGFS_EPOCH := 20
endif
# underscores are not allowed in version strings, because they are not valid semver
ifneq (,$(findstring _,$(BEEGFS_VERSION)))
$(error Underscores not allowed in versions. BEEGFS_VERSION is $(BEEGFS_VERSION))
endif
# dashes in semver for pre-releases should be converted to tildes for package managers in the
# distributions we support
BEEGFS_VERSION_RPM := $(subst -,~,$(BEEGFS_VERSION))
BEEGFS_VERSION_DEB := $(BEEGFS_EPOCH):$(subst -,~,$(BEEGFS_VERSION))
export BEEGFS_VERSION
ifneq ($(NVFS_INCLUDE_PATH),)
BEEGFS_NVFS=1
endif
export BEEGFS_NVFS
PREFIX ?= /opt/beegfs
DESTDIR ?=
DAEMONS := meta storage mon
UTILS := fsck event_listener $(if $(WITHOUT_COMM_DEBUG),,comm_debug)
# exclude components with no runnable tests from `test'.
DO_NOT_TEST := thirdparty event_listener
ALL_COMPONENTS := thirdparty common $(DAEMONS) $(UTILS)
TIDY_COMPONENTS := $(filter-out thirdparty event_listener, $(ALL_COMPONENTS))
all: daemons utils client
.PHONY: daemons
daemons: $(patsubst %,%-all,$(DAEMONS))
@
.PHONY: utils
utils: $(patsubst %,%-all,$(UTILS))
@
.PHONY: $(patsubst %,%-all,$(DAEMONS) $(UTILS))
$(patsubst %,%-all,$(DAEMONS) $(UTILS)): common-all
$(MAKE) -C $(subst -all,,$@)/build all
.PHONY: common-all common
common-all: thirdparty
$(MAKE) -C common/build all
.PHONY: thirdparty
thirdparty:
$(MAKE) -C thirdparty/build all $(BEEGFS_THIRDPARTY_OPTIONAL)
.PHONY: client
client:
$(MAKE) -C client_module/build
.PHONY: tidy
tidy: $(addsuffix -tidy,$(TIDY_COMPONENTS))
@
define tidy_component
.PHONY: $1-tidy
$1-tidy:
+$(MAKE) -C $1/build tidy
endef
$(foreach C,$(TIDY_COMPONENTS),$(eval $(call tidy_component,$(C))))
_tested_components := $(filter-out $(DO_NOT_TEST),$(ALL_COMPONENTS))
.PHONY: test
test: $(patsubst %,%-test,$(_tested_components))
@
define test_component
.PHONY: $1-test
$1-test: $1-all
cd $1/build && ./test-runner --compiler
endef
$(foreach C,$(_tested_components),$(eval $(call test_component,$(C))))
.PHONY: install
install: daemons-install utils-install common-install client-install event_listener-install
@
define install_component
.PHONY: $1-install
$1-install: $1-all
install -t $(DESTDIR)/$(PREFIX)/$2 -D \
$1/build/beegfs-$$(or $$(install_name),$1)
endef
comm_debug-install: install_name=comm-debug
$(foreach D,$(DAEMONS),$(eval $(call install_component,$D,sbin)))
$(foreach U,$(filter-out event_listener,$(UTILS)),$(eval $(call install_component,$U,sbin)))
.PHONY: daemons-install
daemons-install: $(patsubst %,%-install,$(DAEMONS))
@
.PHONY: utils-install
utils-install: $(patsubst %,%-install,$(UTILS))
@
.PHONY: common-install
common-install: common-all
install -t $(DESTDIR)/$(PREFIX)/lib -D \
common/build/libbeegfs_ib.so
.PHONY: client-install
client-install: client
install -t $(DESTDIR)/$(PREFIX)/lib/modules/$(KVER)/kernel/beegfs -D \
client_module/build/beegfs.ko
## Overriding previous generic rule due to non-matching executable name
.PHONY: event_listener-intsall
event_listener-install: event_listener-all
install -t $(DESTDIR)/$(PREFIX)/sbin -D \
event_listener/build/beegfs-event-listener
.PHONY: clean
clean: $(patsubst %,%-clean,$(ALL_COMPONENTS)) client-clean
@
.PHONY: $(patsubst %,%-clean,$(ALL_COMPONENTS))
$(patsubst %,%-clean,$(ALL_COMPONENTS)):
$(MAKE) -C $(subst -clean,,$@)/build clean
.PHONY: client-clean
client-clean:
$(MAKE) -C client_module/build clean
# use DEBUILD_OPTS to pass more options to debuild, eg
# DEBUILD_OPTS='-j32 --prepend-path=/usr/lib/ccache'
# for greater concurrency during build and ccache support
.PHONY: package-deb
package-deb: clean
[ '$(PACKAGE_DIR)' ] || { echo need a PACKAGE_DIR >&2; false; }
! [ -d '$(PACKAGE_DIR)' ] || { echo choose a new directory for PACKAGE_DIR, please >&2; false; }
mkdir -p '$(PACKAGE_DIR)'
cd '$(PACKAGE_DIR)' && \
dpkg-source -I '-I$(PACKAGE_DIR)' -z1 -b '$(dir $(realpath $(firstword $(MAKEFILE_LIST))))' && \
rm -rf build && \
dpkg-source -x *.dsc build && \
( \
cd build; \
sed -i -e 's/beegfs (.*)/beegfs ($(BEEGFS_VERSION_DEB))/' debian/changelog; \
sed -i -e 's/@DATE/$(shell date -R)/' debian/changelog; \
debuild -eBEEGFS_\* $(DEBUILD_OPTS) -us -uc -b 2>&1 | grep -Ev "dir-or-file-in-opt" \
) && \
rm -rf build *.dsc *.tar.gz \
# Replace tilde in package filename with hypens.
# Github release action and api substitutes tilde (~) with dot (.) in file names when uploaded to Github packages.
find -type f -name "*~*.deb" -exec bash -c 'mv "$$1" "$${1//\~/-}"' _ {} \;
# use RPMBUILD_OPTS to pass more options to rpmuild, eg
# RPMBUILD_OPTS='-D "MAKE_CONCURRENCY 32"'
# for greater concurrency during build
.PHONY: package-rpm
package-rpm: clean
[ '$(PACKAGE_DIR)' ] || { echo need a PACKAGE_DIR >&2; false; }
! [ -d '$(PACKAGE_DIR)' ] || { echo choose a new directory for PACKAGE_DIR, please >&2; false; }
mkdir -p $(PACKAGE_DIR)/SOURCES
tar --exclude $(PACKAGE_DIR) --exclude .git --exclude .ccache \
-cf $(PACKAGE_DIR)/SOURCES/beegfs-$(BEEGFS_VERSION_RPM).tar .
rpmbuild --clean -bb beegfs.spec \
--define '_topdir $(abspath $(PACKAGE_DIR))' \
--define 'EPOCH $(BEEGFS_EPOCH)' \
--define 'BEEGFS_VERSION $(BEEGFS_VERSION_RPM)' \
$(RPMBUILD_OPTS) \
# Replace tilde in package filename with hypens.
# Github release action and api substitutes tilde (~) with dot (.) in file names when uploaded to Github packages.
find $(PACKAGE_DIR)/RPMS -type f -name "*~*.rpm" -exec bash -c 'mv "$$1" "$${1//\~/-}"' _ {} \;

185
README.md Normal file
View File

@@ -0,0 +1,185 @@
# BeeGFS Parallel File System
BeeGFS (formerly FhGFS) is the leading parallel cluster file system, developed with a strong focus
on performance and designed for very easy installation and management. If I/O intensive workloads
are your problem, BeeGFS is the solution.
Homepage: https://www.beegfs.io
Documentation: https://doc.beegfs.io/
# Getting Started with BeeGFS
## How do I download BeeGFS?
If you don't need/want to build BeeGFS from sources, prebuilt packages for both x86 and ARM [are
available](https://www.beegfs.io/c/download/) for many popular Linux distributions.
## How do I build BeeGFS from sources?
Prior to BeeGFS 8, all development happened in a private Git repository, with the source code for
each release squashed into a single commit in the public Git repository. As part of BeeGFS 8, the
opportunity came up to rewrite some components and make the full history of the new components
public. For this to happen the source code is split across these repositories:
* `beegfs` - The main public repository containing all original C/C++ components, notably the
Metadata and Storage services along with the Client kernel module and file system checker.
* `beegfs-rust` - New BeeGFS components written in Rust, notably the Management service.
* `beegfs-go` - New BeeGFS components written in Go, notably the BeeGFS command-line tool (CTL).
* `protobuf` - Common protocol buffer and gRPC service definitions along with generated library code
to interact with new BeeGFS services from multiple languages including C++, Go, Rust, etc.
* For Go, comprehensive libraries for fully managing BeeGFS can be found in `beegfs-go`.
It is only necessary to clone the repo(s) containing the component(s) you wish to modify or build
from sources. If you wanted to build everything you would need to clone all three repositories:
* `git clone git@github.com:ThinkParQ/beegfs.git`
* `git clone git@github.com:ThinkParQ/beegfs-rust.git`
* `git clone git@github.com:ThinkParQ/beegfs-go.git`
Then refer to each repositories' README for directions on how to get started including installing any
prerequisites and building packaged or unpackaged binaries for the components provided by that repo.
Note: It is not necessary to clone the `protobuf` repo to build BeeGFS from sources. This is only
needed to modify the protocol buffers or develop an application that integrates with BeeGFS.
# Getting Started with BeeGFS C/C++ Components (this repo)
## Prerequisites
Before building BeeGFS, install the following dependency packages:
### Red Hat / CentOS
```
$ yum install libuuid-devel libibverbs-devel librdmacm-devel libattr-devel redhat-rpm-config \
rpm-build xfsprogs-devel zlib-devel gcc-c++ gcc \
redhat-lsb-core unzip libcurl-devel elfutils-libelf-devel kernel-devel \
libblkid-devel libnl3-devel
```
The `elfutils-libelf-devel` and `kernel-devel` packages can be omitted if you don't intend to
build the client module.
On RHEL releases older than 8, the additional `devtoolset-7` package is also required,
which provides a newer compiler version. The installation steps are outlined here.
Please consult the documentation of your distribution for details.
1. Install a package with repository for your system:
- On CentOS, install package centos-release-scl available in CentOS repository:
```
$ sudo yum install centos-release-scl
```
- On RHEL, enable RHSCL repository for you system:
```
$ sudo yum-config-manager --enable rhel-server-rhscl-7-rpms
```
2. Install the collection:
```
$ sudo yum install devtoolset-7
```
3. Start using software collections:
```
$ scl enable devtoolset-7 bash
```
4. Follow the instructions below to build BeeGFS.
### Debian and Ubuntu
#### Option 1: Semi-automatic installation of build dependencies
Install required utilities:
```
$ apt install --no-install-recommends devscripts equivs
```
Automatically install build dependencies:
```
$ mk-build-deps --install debian/control
```
#### Option 2: Manual installation of build dependencies
Run this command to install the required packages:
```
$ sudo apt install build-essential autoconf automake pkg-config devscripts debhelper \
libtool libattr1-dev xfslibs-dev lsb-release kmod librdmacm-dev libibverbs-dev \
default-jdk zlib1g-dev libssl-dev libcurl4-openssl-dev libblkid-dev uuid-dev \
libnl-3-200 libnl-3-dev libnl-genl-3-200 libnl-route-3-200 libnl-route-3-dev dh-dkms
```
Note: If you have an older Debian system you might have to install the `module-init-tools`
package instead of `kmod`. You also have the choice between the openssl, nss, or gnutls version
of `libcurl-dev`. Choose the one you prefer. On Debian versions older than 12, replace `dh-dkms`
by `dkms`.
## Building Packages
### For development systems
BeeGFS comes with a Makefile capable of building packages for the system on which it is executed.
These include all services, the client module and utilities.
To build RPM packages, run
```
$ make package-rpm PACKAGE_DIR=packages
```
You may also enable parallel execution with
```
$ make package-rpm PACKAGE_DIR=packages RPMBUILD_OPTS="-D 'MAKE_CONCURRENCY <n>'"
```
where `<n>` is the number of concurrent processes.
For DEB packages use this command:
```
$ make package-deb PACKAGE_DIR=packages
```
Or start with `<n>` jobs running in parallel:
```
$ make package-deb PACKAGE_DIR=packages DEBUILD_OPTS="-j<n>"
```
This will generate individual packages for each service (management, meta-data, storage)
as well as the client kernel module and administration tools.
The above examples use `packages` as the output folder for packages, which must not exist
and will be created during the build process.
You may specify any other non-existent directory instead.
Note, however, that having `PACKAGE_DIR` on a NFS or similar network share may slow down
the build process significantly.
### For production systems, or from source snapshots
By default the packaging system generates version numbers suitable only for development
packages. Packages intended for installation on production systems must be built differently.
All instructions to build development packages (as given above) apply, but additionally the
package version must be explicitly set. This is done by passing `BEEGFS_VERSION=<version>`
in the make command line, e.g.
```
$ make package-deb PACKAGE_DIR=packages DEBUILD_OPTS="-j<n>" BEEGFS_VERSION=7.1.4-local1
```
Setting the version explicitly is required to generate packages that can be easily upgraded
with the system package manager.
## Building without packaging
To build the complete project without generating any packages,
simply run
```
$ make
```
The sub-projects have individual make targets, for example `storage-all`,
`meta-all`, etc.
To speed things you can use the `-j` option of `make`.
Additionally, the build system supports `distcc`:
```
$ make DISTCC=distcc
```
# Setup Instructions
Detailed guides on how to configure BeeGFS can be found at
[doc.beegfs.io](https://doc.beegfs.io/latest/index.html)
# Share your thoughts
Of course, we are curious about what you are doing with the BeeGFS sources, so
don't forget to drop us a note...

137
SUPPORT.md Normal file
View File

@@ -0,0 +1,137 @@
Support for BeeGFS <!-- omit in toc -->
==================
- [Overview](#overview)
- [Documentation](#documentation)
- [Community Support](#community-support)
- [Enterprise Support](#enterprise-support)
- [Support Lifecycle and Policies](#support-lifecycle-and-policies)
- [BeeGFS Versioning](#beegfs-versioning)
- [Release Lifecycle](#release-lifecycle)
- [End-of-Life (EOL)](#end-of-life-eol)
- [End-of-Support (EOS)](#end-of-support-eos)
- [Example Scenarios](#example-scenarios)
# Overview
The BeeGFS community edition is available free of charge and shares a common codebase with our
[enterprise edition](https://www.beegfs.io/c/enterprise/enterprise-features/). The enterprise
edition includes support alongside additional features, and is how we fund ongoing BeeGFS
development. Regardless of whether you use the paid or community edition, we welcome [GitHub
issues](https://github.com/ThinkParQ/beegfs/issues) for bugs and feature requests from everyone in
our community.
**Please note:** GitHub issues are not the place for general questions on how to deploy or use
BeeGFS. Refer to the resources below. If you are unsure if your issue is a bug or "working as
designed," feel free to open an issue, and we will politely direct you to community support options
if necessary.
Thank you for being part of the BeeGFS community!
# Documentation
* [BeeGFS Documentation Site](https://doc.beegfs.io).
* [Building BeeGFS from sources](README.md) (for developers).
* Check out the [contributing guide](CONTRIBUTING.md) if you'd like to contribute to BeeGFS!
# Community Support
BeeGFS is fortunate to have an active community of users who are often willing to help with general
questions on designing, deploying, and otherwise administering BeeGFS.
* [BeeGFS Google Groups](https://groups.google.com/g/fhgfs-user).
* [GitHub Discussions](https://github.com/ThinkParQ/beegfs/discussions).
While our team moderates these forums to ensure posts are on-topic and meet our [Code of
Conduct](code-of-conduct.md), we generally do not actively respond to posts. However, we are always
keeping an eye out for ways to improve BeeGFS and our documentation.
# Enterprise Support
The BeeGFS [enterprise edition](https://www.beegfs.io/c/enterprise/enterprise-features/) offers:
- Dedicated support from BeeGFS experts.
- Access to features not available in the community edition such as storage pools and quotas.
- Assistance with designing, deploying, and managing BeeGFS.
If you are a current BeeGFS enterprise customer with a valid support contract, please contact our
support team via the channels specified in your support contract documentation.
If you are interested in enterprise support, professional services, or learning more about the
additional features of the enterprise edition, please contact us at
[info@thinkparq.com](mailto:info@thinkparq.com).
# Support Lifecycle and Policies
## BeeGFS Versioning
Starting with BeeGFS 8, we will more strictly adhere to [Semantic Versioning](https://semver.org/)
to ensure a predictable and consistent support lifecycle. BeeGFS releases follow a MAJOR.MINOR.PATCH
versioning scheme, where:
* Major releases (e.g., 8.x) introduce breaking changes and new features.
* Minor releases (e.g., 8.1, 8.2) add functionality in a backward-compatible manner.
* Note: Enabling new functionality typically requires all components to be on the same version
otherwise older components may see errors about unknown functionality.
* Patch releases (e.g., 8.0.1, 8.1.2) contain only backward-compatible bug fixes and security
updates.
## Release Lifecycle
* Latest Major Release (e.g., BeeGFS 8.x)
* Actively maintained with bug fixes, security patches, and feature enhancements.
* Receives support for new operating systems, kernels, and DOCA/OFED versions.
* New deployments are recommended to use this version to ensure continued support without
requiring a major upgrade.
* Previous Major Releases (e.g., BeeGFS 7.x)
* Receive critical security and stability fixes until the release reaches EOL.
* Receive best effort support for new operating systems, kernels, and DOCA/OFED versions until the
release reaches EOL.
* New deployments are strongly discouraged from using these versions.
* Minor and Patch Releases (e.g., 8.1.0, 8.0.1)
* To receive bug fixes and security patches, users must upgrade to the latest available patch or
minor version within their major release, as fixes will not be backported to older minor
versions.
## End-of-Life (EOL)
* A BeeGFS release reaches EOL when it no longer receives regular updates, including:
* Bug fixes
* Security patches
* Support for new OS/kernel/DOCA/OFED versions.
* New deployments should not be performed using a release that has reached EOL.
* Users with active support contracts for systems originally deployed on that version may still
receive best-effort patches if they cannot upgrade to the latest major version due to
incompatibilities.
* Patches made after a release reaches EOL will typically be private unless they address a
security vulnerability that affects all users.
* EOL timing: When a new major BeeGFS is made available, adoption trends, stability, and customer
feedback are considered before announcing the EOL date for the previous major release. Generally
the EOL date will be no less than 12 months from the release date of the new major version.
## End-of-Support (EOS)
* When a BeeGFS release reaches EOS it is considered obsolete and no further updates will be
made—even for customers with a support contract.
* EOS timing: Depending on customer demand and extended support contracts EOS will typically follow
EOL by 12-24 months.
* ThinkParQ support will assist all customers holding a valid support contract regardless if the
BeeGFS version has reached EOS.
If support identifies a software issue in an EOS release, the recommended action will be to upgrade
to a supported version where the issue is (or can be) resolved. Support will assist as needed to
define a recommended upgrade path.
## Example Scenarios
* A user with/without support running BeeGFS 8.0.0 finds a bug before BeeGFS 7 reaches EOL:
* If critical, it may be fixed in a patch release (8.0.1).
* If less severe or found/fixed close to the next scheduled release, it may be fixed in a minor
release (8.1.0).
* If this bug also affects BeeGFS 7, it would be backported to the latest 7.x patch release (e.g.,
7.4.x).
* A user with support running BeeGFS 7 after it reaches EOL finds a bug impacting performance or
stability:
* If the bug affects BeeGFS 8 and has not yet been fixed, a fix will be made in the latest 8.x
release and the user advised to upgrade if possible.
* If the user is unable to upgrade to BeeGFS 8 due to incompatibilities in their OS/kernel/etc.,
the feasibility of patching BeeGFS 7 will be evaluated and decided on a case-by-case basis
working in conjunction with the user to identify the best possible solution.

631
beegfs.spec Normal file
View File

@@ -0,0 +1,631 @@
%define VER %(echo '%{BEEGFS_VERSION}' | cut -d - -f 1)
%define BEEGFS_MAJOR_VERSION %(echo '%{BEEGFS_VERSION}' | cut -d . -f 1)
%define CLIENT_DIR /opt/beegfs/src/client/client_module_%{BEEGFS_MAJOR_VERSION}
%define CLIENT_COMPAT_DIR /opt/beegfs/src/client/client_compat_module_%{BEEGFS_MAJOR_VERSION}
%define is_sles %(test -f /etc/os-release && grep -q "openSUSE" /etc/os-release || test -f /etc/SUSEConnect && echo 1 || echo 0)
%if %is_sles
%define distver %(release="`rpm -qf --queryformat='%%{VERSION}' /etc/os-release 2> /dev/null | tr . : | sed s/:.*$//g`" ; if test $? != 0 ; then release="" ; fi ; echo "$release")
%define RELEASE sles%{distver}
%else
%if %{defined ?dist}
%define RELEASE %(tr -d . <<< %{?dist})
%else
%define RELEASE generic
%endif
%endif
%define post_package() if [ "$1" = 1 ] \
then \
output=$(systemctl is-system-running 2> /dev/null) \
if [ "$?" == 127 ] \
then \
chkconfig %1 on \
elif [ "$?" == 0 ] || ( [ "$output" != "offline" ] && [ "$output" != "unknown" ] ) \
then \
systemctl enable %1.service \
else \
chkconfig %1 on \
fi \
fi
%define preun_package() if [ "$1" = 0 ] \
then \
output=$(systemctl is-system-running 2> /dev/null) \
if [ "$?" == 127 ] \
then \
chkconfig %1 off \
elif [ "$?" == 0 ] || ( [ "$output" != "offline" ] && [ "$output" != "unknown" ] ) \
then \
systemctl disable %1.service \
else \
chkconfig %1 off \
fi \
fi
Name: beegfs
Summary: BeeGFS parallel file system
License: BeeGFS EULA
Version: %{VER}
Release: %{RELEASE}
URL: http://www.beegfs.io
Source: beegfs-%{BEEGFS_VERSION}.tar
Vendor: ThinkParQ GmbH
BuildRoot: %{_tmppath}/beegfs-root
Epoch: %{EPOCH}
%description
Distribution of the BeeGFS parallel filesystem.
%clean
rm -rf %{buildroot}
%prep
%setup -c
%define make_j %{?MAKE_CONCURRENCY:-j %{MAKE_CONCURRENCY}}
%build
export BEEGFS_VERSION=%{BEEGFS_VERSION}
export WITHOUT_COMM_DEBUG=1
export BEEGFS_NVFS=1
make %make_j daemons utils
%install
export BEEGFS_VERSION=%{BEEGFS_VERSION}
export WITHOUT_COMM_DEBUG=1
# makefiles need some adjustments still
mkdir -p \
${RPM_BUILD_ROOT}/opt/beegfs/sbin \
${RPM_BUILD_ROOT}/opt/beegfs/lib \
${RPM_BUILD_ROOT}/usr/bin \
${RPM_BUILD_ROOT}/usr/include \
${RPM_BUILD_ROOT}/sbin \
${RPM_BUILD_ROOT}/usr/share/doc/beegfs-client-devel/examples/ \
${RPM_BUILD_ROOT}/usr/share/doc/beegfs-utils-devel/examples/beegfs-event-listener/build \
${RPM_BUILD_ROOT}/usr/share/doc/beegfs-utils-devel/examples/beegfs-event-listener/source \
${RPM_BUILD_ROOT}/etc/bash_completion.d
##########
########## libbeegfs-ib files
##########
install -D common/build/libbeegfs_ib.so \
${RPM_BUILD_ROOT}/opt/beegfs/lib/libbeegfs_ib.so
install -D debian/copyright ${RPM_BUILD_ROOT}/usr/share/doc/libbeegfs-ib/copyright
##########
########## daemons, utils
##########
make DESTDIR=${RPM_BUILD_ROOT} daemons-install utils-install
##########
########## common directories for extra files
##########
mkdir -p \
${RPM_BUILD_ROOT}/etc/beegfs \
${RPM_BUILD_ROOT}/etc/init.d \
${RPM_BUILD_ROOT}/opt/beegfs/scripts/grafana
##########
########## meta extra files
##########
cp -a meta/build/dist/etc/*.conf ${RPM_BUILD_ROOT}/etc/beegfs
#install systemd unit description
install -D -m644 meta/build/dist/usr/lib/systemd/system/beegfs-meta.service \
${RPM_BUILD_ROOT}/usr/lib/systemd/system/beegfs-meta.service
install -D -m644 meta/build/dist/usr/lib/systemd/system/beegfs-meta@.service \
${RPM_BUILD_ROOT}/usr/lib/systemd/system/beegfs-meta@.service
install -D meta/build/dist/sbin/beegfs-setup-meta \
${RPM_BUILD_ROOT}/opt/beegfs/sbin/beegfs-setup-meta
install -D meta/build/dist/etc/default/beegfs-meta ${RPM_BUILD_ROOT}/etc/default/beegfs-meta
install -D debian/copyright ${RPM_BUILD_ROOT}/usr/share/doc/beegfs-meta/copyright
##########
########## storage extra files
##########
cp -a storage/build/dist/etc/*.conf ${RPM_BUILD_ROOT}/etc/beegfs/
#install systemd unit description
install -D -m644 storage/build/dist/usr/lib/systemd/system/beegfs-storage.service \
${RPM_BUILD_ROOT}/usr/lib/systemd/system/beegfs-storage.service
install -D -m644 storage/build/dist/usr/lib/systemd/system/beegfs-storage@.service \
${RPM_BUILD_ROOT}/usr/lib/systemd/system/beegfs-storage@.service
install -D storage/build/dist/sbin/beegfs-setup-storage \
${RPM_BUILD_ROOT}/opt/beegfs/sbin/beegfs-setup-storage
install -D storage/build/dist/etc/default/beegfs-storage ${RPM_BUILD_ROOT}/etc/default/beegfs-storage
install -D debian/copyright ${RPM_BUILD_ROOT}/usr/share/doc/beegfs-storage/copyright
##########
########## mon extra files
##########
install -D -m644 mon/build/dist/etc/beegfs-mon.conf ${RPM_BUILD_ROOT}/etc/beegfs
install -D -m600 mon/build/dist/etc/beegfs-mon.auth ${RPM_BUILD_ROOT}/etc/beegfs
#install systemd unit description
install -D -m644 mon/build/dist/usr/lib/systemd/system/beegfs-mon.service \
${RPM_BUILD_ROOT}/usr/lib/systemd/system/beegfs-mon.service
install -D -m644 mon/build/dist/usr/lib/systemd/system/beegfs-mon@.service \
${RPM_BUILD_ROOT}/usr/lib/systemd/system/beegfs-mon@.service
install -D mon/build/dist/etc/default/beegfs-mon ${RPM_BUILD_ROOT}/etc/default/beegfs-mon
cp -a mon/scripts/grafana/* ${RPM_BUILD_ROOT}/opt/beegfs/scripts/grafana/
install -D debian/copyright ${RPM_BUILD_ROOT}/usr/share/doc/beegfs-mon/copyright
##########
########## mon-grafana
##########
install -D debian/copyright ${RPM_BUILD_ROOT}/usr/share/doc/beegfs-mon-grafana/copyright
##########
########## utils
##########
cp -a utils/scripts/fsck.beegfs ${RPM_BUILD_ROOT}/sbin/
ln -s /opt/beegfs/sbin/beegfs-fsck ${RPM_BUILD_ROOT}/usr/bin/beegfs-fsck
install -D debian/copyright ${RPM_BUILD_ROOT}/usr/share/doc/beegfs-utils/copyright
##########
########## utils-devel
##########
cp -a event_listener/include/* ${RPM_BUILD_ROOT}/usr/include/
cp -a event_listener/build/Makefile \
${RPM_BUILD_ROOT}/usr/share/doc/beegfs-utils-devel/examples/beegfs-event-listener/build/
cp -a event_listener/source/beegfs-event-listener.cpp \
event_listener/source/beegfs-file-event-log.cpp \
event_listener/source/seqpacket-reader-new-protocol.cpp \
${RPM_BUILD_ROOT}/usr/share/doc/beegfs-utils-devel/examples/beegfs-event-listener/source/
install -D debian/copyright ${RPM_BUILD_ROOT}/usr/share/doc/beegfs-utils-devel/copyright
##########
########## client
##########
make -C client_module/build %make_j \
RELEASE_PATH=${RPM_BUILD_ROOT}/opt/beegfs/src/client KDIR="%{KDIR}" V=1 \
prepare_release
cp client_module/build/dist/etc/*.conf ${RPM_BUILD_ROOT}/etc/beegfs/
cp client_module/build/dist/etc/beegfs-client-build.mk ${RPM_BUILD_ROOT}/etc/beegfs/beegfs-client-build.mk
# compat files
cp -a ${RPM_BUILD_ROOT}/%{CLIENT_DIR} ${RPM_BUILD_ROOT}/%{CLIENT_COMPAT_DIR}
echo beegfs-%{BEEGFS_MAJOR_VERSION} | tr -d . > ${RPM_BUILD_ROOT}/%{CLIENT_COMPAT_DIR}/build/beegfs.fstype
# we use the redhat script for all rpm distros, as we now provide our own
# daemon() and killproc() function library (derived from redhat)
install -D client_module/build/dist/sbin/beegfs-client.init ${RPM_BUILD_ROOT}/opt/beegfs/sbin/beegfs-client
%if !%is_sles
ln -s /opt/beegfs/sbin/beegfs-client ${RPM_BUILD_ROOT}/etc/init.d/beegfs-client
%endif
#install systemd unit description
install -D -m644 client_module/build/dist/usr/lib/systemd/system/beegfs-client.service \
${RPM_BUILD_ROOT}/usr/lib/systemd/system/beegfs-client.service
install -D -m644 client_module/build/dist/usr/lib/systemd/system/beegfs-client@.service \
${RPM_BUILD_ROOT}/usr/lib/systemd/system/beegfs-client@.service
install -D client_module/build/dist/etc/default/beegfs-client ${RPM_BUILD_ROOT}/etc/default/beegfs-client
install -D client_module/scripts/etc/beegfs/lib/init-multi-mode.beegfs-client \
${RPM_BUILD_ROOT}/etc/beegfs/lib/init-multi-mode.beegfs-client
install -D client_module/build/dist/sbin/beegfs-setup-client \
${RPM_BUILD_ROOT}/opt/beegfs/sbin/beegfs-setup-client
install -D client_module/build/dist/sbin/mount.beegfs \
${RPM_BUILD_ROOT}/sbin/mount.beegfs
install -D client_module/build/dist/etc/beegfs-client-mount-hook.example \
${RPM_BUILD_ROOT}/etc/beegfs/beegfs-client-mount-hook.example
install -D debian/copyright ${RPM_BUILD_ROOT}/usr/share/doc/beegfs-client/copyright
##########
########## client-dkms
##########
cp client_module/build/dist/etc/*.conf ${RPM_BUILD_ROOT}/etc/beegfs/
mkdir -p ${RPM_BUILD_ROOT}/usr/src/beegfs-%{VER}
cp -r client_module/build ${RPM_BUILD_ROOT}/usr/src/beegfs-%{VER}
cp -r client_module/source ${RPM_BUILD_ROOT}/usr/src/beegfs-%{VER}
cp -r client_module/include ${RPM_BUILD_ROOT}/usr/src/beegfs-%{VER}
rm -Rf ${RPM_BUILD_ROOT}/usr/src/beegfs-%{VER}/build/dist
install -D client_module/build/dist/sbin/beegfs-setup-client \
${RPM_BUILD_ROOT}/opt/beegfs/sbin/beegfs-setup-client
install -D client_module/build/dist/sbin/mount.beegfs \
${RPM_BUILD_ROOT}/sbin/mount.beegfs
sed -e 's/__VERSION__/%{VER}/g' -e 's/__NAME__/beegfs/g' -e 's/__MODNAME__/beegfs/g' \
< client_module/dkms.conf.in \
> ${RPM_BUILD_ROOT}/usr/src/beegfs-%{VER}/dkms.conf
install -D debian/copyright ${RPM_BUILD_ROOT}/usr/share/doc/beegfs-client-dkms/copyright
##########
########## client-compat
##########
install -D debian/copyright ${RPM_BUILD_ROOT}/usr/share/doc/beegfs-client-compat/copyright
##########
########## client-devel
##########
cp -a client_devel/include/beegfs \
${RPM_BUILD_ROOT}/usr/include/
cp -a client_module/include/uapi/* \
${RPM_BUILD_ROOT}/usr/include/beegfs/
sed -i '~s~uapi/beegfs_client~beegfs/beegfs_client~g' \
${RPM_BUILD_ROOT}/usr/include/beegfs/*.h
cp -a client_devel/build/dist/usr/share/doc/beegfs-client-devel/examples/* \
${RPM_BUILD_ROOT}/usr/share/doc/beegfs-client-devel/examples/
install -D debian/copyright ${RPM_BUILD_ROOT}/usr/share/doc/beegfs-client-devel/copyright
##########
########## beeond
##########
install -D beeond/source/beeond ${RPM_BUILD_ROOT}/opt/beegfs/sbin/beeond
install -D beeond/source/beeond-cp ${RPM_BUILD_ROOT}/opt/beegfs/sbin/beeond-cp
cp beeond/scripts/lib/* ${RPM_BUILD_ROOT}/opt/beegfs/lib/
ln -s /opt/beegfs/sbin/beeond ${RPM_BUILD_ROOT}/usr/bin/beeond
ln -s /opt/beegfs/sbin/beeond-cp ${RPM_BUILD_ROOT}/usr/bin/beeond-cp
install -D debian/copyright ${RPM_BUILD_ROOT}/usr/share/doc/beeond/copyright
%package -n libbeegfs-ib
Summary: BeeGFS InfiniBand support
Group: Software/Other
Buildrequires: librdmacm-devel, libibverbs-devel
BuildRequires: libnl3-devel
Provides: libbeegfs-ib = %{VER}
%description -n libbeegfs-ib
This package contains support libraries for InfiniBand.
%files -n libbeegfs-ib
%license /usr/share/doc/libbeegfs-ib/copyright
/opt/beegfs/lib/libbeegfs_ib.so
%package meta
Summary: BeeGFS meta server daemon
Group: Software/Other
BuildRequires: libnl3-devel
Provides: beegfs-meta = %{VER}
%description meta
This package contains the BeeGFS meta server binaries.
%post meta
%post_package beegfs-meta
%preun meta
%preun_package beegfs-meta
%files meta
%defattr(-,root,root)
%license /usr/share/doc/beegfs-meta/copyright
%config(noreplace) /etc/beegfs/beegfs-meta.conf
%config(noreplace) /etc/default/beegfs-meta
/opt/beegfs/sbin/beegfs-meta
/opt/beegfs/sbin/beegfs-setup-meta
/usr/lib/systemd/system/beegfs-meta.service
/usr/lib/systemd/system/beegfs-meta@.service
%package storage
Summary: BeeGFS storage server daemon
Group: Software/Other
BuildRequires: libnl3-devel
Provides: beegfs-storage = %{VER}
%description storage
This package contains the BeeGFS storage server binaries.
%post storage
%post_package beegfs-storage
%preun storage
%preun_package beegfs-storage
%files storage
%defattr(-,root,root)
%license /usr/share/doc/beegfs-storage/copyright
%config(noreplace) /etc/beegfs/beegfs-storage.conf
%config(noreplace) /etc/default/beegfs-storage
/opt/beegfs/sbin/beegfs-storage
/opt/beegfs/sbin/beegfs-setup-storage
/usr/lib/systemd/system/beegfs-storage.service
/usr/lib/systemd/system/beegfs-storage@.service
%package mon
Summary: BeeGFS mon server daemon
Group: Software/Other
BuildRequires: libnl3-devel
Provides: beegfs-mon = %{VER}
%description mon
This package contains the BeeGFS mon server binaries.
%post mon
%post_package beegfs-mon
%preun mon
%preun_package beegfs-mon
%files mon
%defattr(-,root,root)
%license /usr/share/doc/beegfs-mon/copyright
%config(noreplace) /etc/beegfs/beegfs-mon.conf
%config(noreplace) /etc/beegfs/beegfs-mon.auth
%config(noreplace) /etc/default/beegfs-mon
/opt/beegfs/sbin/beegfs-mon
/usr/lib/systemd/system/beegfs-mon.service
/usr/lib/systemd/system/beegfs-mon@.service
%package mon-grafana
Summary: BeeGFS mon dashboards for Grafana
Group: Software/Other
BuildArch: noarch
Provides: beegfs-mon-grafana = %{VER}
%description mon-grafana
This package contains the BeeGFS mon dashboards to display monitoring data in Grafana.
The default dashboard setup requires both Grafana, and InfluxDB.
%files mon-grafana
%license /usr/share/doc/beegfs-mon-grafana/copyright
%defattr(-,root,root)
/opt/beegfs/scripts/grafana/
%package utils
Summary: BeeGFS utilities
Group: Software/Other
BuildRequires: libnl3-devel
Provides: beegfs-utils = %{VER}
%description utils
This package contains BeeGFS utilities.
%files utils
%defattr(-,root,root)
%license /usr/share/doc/beegfs-utils/copyright
%attr(0755, root, root) /opt/beegfs/sbin/beegfs-fsck
/usr/bin/beegfs-fsck
/sbin/fsck.beegfs
/opt/beegfs/sbin/beegfs-event-listener
%package utils-devel
Summary: BeeGFS utils devel files
Group: Software/Other
BuildArch: noarch
Provides: beegfs-utils-devel = %{VER}
%description utils-devel
This package contains BeeGFS utils development files and examples.
%files utils-devel
%defattr(-,root,root)
%license /usr/share/doc/beegfs-utils-devel/copyright
/usr/include/beegfs/beegfs_file_event_log.hpp
/usr/include/beegfs/seqpacket-reader-new-protocol.hpp
/usr/share/doc/beegfs-utils-devel/examples/beegfs-event-listener/*
%package client
Summary: BeeGFS client kernel module
License: GPL v2
Group: Software/Other
BuildArch: noarch
%if %is_sles
Requires: make, gcc, kernel-default-devel, elfutils
%else
Requires: make, gcc
Recommends: kernel-devel, elfutils-libelf-devel
%endif
Conflicts: beegfs-client-dkms
Provides: beegfs-client = %{VER}
%description client
This package contains scripts, config and source files to build and
start beegfs-client.
%post client
%post_package beegfs-client
# make the script to run autobuild
mkdir -p /var/lib/beegfs/client
touch /var/lib/beegfs/client/force-auto-build
%preun client
%preun_package beegfs-client
%files client
%defattr(-,root,root)
%license /usr/share/doc/beegfs-client/copyright
%config(noreplace) /etc/beegfs/beegfs-client-autobuild.conf
%config(noreplace) /etc/beegfs/beegfs-client-mount-hook.example
%config(noreplace) /etc/beegfs/beegfs-client.conf
%config(noreplace) /etc/beegfs/beegfs-mounts.conf
%dir /etc/beegfs/lib/
%config(noreplace) /etc/beegfs/lib/init-multi-mode.beegfs-client
%config(noreplace) /etc/default/beegfs-client
/opt/beegfs/sbin/beegfs-client
%if !%is_sles
/etc/init.d/beegfs-client
%endif
/opt/beegfs/sbin/beegfs-setup-client
/sbin/mount.beegfs
/usr/lib/systemd/system/beegfs-client.service
/usr/lib/systemd/system/beegfs-client@.service
%{CLIENT_DIR}
%postun client
rm -rf /lib/modules/*/updates/fs/beegfs_autobuild
%package client-dkms
Summary: BeeGFS client kernel module (DKMS version)
License: GPL v2
Group: Software/Other
BuildArch: noarch
%if %is_sles
Requires: make, dkms, kernel-default-devel, elfutils
%else
Requires: make, dkms
Recommends: kernel-devel, elfutils-libelf-devel
%endif
Conflicts: beegfs-client
Provides: beegfs-client = %{VER}
%description client-dkms
This package contains scripts, config and source files to build and
start beegfs-client. It uses DKMS to build the kernel module.
%post client-dkms
dkms install beegfs/%{VER}
%preun client-dkms
dkms remove beegfs/%{VER} --all
%files client-dkms
%defattr(-,root,root)
%license /usr/share/doc/beegfs-client-dkms/copyright
%config(noreplace) /etc/beegfs/beegfs-client.conf
%config(noreplace) /etc/beegfs/beegfs-client-build.mk
/sbin/mount.beegfs
/usr/src/beegfs-%{VER}
%package client-compat
Summary: BeeGFS client compat module, allows to run two different client versions.
License: GPL v2
Group: Software/Other
%if %is_sles
Requires: make, gcc, kernel-default-devel, elfutils
%else
Requires: make, gcc
Recommends: kernel-devel, elfutils-libelf-devel
%endif
BuildArch: noarch
Provides: beegfs-client-compat = %{VER}
%description client-compat
This package allows to build and to run a compatbility beegfs-client kernel module
on a system that has a newer beegfs-client version installed.
%files client-compat
%license /usr/share/doc/beegfs-client-compat/copyright
%defattr(-,root,root)
%{CLIENT_COMPAT_DIR}
%package client-devel
Summary: BeeGFS client devel files
Group: Software/Other
BuildArch: noarch
Provides: beegfs-client-devel = %{VER}
%description client-devel
This package contains BeeGFS client development files.
%files client-devel
%defattr(-,root,root)
%license /usr/share/doc/beegfs-client-devel/copyright
%dir /usr/include/beegfs
/usr/include/beegfs/beegfs.h
/usr/include/beegfs/beegfs_client.h
/usr/include/beegfs/beegfs_ioctl.h
/usr/include/beegfs/beegfs_ioctl_functions.h
/usr/share/doc/beegfs-client-devel/examples/createFileWithStripePattern.cpp
/usr/share/doc/beegfs-client-devel/examples/getStripePatternOfFile.cpp
%package -n beeond
Summary: BeeOND
Group: Software/Other
# The dependecies used to be on FULL_VERSION=%{EPOCH}:%{VER}-%{RELEASE}, which
# doesn't work with BeeGFS 8, because the distribution independent packages
# can not append an OS RELEASE. We also don't need to depend on the EPOCH, the
# semantic version should be enough, so we just depend on %{VER} now.
Requires: beegfs-tools = %{VER}, beegfs-mgmtd = %{VER}, beegfs-meta = %{VER}, beegfs-storage = %{VER}, beegfs-client = %{VER}, libbeegfs-license = %{VER}, psmisc
BuildArch: noarch
Provides: beeond = %{VER}
%description -n beeond
This package contains BeeOND.
%files -n beeond
%defattr(-,root,root)
%license /usr/share/doc/beeond/copyright
/opt/beegfs/sbin/beeond
/usr/bin/beeond
/opt/beegfs/sbin/beeond-cp
/usr/bin/beeond-cp
/opt/beegfs/lib/beeond-lib
/opt/beegfs/lib/beegfs-ondemand-stoplocal

11
beeond/CMakeLists.txt Normal file
View File

@@ -0,0 +1,11 @@
install(
PROGRAMS "beegfs-ondemand-stoplocal" "beeond-lib"
DESTINATION "usr/share/beeond"
COMPONENT "beeond"
)
install(
PROGRAMS "beeond" "beeond-cp"
DESTINATION "usr/bin"
COMPONENT "beeond"
)

View File

@@ -0,0 +1,400 @@
#!/bin/bash
# beegfs-ondemand-stoplocal
# This file contains helper functions to stop BeeOND services locally on one node.
# This is meant to be sourced from another script (i.e. beeond)
# Checks the return code of the last command that has been executed. If the code is !=0, indicating
# an error, it prints a message and sets an error flag.
# Parameters:
# * The return code of the last command
# * A string containing a hint on what was being done that could have caused the error. It is
# used for the error message.
# Modifies:
# ERROR: Is set to "true" when an error was encountered.
sl_checkerror()
{
if [ "${1}" != 0 ]
then
echo "ERROR: There was a problem ${2} on host $(hostname)"
ERROR="true"
fi
}
# Prints an info message if the QUIET variable is not set.
# Parameter:
# A string (the message). It is prefixed with INFO when printed.
# Checks:
# QUIET: If "true", nothing is printed.
sl_print_info()
{
local MESSAGE=${1}
if [ "${QUIET}" != "true" ]
then
echo "INFO: ${MESSAGE}"
fi
}
# unmounts tmpfs mounts listed in the status file
sl_unmount_tmpfs()
{
local SERVICE MOUNTPOINT _
IFS=,
while read -r _ SERVICE MOUNTPOINT _ _
do
if [ "${SERVICE}" != "tmpfs" ]
then
continue
fi
sl_print_info "Unmounting tmpfs at ${MOUNTPOINT}"
if [ "${CLEANUP}" != "true" ]
then
fuser -k "${MOUNTPOINT}"
umount -l "${MOUNTPOINT}"
sl_checkerror $? "unmounting tmpfs"
else
fuser -k "${MOUNTPOINT}" 2>/dev/null
umount -l "${MOUNTPOINT}" 2>/dev/null
true
fi
done < "${STATUSFILE}"
unset IFS
}
# Unmounts all local mounts listed in the status file
sl_unmount_local_mounts()
{
local SERVICE MOUNTPOINT _
IFS=,
while read -r _ SERVICE MOUNTPOINT _ _
do
if [ "${SERVICE}" != "${CLIENTSERVICE}" ]
then
continue
fi
sl_print_info "Unmounting ${MOUNTPOINT}"
if [ "${CLEANUP}" != "true" ]
then
fuser -k "${MOUNTPOINT}" # no "sl_checkerror" after this, becuase fuser also returns
# non-zero when there are no processes accessing the file system
umount -l "${MOUNTPOINT}"
sl_checkerror $? "unmounting the ondemand file system"
else
fuser -k "${MOUNTPOINT}" 2>/dev/null
umount -l "${MOUNTPOINT}" 2>/dev/null
true # reset error code before next invocation of sl_checkerror
fi
done < "${STATUSFILE}"
unset IFS
# try to remove the client module - this is allowed to fail, because we might have a "normal"
# beegfs mount somewhere in the system.
rmmod beegfs 2>/dev/null || true
}
# sends a SIGTERM to a process, then waits until the process is stopped or appriximately 10 seconds
# have passed.
# Parameter:
# The PID of the proces
# Returns:
# 0 if process was stopped within 10 seconds, 1 if it wasn't, 255 if initial kill returned an
# error.
sl_kill_check()
{
local PID=$1
if ! kill "$PID"
then
return 255
fi
for ((i=0; i<100; i++))
do
if kill -0 "$PID" 2>/dev/null
then
sleep 0.1
else
return 0
fi
done
return 1
}
# stops all services listed in the status file except for clients
sl_stop_services()
{
local SERVICE DATAPATH PIDFILE _
IFS=,
while read -r _ SERVICE DATAPATH _ PIDFILE
do
if [ "${PIDFILE}" != "-" ] # pidfile is "-" for beegfs-client and tmpfs, because it is not
# a process
then
if [ -e "${PIDFILE}" ]
then
PID=$(cat "${PIDFILE}")
sl_kill_check "${PID}"
RES=$?
if [ $RES -eq 1 ]
then
echo "ERROR: ${SERVICE} did not stop within 10 seconds (PID ${PID})."
ERROR="true"
elif [ $RES -eq 255 ]
then
echo "ERROR: ${SERVICE} does not seem to be running any more (PID ${PID})."
fi
else
if [ "${CLEANUP}" != "true" ]
then
echo "ERROR: PID file ${PIDFILE} does not exist on host $(hostname)"
ERROR="true"
fi
fi
# delete data...
if [ "${DELETE_DATA}" = "true" ]
then
if [ "${DATAPATH}" != "-" ]
then
sl_print_info "Deleting stored data; Data path: ${DATAPATH}"
rm -rf "${DATAPATH}"
sl_checkerror $? "deleting ${DATAPATH}"
fi
fi
# delete preferredMds and preferredTarget files
rm -f "${PREFERRED_MDS_FILE}"
sl_checkerror $? "deleting ${PREFERRED_MDS_FILE}"
rm -f "${PREFERRED_TARGET_FILE}"
sl_checkerror $? "deleting ${PREFERRED_TARGET_FILE}"
fi
done < "${STATUSFILE}"
unset IFS
# unmount tempfs if it was used
sl_unmount_tmpfs
}
# deletes the logfiles listed in the status file if ERROR is set to false
# If the log directory is empty afterwards, it is also deleted
sl_delete_logfiles()
{
local LOGFILE # declare it here, because the last LOGFILE path is needed to delete the directory
# after the loop
# delete log files
if [ "${ERROR}" != "true" ] # if we haven't encountered an error yet.
then
# delete log files
local SERVICE LOGFILE _
IFS=,
while read -r _ SERVICE _ LOGFILE _
do
if [ "${ONLY_UNMOUNT}" = "true" ] && [ "${SERVICE}" != "${CLIENTSERVICE}" ]
then continue; fi
if [ "${ONLY_STOP_SERVER}" = "true" ] && [ "${SERVICE}" = "${CLIENTSERVICE}" ]
then continue; fi
if [ "${LOGFILE}" != "-" ]
then
sl_print_info "Deleting log file ${LOGFILE}"
rm -f "${LOGFILE}" 2>/dev/null # beegfs-client does not (always) generate a logfile.
# in this case rm gives an error message, but we don't
# want to see it. - for the same reason no sl_checkerror
# here
fi
done < "${STATUSFILE}"
unset IFS
# delete log directory if empty
local LOG_DIR
LOG_DIR=$(dirname "${LOGFILE}")
if [ "${LOG_DIR}" != "." ] && [ ! "$(ls -A "${LOG_DIR}")" ]
then
echo "Deleting log directory ${LOG_DIR}"
rmdir "${LOG_DIR}"
sl_checkerror $? "deleting ${LOG_DIR}"
fi
else
sl_print_info "Not deleting log files because of a previous error."
fi
}
# The "main" stoplocal function. From here, the functions to unmount the file system and stop the
# services are called. If there was no error, sl_delete_logfiles is called, and the status file is
# also removed.
# Checks the following variables:
# STATUSFILE The location of the status file
# ONLY_STOP_SERVER If "true", the umount_local_mounts step is skipped, and status file is not
# removed.
# ONLY_UNMOUNT If "true", the stop_services step is skipped, and status file is not
# removed.
# Modifies:
# ERROR Is set to "true" (and an error message is printed to %2) if an error is
# encountered in any step.
stoplocal()
{
sl_print_info "Using status file ${STATUSFILE}"
# do the actual shutdown process
# unmount the file system (skip this step if we only want to stop the server)
if [ "${ONLY_STOP_SERVER}" != "true" ]
then
sl_unmount_local_mounts
fi
# stop the services (skip this step if we only got asked to unmount the file system)
if [ "${ONLY_UNMOUNT}" != "true" ]
then
sl_stop_services
fi
# delete the logfiles
if [ "${ERROR}" != "true" ] && [ "${DELETE_LOGS}" = "true" ]
then
sl_delete_logfiles
fi
# delete the status file (only if a full shutdown was requested)
if [ "${ONLY_UNMOUNT}" != "true" ] && [ "${ONLY_STOP_SERVER}" != "true" ]
then
rm -f "${STATUSFILE}"
sl_checkerror $? "deleting the status file"
fi
}
# the user interface / main entry point to stoplocal
# Options:
# -i FILENAME => Status information filename
# (DEFAULT: ${DEFAULT_STATUSFILE})
# -d => Delete BeeGFS data on disks
# -L => Delete log files after successful shutdown
# -q => Suppress \"INFO\" messages, only print \"ERROR\"s
# -c => "Cleanup": Remove remaining processes and directories of a
# potentially unsuccessful shutdown of an earlier beeond
# instance. This switch silences the error message when a status
# information file is not found or an unmount command fails;
# instead, a message is printed (if \"INFO\" messages are not
# suppressed) when a status file DOES exist, because this means
# there actually was an instance before that is now being
# cleaned up.
# -u => ONLY unmount the file systems(*)
# -s => ONLY stop non-client services(*)
#
# (*) Options -u and -s are mutually exclusive
# If -u or -s are given, the status file is not deleted.
do_stoplocal()
{
local DEFAULT_STATUSFILE=/tmp/beeond.tmp
local CLIENTSERVICE=beegfs-client
local DELETE_DATA="false"
local DELETE_LOGS="false"
local ONLY_UNMOUNT="false"
local ONLY_STOP_SERVER="false"
local PREFERRED_MDS_FILE=/tmp/preferredMds.fod
local PREFERRED_TARGET_FILE=/tmp/preferredTarget.fod
local QUIET="false"
local ERROR="false"
local STATUSFILE="${DEFAULT_STATUSFILE}"
local OPTIND=1
local OPTARG=""
while getopts ":i:dLusqc" opt "$@"
do
case $opt in
i)
STATUSFILE=${OPTARG}
;;
d)
DELETE_DATA="true"
;;
L)
DELETE_LOGS="true"
;;
u)
if [ "${ONLY_STOP_SERVER}" = "true" ]
then
echo "ERROR: Options -s and -${OPTARG} are mutually exclusive" >&2
if declare -f -F print_usage_and_exit >/dev/null
then print_usage_and_exit; fi
return 1
fi
ONLY_UNMOUNT="true"
;;
s)
if [ "${ONLY_UNMOUNT}" = "true" ]
then
echo "ERROR: Options -u and -${OPTARG} are mutually exclusive" >&2
if declare -f -F print_usage_and_exit >/dev/null
then print_usage_and_exit; fi
return 1
fi
ONLY_STOP_SERVER="true"
;;
q)
QUIET="true"
;;
c)
CLEANUP="true"
;;
\?)
echo "ERROR: invalid option -${OPTARG}" >&2
if declare -f -F print_usage_and_exit >/dev/null
then print_usage_and_exit; fi
return 1
;;
:)
echo "ERROR: Option -${OPTARG} requires an argument" >&2
if declare -f -F print_usage_and_exit >/dev/null
then print_usage_and_exit; fi
return 1
;;
esac
done
# if statusfile can't be found, print a message and exit.
if [ ! -f ${STATUSFILE} ]
then
# only print message when we're not doing a cleanup run.
if [ "${CLEANUP}" != "true" ]
then
echo "ERROR: Status file ${STATUSFILE} not found." >&2
# If the user has specified a status file, just give a brief error message and exit.
# If the user has not specified a status file, give the full usage info - maybe the user
# didn't know how to specify a status file.
if [ "${STATUSFILE}" = "${DEFAULT_STATUSFILE}" ]
then
if declare -f -F "print_usage_and_exit" >/dev/null
then print_usage_and_exit; fi
fi
return 1
else
return 0 # return 0 if we're doing a cleanup so that pdsh doesn't complain
fi
fi
# if we're doing a cleanup run, inform the user that a status file was found.
if [ "${CLEANUP}" = "true" ]
then
sl_print_info "Status file found."
fi
stoplocal
if [ "${ERROR}" = "true" ]
then
return 1
else
return 0
fi
}

View File

@@ -0,0 +1,392 @@
#!/bin/bash
# This file contains some functions used across all of the BeeOND scripts.
BEEOND_FILENAME_PREFIX=".beeond_"
BEEOND_COPY_FILE_LIST="${BEEOND_FILENAME_PREFIX}files_copy"
BEEOND_COPY_SCAN_LIST="${BEEOND_FILENAME_PREFIX}scan_list" # List of dirs that have to be scanned.
BEEOND_COPY_DIR_LIST="${BEEOND_FILENAME_PREFIX}dirs_copy"
BEEOND_START_FILE_LIST="${BEEOND_FILENAME_PREFIX}files_start"
BEEOND_END_FILE_LIST="${BEEOND_FILENAME_PREFIX}files_end"
BEEOND_END_UPDATED_FILE_LIST="${BEEOND_FILENAME_PREFIX}files_end_updated"
BEEOND_START_DIR_LIST="${BEEOND_FILENAME_PREFIX}dirs_start"
BEEOND_END_DIR_LIST="${BEEOND_FILENAME_PREFIX}dirs_end"
BEEOND_END_UPDATED_DIR_LIST="${BEEOND_FILENAME_PREFIX}dirs_end_updated"
BEEOND_SESSION_FILE="${BEEOND_FILENAME_PREFIX}session"
BEEOND_BATCH_SIZE=20
beeond_print_error()
{
echo "ERROR: ${1}" >&2
echo ""
}
beeond_print_error_and_exit()
{
beeond_print_error "${1}" >&2
exit 1
}
beeond_print_info()
{
local MESSAGE="${1}"
if [ "${QUIET}" != "true" ]
then
echo "INFO: ${MESSAGE}"
fi
}
# Saves the session info file which contains the paths of the global store and the node file.
beeond_save_session_info()
{
local NODEFILE="${1}"
local GLOBAL_PATH="${2}"
if ! printf "NodeFile=%q\nGlobalPath=%q\n" "${NODEFILE}" "${GLOBAL_PATH}" \
> "${LOCAL_PATH}/${BEEOND_SESSION_FILE}"
then
beeond_print_error_and_exit "Could not write to session file."
fi
}
# Generate the list of files in the beeond folder.
beeond_generate_file_list()
{
local LOCAL_PATH="${1}"
local LISTFILE="${2}"
local REFERENCE_FILE="${3}"
pushd "${LOCAL_PATH}"
if [ "${REFERENCE_FILE}" = "" ]
then # No reference file - just generate the full list (e.g. on startup).
beeond_print_info "Generating file list ${LISTFILE}..."
find . ! -path ./${BEEOND_FILENAME_PREFIX}\* \( -type f -or -type l \)\
-exec bash -c 'printf "%q\n" "$0"' {} \; \
| grep -v ^\\$ | sort > "${LISTFILE}"
# The grep statement filters out file names with newlines in them. While they are technically
# legal they would cause problems later on due to the way the script run by parallel handles
# the arguments.
else # Reference file given: Compare timestamps.
beeond_print_info \
"Generating file list ${LISTFILE}. Timestamp reference: ${REFERENCE_FILE}..."
find . ! -path ./${BEEOND_FILENAME_PREFIX}\* \( -type f -or -type l \) \
\( -cnewer "${REFERENCE_FILE}" -or -newer "${REFERENCE_FILE}" \) \
-exec bash -c 'printf "%q\n" "$0"' {} \; \
| grep -v ^\\$ | sort > "${LISTFILE}"
fi
popd
}
# Generate list of directories - this is necessary in case directories were created during the
# session and need to be created on the global store as well.
beeond_generate_directory_list()
{
local LOCAL_PATH="${1}"
local LISTFILE="${2}"
local REFERENCE_FILE="${3}"
pushd "${LOCAL_PATH}"
if [ "${REFERENCE_FILE}" = "" ]
then # No reference file - just generate the full list (e.g. on startup).
beeond_print_info "Generating directory list ${LISTFILE}..."
find . ! -path . -type d \
-exec bash -c 'printf "%q\n" "$0"' {} \; \
| grep -v ^\\$ | sort > "${LISTFILE}"
else # Reference file given: Compare timestamps.
beeond_print_info \
"Generating directory list ${LISTFILE}. Timestamp reference: ${REFERENCE_FILE}..."
find . ! -path . -type d \
\( -cnewer "${REFERENCE_FILE}" -or -newer "${REFERENCE_FILE}" \) \
-exec bash -c 'printf "%q\n" "$0"' {} \; \
| grep -v ^\\$ | sort > "${LISTFILE}"
fi
popd
}
# Generate copy file list. If we do a parallel copy, we can't just list the paths to all the files
# to be copied, because we have to "flatten" the folder hierarchy (e.g. when the user says
# "copy dir/subfir/file_a anotherdir/file_b target_dir" we want to end up with
# target_dir/file_a and target_dir/file_b. To achieve this, we just save an explicit target path
# to each source file. We also have to keep a list of directories we encounter because we want to
# create them before we start copying.
beeond_generate_copy_lists()
{
local TARGET="${1}"
local NODE_LIST="${2}"
local CONCURRENCY="${3}"
shift 3
# Note: We do relative path expansion here, (and not directly in the do_... functions)
# because this is the first time we iterate over the source list.
# Expand target path.
if [ ! "${TARGET:0:1}" = "/" ]
then
TARGET="${PWD}/${TARGET}"
fi
# Delete possibly left over file lists.
rm -f "${TARGET}/${BEEOND_COPY_SCAN_LIST}" \
"${TARGET}/${BEEOND_COPY_DIR_LIST}" \
"${TARGET}/${BEEOND_COPY_FILE_LIST}"
# Generate lists: A list of files which can be used directly, and a list of directories which
# have to be scanned first.
for ENTRY in "$@"
do
# Expand path if it's relative.
if [ ! "${ENTRY:0:1}" = "/" ]
then
ENTRY="${PWD}/${ENTRY}"
fi
beeond_print_info "Path to scan: ${ENTRY}"
if [ -d "${ENTRY}" ]; then
printf "%q\n" "${ENTRY}" >> "${TARGET}/${BEEOND_COPY_SCAN_LIST}"
elif [ -f "${ENTRY}" ]; then
printf "%q\n" >> "${TARGET}/${BEEOND_COPY_FILE_LIST}"
else
beeond_print_error_and_exit "File or directory does not exist: ${ENTRY}"
fi
done
beeond_print_info "Scanning sources..."
< "${TARGET}/${BEEOND_COPY_SCAN_LIST}" \
${PARALLEL} -S "${NODE_LIST}" -j"${CONCURRENCY}" --pipe --recend "\n" \
-N${BEEOND_BATCH_SIZE} --controlmaster --will-cite \
" \
while read DIR; do \
cd \"\${DIR}\"; \
find . -type d -exec bash -c \\\'printf \"%s/%q\n\" \"\$0\" \"\$1\"\' \"\`basename \"\${DIR}\"\`\" \{\} \; \
| grep -v ^\\$; \
done;
" \
| sort > "${TARGET}/${BEEOND_COPY_DIR_LIST}"
< "${TARGET}/${BEEOND_COPY_SCAN_LIST}" \
${PARALLEL} -S "${NODE_LIST}" -j"${CONCURRENCY}" --pipe --recend "\n" \
-N${BEEOND_BATCH_SIZE} --controlmaster --will-cite \
" \
while read DIR; do \
cd \"\${DIR}\"; \
find . \( -type f -or -type l \) -exec bash -c \
\\\'printf \"%q %q\n\" \"\${PWD}/\$0\" \"${TARGET}/\`basename \"\${PWD}\"\`/\$0\"\' \{\} \; \
| grep -v ^\\$; \
done; \
" \
| sort > "${TARGET}/${BEEOND_COPY_FILE_LIST}"
}
# Parallel copy of the files from a previously generated file list to the target directory.
# First, the directory structure is generated, then the files are copied into it.
beeond_parallel_copy()
{
local TARGET="${1}"
local NODE_LIST="${2}"
local CONCURRENCY="${3}"
# Expand target path.
if [ ! "${TARGET:0:1}" = "/" ]
then
TARGET="${PWD}/${TARGET}"
fi
beeond_print_info "Generating target directory structure..."
< "${TARGET}/${BEEOND_COPY_DIR_LIST}" \
${PARALLEL} -S "${NODE_LIST}" -j"${CONCURRENCY}" --pipe --recend "\n" \
-N${BEEOND_BATCH_SIZE} --controlmaster --will-cite \
" \
while read DIR; do \
mkdir -pv \"${TARGET}/\${DIR}\"; \
done; \
"
beeond_print_info "Copying files..."
< "${TARGET}/${BEEOND_COPY_FILE_LIST}" \
${PARALLEL} -S "${NODE_LIST}" -j"${CONCURRENCY}" --pipe --recend "\n" \
-N${BEEOND_BATCH_SIZE} --controlmaster --will-cite \
" \
while read -a LINE; do \
cp -av \"\${LINE[0]}\" \"\${LINE[1]}\"; \
done; \
"
# Delete temporary files.
# rm "${TARGET}/${BEEOND_COPY_SCAN_LIST}" \
# "${TARGET}/${BEEOND_COPY_DIR_LIST}" \
# "${TARGET}/${BEEOND_COPY_FILE_LIST}"
}
# Remove all files from the global store that have been deleted during the session.
beeond_remove_removed_files()
{
local GLOBAL_PATH="${1}"
local LOCAL_PATH="${2}"
local NODE_LIST="${3}"
local CONCURRENCY="${4}"
beeond_print_info "Deleting files:"
comm -23 "${LOCAL_PATH}/${BEEOND_START_FILE_LIST}" "${LOCAL_PATH}/${BEEOND_END_FILE_LIST}" | \
${PARALLEL} -S "${NODE_LIST}" -j"${CONCURRENCY}" --pipe --recend "\n" \
-N${BEEOND_BATCH_SIZE} --controlmaster --will-cite \
" \
while read FILE; do \
rm -v \"${GLOBAL_PATH}/\${FILE}\"; \
done; \
"
beeond_print_info "Deleting directories:"
comm -23 "${LOCAL_PATH}/${BEEOND_START_DIR_LIST}" "${LOCAL_PATH}/${BEEOND_END_DIR_LIST}" | \
tac | \
xargs -I{} rmdir -v "${GLOBAL_PATH}/{}"
# Not being done in parallel to avoid deleting a subdirectory before its parent (this is also
# the reason the list is inverted (tac)).
}
# Copy back all files to the global store that have been updated during the session.
beeond_copy_updated_files()
{
local GLOBAL_PATH="${1}"
local LOCAL_PATH="${2}"
local NODE_LIST="${3}"
local CONCURRENCY="${4}"
beeond_print_info "Creating new directories:"
< "${LOCAL_PATH}/${BEEOND_END_DIR_LIST}" \
${PARALLEL} -S "${NODE_LIST}" -j"${CONCURRENCY}" --pipe --recend "\n" \
-N${BEEOND_BATCH_SIZE} --controlmaster --will-cite \
" \
while read DIR; do \
mkdir -pv \"${GLOBAL_PATH}/\${DIR}\"; \
done; \
"
beeond_print_info "Copying back changed files:"
< "${LOCAL_PATH}/${BEEOND_END_UPDATED_FILE_LIST}" \
${PARALLEL} -S "${NODE_LIST}" -j"${CONCURRENCY}" --pipe --recend "\n" \
-N${BEEOND_BATCH_SIZE} --controlmaster --will-cite \
" \
while read FILE; do \
cp -uv \"${LOCAL_PATH}/\${FILE}\" \"${GLOBAL_PATH}/\${FILE}\"; \
done; \
"
# Copy files into updated directories. (When a directory is renamed or files
# are moved to a directory, the files in it don't have their timestamp
# updated. Therefore, we need to check all the updated directories again).
beeond_print_info "Copying back changed files (updated dirs):"
pushd "${LOCAL_PATH}"
< "${LOCAL_PATH}/${BEEOND_END_UPDATED_DIR_LIST}" \
xargs -I{} find {} -maxdepth 1 \( -type f -or -type l \) | \
${PARALLEL} -S "${NODE_LIST}" -j"${CONCURRENCY}" --pipe --recend "\n" \
-N${BEEOND_BATCH_SIZE} --controlmaster --will-cite \
" \
while read FILE; do \
cp -uv \"${LOCAL_PATH}/\${FILE}\" \"\`dirname \"${GLOBAL_PATH}/\${FILE}\"\`\"; \
done; \
"
popd
}
# Stage in process: Copy all files from the global store to the local store.
beeond_stage_in()
{
local GLOBAL_PATH="${1}"
local LOCAL_PATH="${2}"
local NODE_LIST="${3}"
local CONCURRENCY="${4}"
# Generate list of files that have to be copied.
beeond_generate_file_list "${GLOBAL_PATH}" "${LOCAL_PATH}/${BEEOND_START_FILE_LIST}"
beeond_generate_directory_list "${GLOBAL_PATH}" "${LOCAL_PATH}/${BEEOND_START_DIR_LIST}"
beeond_print_info "Creating directory structure..."
< "${LOCAL_PATH}/${BEEOND_START_DIR_LIST}" \
${PARALLEL} -S "${NODE_LIST}" -j"${CONCURRENCY}" --pipe --recend "\n" \
-N${BEEOND_BATCH_SIZE} --controlmaster --will-cite \
" \
while read DIR; do \
mkdir -pv \"${LOCAL_PATH}/\${DIR}\"; \
touch --reference=\"${GLOBAL_PATH}/\${DIR}\" \"${LOCAL_PATH}/\${DIR}\"; \
done; \
"
beeond_print_info "Copying files to local directory..."
if ! < "${LOCAL_PATH}/${BEEOND_START_FILE_LIST}" \
${PARALLEL} -S "${NODE_LIST}" -j"${CONCURRENCY}" --pipe --recend "\n" \
-N${BEEOND_BATCH_SIZE} --controlmaster --will-cite \
" \
while read FILE; do \
cp -av \"${GLOBAL_PATH}/\${FILE}\" \"\`dirname \"${LOCAL_PATH}/\${FILE}\"\`\"/; \
done;
"
then
beeond_print_error "Stage-in copy did not succeed. Data is incompletely staged in."
fi
# Generate list of files and dirs that were actually copied to keep track if the user deletes
# files during a session. (re-generate list here, so that if something went wrong during the
# stage-in copy, we don't start deleting stuff from the global store by accident).
beeond_generate_file_list "${LOCAL_PATH}" "${LOCAL_PATH}/${BEEOND_START_FILE_LIST}"
beeond_generate_directory_list "${LOCAL_PATH}" "${LOCAL_PATH}/${BEEOND_START_DIR_LIST}"
}
# Stage out process: remove all the files that have been removed during the beeond session,
# and copy back the files which have been changed.
beeond_stage_out()
{
local GLOBAL_PATH="${1}"
local LOCAL_PATH="${2}"
local NODE_LIST="${3}"
local CONCURRENCY="${4}"
beeond_print_info "Nodes for parallel stage out: ${NODE_LIST}."
beeond_generate_file_list "${LOCAL_PATH}" "${LOCAL_PATH}/${BEEOND_END_FILE_LIST}"
beeond_generate_file_list "${LOCAL_PATH}" "${LOCAL_PATH}/${BEEOND_END_UPDATED_FILE_LIST}" \
"${BEEOND_START_FILE_LIST}"
beeond_generate_directory_list "${LOCAL_PATH}" "${LOCAL_PATH}/${BEEOND_END_DIR_LIST}"
beeond_generate_directory_list "${LOCAL_PATH}" "${LOCAL_PATH}/${BEEOND_END_UPDATED_DIR_LIST}" \
"${BEEOND_START_DIR_LIST}"
beeond_remove_removed_files "${GLOBAL_PATH}" "${LOCAL_PATH}" "${NODE_LIST}" "${CONCURRENCY}"
beeond_copy_updated_files "${GLOBAL_PATH}" "${LOCAL_PATH}" "${NODE_LIST}" "${CONCURRENCY}"
}
# Parallel copy process: copy all files and directories (recursively) into the target directory.
beeond_copy()
{
local NODE_LIST="${1}"
local CONCURRENCY="${2}"
shift 2
beeond_print_info "Nodes for parallel copy: ${NODE_LIST}; Concurrency: ${CONCURRENCY}"
beeond_generate_copy_lists "${@:$#}" "${NODE_LIST}" "${CONCURRENCY}" "${@:1:$#-1}"
beeond_parallel_copy "${@:$#}" "${NODE_LIST}" "${CONCURRENCY}"
}

1606
beeond/source/beeond Executable file

File diff suppressed because it is too large Load Diff

354
beeond/source/beeond-cp Executable file
View File

@@ -0,0 +1,354 @@
#!/bin/bash
# Source helper script.
ABSOLUTE_PATH=$(dirname "$(readlink -e "$0")") # using readlink, because somone might be calling
# this script using a symlink
if [ -e "${ABSOLUTE_PATH}/../lib/beeond-lib" ]
then
BEEOND_LIB="${ABSOLUTE_PATH}/../lib/beeond-lib"
else
BEEOND_LIB="${ABSOLUTE_PATH}/../scripts/lib/beeond-lib"
fi
#shellcheck source=scripts/lib/beeond-lib
source "${BEEOND_LIB}"
PARALLEL="${ABSOLUTE_PATH}/../thirdparty/parallel/parallel"
# Print usage.
print_usage_and_exit()
{
echo ""
echo "BeeOND copy (http://www.beegfs.com)"
echo ""
echo "DESCRIPTION:"
echo " BeeGFS OnDemand copying/staging system."
echo ""
echo "USAGE: $(basename "$0") <mode> <options>"
echo ""
echo "ACTIONS:"
echo " The first argument to $(basename "$0") is considered to be an action that the script"
echo " should perform."
echo ""
echo " The following actions are available:"
echo ""
echo " stagein: (EXPERIMENTAL)"
echo " Stage a complete directory from the global storage in to BeeOND."
echo ""
echo " Mandatory arguments:"
echo " -n FILENAME => File containing the list of nodes where the parallel"
echo " copy should be performed. All nodes must have access to"
echo " the global and local directories."
echo " -g PATH => Directory on global storage. (*)"
echo " -l PATH => Directory on local (BeeOND) storage. (*)"
echo ""
echo " Notes:"
echo " (*) Global and local directories have to be specified in form of an"
echo " absolute path."
echo ""
echo " stageout: (EXPERIMENTAL)"
echo " Stage a complete directory out from BeeOND to the global storage."
echo " Only changes will be staged out of the local directory and committed to"
echo " the global directory."
echo ""
echo " Mandatory arguments:"
echo " -l PATH => Local directory."
echo ""
echo " Notes:"
echo " The contents will be completely synchronized, i.e. deleted files on "
echo " BeeOND will get deleted on global storage, too."
echo ""
echo " copy:"
echo " Perform a parallel copy of a set of files or folders."
echo " Files will be copied into the target directory, folders will be copied"
echo " recursively. The copy process is parallelized across the set of nodes"
echo " specified in the nodefile."
echo ""
echo " Mandatory arguments:"
echo " -n FILENAME => File containing the list of nodes where the parallel"
echo " copy should be performed. All nodes must have access to"
echo " the sources and the target directory."
echo ""
echo " Notes:"
echo " Further command line arguments are consdiered source directory or file"
echo " names. The last command line argument specifies the target directory"
echo ""
echo "EXAMPLES:"
echo " Stage data from /mnt/beegfs-global/dataset in to BeeOND mounted at /mnt/beeond,"
echo " using the nodes given in /tmp/nodefile:"
echo " beeond-cp stagein -n /tmp/nodefile -g /mnt/beegfs-global/dataset -l /mnt/beeond"
echo ""
echo " Stage out modified data from BeeOND mounted at /mnt/beeond to the global "
echo " storage:"
echo " beeond-cp stageout -n /tmp/nodefile -g /mnt/beegfs-global/dataset -l /mnt/beeond"
echo ""
echo " Recursively copy the directories dir_1 and dir_2 to /mnt/beegfs, using the nodes"
echo " in /tmp/nodefile:"
echo " beeond-cp copy -n /tmp/nodefile dir_1 dir_2 /mnt/beegfs"
echo ""
echo "NOTE:"
echo " BeeOND copy uses GNU Parallel -"
echo " When using programs that use GNU Parallel to process data for publication"
echo " please cite:"
echo " O. Tange (2011): GNU Parallel - The Command-Line Power Tool,"
echo " ;login: The USENIX Magazine, February 2011:42-47."
echo ""
echo " SSH is used to log into the nodes specified in the nodefile. Please make"
echo " sure your SSH configuration allows for enough concurrent sessions and pending"
echo " logins. You might have to (ask your admin to) raise the MaxSessions and"
echo " MaxStartups settings in the sshd_config file."
echo ""
echo " Also please make sure you have the access rights needed to write to the"
echo " global store. Otherwise the stage-out might fail. Note that the access rights"
echo " in the BeeOND local store do not necessarily reflect those in the global"
echo " store."
exit 1
}
### main functions
do_start()
{
local NODEFILE="${1}"
local GLOBAL_PATH="${2}"
local LOCAL_PATH="${3}"
beeond_print_info "BeeOND startup..."
beeond_print_info "nodefile: ${NODEFILE}"
beeond_print_info "global path: ${GLOBAL_PATH}"
beeond_print_info "local path: ${LOCAL_PATH}"
MISSING_PARAM=0
if [ "${NODEFILE}" = "" ]
then
beeond_print_error "No nodefile specified."
MISSING_PARAM=1
fi
if [ "${GLOBAL_PATH}" = "" ]
then
beeond_print_error "Global path not specified."
MISSING_PARAM=1
fi
if [ "${LOCAL_PATH}" = "" ]
then
beeond_print_error "Local path not specified."
MISSING_PARAM=1
fi
# Expand relative path to nodefile.
if [ ! "${NODEFILE:0:1}" = "/" ]
then
NODEFILE="${PWD}/${NODEFILE}"
fi
if [ ! -e "${NODEFILE}" ]
then
beeond_print_error_and_exit "Node file does not exist."
fi
# The paths to the global and local directory have to be specified as absolute paths to prevent
# user errors (like copying a lot of files to ~/mnt/beeond).
if [ ! "${GLOBAL_PATH:0:1}" = "/" ] || [ ! "${LOCAL_PATH:0:1}" = "/" ]
then
beeond_print_error_and_exit "Global path and local path have to be absolute."
fi
[ "${MISSING_PARAM}" = "1" ] && exit 1
# Make sure target directory is empty before starting.
if [ -e "${LOCAL_PATH}" ]
then
[ -d "${LOCAL_PATH}" ] \
|| beeond_print_error_and_exit "Target path is not a directory."
find "${LOCAL_PATH}" -maxdepth 0 -type d -empty | read -r _ \
|| beeond_print_error_and_exit "Target directory is not empty."
else
mkdir -p "${LOCAL_PATH}" \
|| beeond_print_error_and_exit "Cannot create target directory."
fi
local CONCURRENCY=$(( $(wc -l < "${NODEFILE}") ))
beeond_print_info "Concurrency: ${CONCURRENCY}"
beeond_print_info "Writing session information."
beeond_save_session_info "${NODEFILE}" "${GLOBAL_PATH}"
beeond_print_info "Starting stage-in..."
NODES=( $(grep -v '^$' "${NODEFILE}" | uniq) ) # Store as array and ignore empty lines.
NODELIST=$(IFS=,; echo "${NODES[*]}") # turn argument list into comma-separated string for PDSH
beeond_stage_in "${GLOBAL_PATH}" "${LOCAL_PATH}" "${NODELIST}" ${CONCURRENCY}
beeond_print_info "Done."
}
do_stop()
{
local LOCAL_PATH="${1}"
if [ "${LOCAL_PATH}" = "" ]
then
beeond_print_error_and_exit "No path specified."
fi
# Expand relative local path.
# Note: Don't have to ensure that it's an absolute path here: We confirm it's a BeeOND instance
# by looking for the session info file.
if [ ! "${LOCAL_PATH:0:1}" = "/" ]
then
LOCAL_PATH="${PWD}/${LOCAL_PATH}"
fi
# Read parameters from session info file.
NODEFILE=$(grep NodeFile "${LOCAL_PATH}/${BEEOND_SESSION_FILE}" | cut -d = -f 2-)
GLOBAL_PATH=$(grep GlobalPath "${LOCAL_PATH}/${BEEOND_SESSION_FILE}" | cut -d = -f 2-)
if [ "${NODEFILE}" = "" ]
then
beeond_print_error "Error reading node file name from session file."
MISSING_PARAM=1
fi
if [ "${GLOBAL_PATH}" = "" ]
then
beeond_print_error "Error reading global path from session file."
MISSING_PARAM=1
fi
[ "${MISSING_PARAM}" = "1" ] && exit 1
if [ ! -e "${NODEFILE}" ]
then
beeond_print_error_and_exit "Node file does not exist."
fi
beeond_print_info "BeeOND shutdown..."
beeond_print_info "nodefile: ${NODEFILE}"
beeond_print_info "global path: ${GLOBAL_PATH}"
beeond_print_info "local path: ${LOCAL_PATH}"
NODES=( $(grep -v '^$' "${NODEFILE}" | uniq) ) # Store as array and ignore empty lines.
NODELIST=$(IFS=,; echo "${NODES[*]}")
local CONCURRENCY=$(( $(wc -l < "${NODEFILE}") ))
beeond_print_info "Concurrency: ${CONCURRENCY}"
beeond_stage_out "${GLOBAL_PATH}" "${LOCAL_PATH}" "${NODELIST}" ${CONCURRENCY}
beeond_print_info "Done."
}
do_copy()
{
local NODEFILE="${1}"
shift
beeond_print_info "BeeOND copy..."
if [ "${NODEFILE}" = "" ]
then
beeond_print_error "No nodefile specified."
fi
# Expand relative path to nodefile.
if [ ! "${NODEFILE:0:1}" = "/" ]
then
NODEFILE="${PWD}/${NODEFILE}"
fi
if [ ! -e "${NODEFILE}" ]
then
beeond_print_error_and_exit "Node file does not exist."
fi
NODES=( $(grep -v '^$' "${NODEFILE}" | uniq) ) # Store as array and ignore empty lines.
NODELIST=$(IFS=,; echo "${NODES[*]}")
local CONCURRENCY=$(( $(wc -l < "${NODEFILE}") ))
beeond_print_info "Concurrency: ${CONCURRENCY}"
beeond_copy "${NODELIST}" "${CONCURRENCY}" "$@"
}
# Print help if no arguments given.
if [ $# -eq 0 ] ; then
print_usage_and_exit
fi
# Do it.
ACTION="${1}"
if [ "${ACTION}" = "stagein" ]
then
shift
while getopts ":n:g:l:" opt; do
case $opt in
n)
NODEFILE="${OPTARG}"
;;
g)
GLOBAL_PATH="${OPTARG}"
;;
l)
LOCAL_PATH="${OPTARG}"
;;
\?)
beeond_print_error_and_exit "Invalid option: -${OPTARG}."
;;
:)
beeond_print_error_and_exit "Option -${OPTARG} requires an argument."
;;
esac
done
do_start "${NODEFILE}" "${GLOBAL_PATH}" "${LOCAL_PATH}"
elif [ "${ACTION}" = "stageout" ]
then
shift
while getopts ":l:" opt; do
case $opt in
l)
LOCAL_PATH="${OPTARG}"
;;
\?)
beeond_print_error_and_exit "Invalid option: -${OPTARG}."
;;
:)
beeond_print_error_and_exit "Option -${OPTARG} requires an argument."
;;
esac
done
do_stop "${LOCAL_PATH}"
elif [ "${ACTION}" = "copy" ]
then
shift
# Nodefile has to be given as the only command line argument.
if getopts ":n:" opt
then
if [ "$opt" = "n" ]
then
NODEFILE="${OPTARG}"
else
beeond_print_error_and_exit "Invalid option: -${opt}"
fi
else
beeond_print_error_and_exit "No nodefile specified."
fi
# All following command line arguments are file or directory names, specifying the sources and
# the target of the copy ancion
shift # shift out -n parameter
shift # shift out name of node file
do_copy "${NODEFILE}" "$@"
elif [ "${ACTION}" = "info" ]
then
do_print_info
else
print_usage_and_exit
fi

598
build/Makefile Normal file
View File

@@ -0,0 +1,598 @@
##### BASE MAKEFILE
#
# This makefile is intended to be a basis on which new makefiles are written.
# It is divided into five parts:
# * help text generation
# * path for subproject locations and thirparty include/library paths
# * default values for tools (like CXX) and compiler/linker flags
# * description of known libraries that may be used in the build
# * functions that define build artifacts
#
# library handling will be described in detail later.
#
# we have three functions that defined build artifacts:
# * build-executable
# * build-static-library
# * build-dynamic-library
#
# they all have the same, basic signature:
# (name: string, sources: list<string>, usedLibraries: list<string>)
#
# $name determines the name given to the output file (for executables) or the library name given
# to the output library (for libraries).
#
# $sources must be a list of source files (allowed types are .cpp and .c), relative to the directory
# of the Makefile you are writing (see example below).
#
# $usedLibraries is a (possibly empty) list of libraries as defined in the KNOWN LIBRARIES section
# below. they will be automatically added to compiler and linker invocations as needed.
#
# EXAMPLE:
#
# imagine you have a project with a directory structure like this:
# - /build
# - Makefile
# - /source
# - /lib
# - ...
# - /exe
# - ...
#
# you want your Makefile to build a shared library from /source/lib and an executable from
# /source/exe. the you could write your Makefile like this:
#
# include ,../../build/Makefile
#
# # will generate a libFancy.so in /build, uses libz
# $(call build-static-library,\
# Fancy,\
# $(shell find ../source/lib -iname '*.cpp'),\
# z)
#
# # this registers libFancy as a shared library. see details below (KNOWN LIBRARIES).
# $(call define-dep-lib, Fancy, -I ../source/lib/include, -L . -l Fancy)
#
# # will generate an executable file Run in /build, uses libFancy
# $(call build-executable,\
# Run,\
# $(shell find ../source/exe -iname '*.cpp'),\
# Fancy)
#
# # a dependency must be added between Run and Fancy, to ensure that Fancy is built first.
# Run: | libFancy.so
override V := $(if $V,,@)
all:
define HELP_ARGS_GENERIC
@echo ' BEEGFS_DEBUG=1 Enables debug information and symbols'
@echo ' BEEGFS_DEBUG_OPT=1 Enables internal debug code, but compiled'
@echo ' with optimizations'
@echo ' BEEGFS_DEBUG_IP=1 Enables low-level debug of network sendto'
@echo ' and recvfrom'
@echo ' CXX=<compiler> Specifies a c++ compiler'
@echo ' DISTCC=distcc Enables the usage of distcc'
@echo ' V=1 Print command lines of tool invocations'
@echo ' BEEGFS_COMMON_PATH=<path> Path to the common directory'
@echo ' BEEGFS_THIRDPARTY_PATH=<path>'
@echo ' Path to the thirdparty directory'
@echo ' BEEGFS_USE_PCH=1 Enables use of precompiled headers'
endef
define HELP_TARGETS_GENERIC
@echo ' all (default) build only'
@echo ' clean delete compiled files'
@echo ' help print this help message'
endef
help:
@echo 'Optional arguments:'
$(HELP_ARGS_GENERIC)
$(HELP_ARGS_SPECIFIC)
@echo
@echo 'Targets:'
$(HELP_TARGETS_GENERIC)
$(HELP_TARGETS_SPECIFIC)
root_dir := $(realpath $(dir $(lastword $(MAKEFILE_LIST)))/..)
build_dir := $(realpath $(dir $(firstword $(MAKEFILE_LIST))))
BEEGFS_COMMON_PATH ?= $(root_dir)/common
BEEGFS_COMMON_PCH_H ?= $(BEEGFS_COMMON_PATH)/source/common/pch.h
BEEGFS_THIRDPARTY_PATH ?= $(root_dir)/thirdparty
BEEGFS_COMM_DEBUG_PATH ?= $(root_dir)/comm_debug
BEEGFS_FSCK_PATH ?= $(root_dir)/fsck
BEEGFS_EVENT_LISTENER_PATH ?= $(root_dir)/event_listener
BEEGFS_DEVEL_INCLUDE_PATH ?= $(root_dir)/client_devel/include
BEEGFS_CLIENT_PATH ?= $(root_dir)/client_module/include
BOOST_INC_PATH ?= $(BEEGFS_THIRDPARTY_PATH)/source/boost
NU_INC_PATH ?= $(BEEGFS_THIRDPARTY_PATH)/source/nu/include
GTEST_INC_PATH ?= $(BEEGFS_THIRDPARTY_PATH)/source/gtest/googletest/include
GTEST_LIB_PATH ?= $(BEEGFS_THIRDPARTY_PATH)/build
ifneq ($(target_arch),)
STRIP := $(target_arch)-strip
AR := $(target_arch)-ar
CC := $(target_arch)-gcc
CXX := $(target_arch)-g++
endif
SHELL := /bin/bash
STRIP ?= strip
CXX ?= g++
AR ?= ar
CLANG_TIDY ?= clang-tidy
# if -T is supported by ar, use it. thin archives are quicker to create and maintain.
ifeq ($(shell ar -TM 2>&1 <<<""),)
AR += -T
endif
CXXFLAGS = \
-std=c++17 -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 \
-isystem $(BOOST_INC_PATH) -isystem $(NU_INC_PATH) \
-pthread \
-fno-strict-aliasing -fmessage-length=0 \
-Wall -Wextra -Wunused-variable -Woverloaded-virtual -Wno-unused-parameter -Wuninitialized \
-Wno-missing-field-initializers \
-Winvalid-pch \
-ggdb3 \
$(USER_CXXFLAGS)
CXXFLAGS_RELEASE = -O3 -Wuninitialized
CXXFLAGS_DEBUG = -O1 -D_FORTIFY_SOURCE=2 \
-DBEEGFS_DEBUG -DDEBUG_READWRITE -DDEBUG_MUTEX_LOCKING -DDEBUG_REFCOUNT \
-DDEBUG_BACKTRACE -DLOG_DEBUG_MESSAGES
CXXFLAGS_COVERAGE = --coverage -O1 -fno-inline
LDFLAGS = -std=c++1y \
-rdynamic \
-pthread -lrt \
-Wl,-rpath,'$$ORIGIN/../lib' \
$(USER_LDFLAGS)
LDFLAGS_COVERAGE = --coverage
ifneq ($(BEEGFS_DEBUG),)
CXXFLAGS += $(CXXFLAGS_DEBUG)
else ifneq ($(BEEGFS_COVERAGE),)
CXXFLAGS += $(CXXFLAGS_COVERAGE)
LDFLAGS += $(LDFLAGS_COVERAGE)
else
CXXFLAGS += $(CXXFLAGS_RELEASE)
endif
CXXFLAGS += -DBEEGFS_VERSION="\"$(BEEGFS_VERSION)\""
ifeq ($(BEEGFS_NVFS),1)
CXXFLAGS += -DBEEGFS_NVFS
endif
ifeq ($(BEEGFS_DEBUG_RDMA),1)
CXXFLAGS += -DBEEGFS_DEBUG_RDMA
endif
ifneq ($(BEEGFS_DEBUG_IP),)
CXXFLAGS += -DBEEGFS_DEBUG_IP
endif
###### KNOWN LIBRARIES
#
# this is our local registry of known libraries, both our own and thirdparty libraries.
#
# currently supports building with our own libraries common and client-devel.
# thirdparty packages supported are:
# * dl (from system)
#
# to define new libraries, add appriopriate calls to define-dep-lib in this section.
# the signature of define-dep-lib is:
# (name: string, CXXFLAGS: string, libraryPath: string[, LDFLAGS: string])
#
# $name is used to identify the library within this registry, and is otherwise unused.
#
# $CXXFLAGS will be added to the set of CXXFLAGS used when compiling files from projects that use
# this library (see example at the beginning of this file for reference).
#
# $libraryPath is the path (absolute or relative) to the library. glob patterns are allowed, and in
# fact required if you want to link a dynamic library.
#
# $LDFLAGS will be added to the set of LDFLAGS used when linking shared libraries or executables
# that use this library. if the library you want to link is static, LDFLAGS need not be set - the
# library will be added to the list of archives.
#
#
# to define libraries that are taken from the system, use define-dep-lib-system. it will use its
# arguments to ask pkgconfig for the correct compiler and linker flags. then signature of
# define-dep-lib-system is:
# (name: string, pkgconfigID: string)
#
# $name is used only to identify the library.
#
# $pkgconfigID is the identifier pkgconfig will be asked about.
define resolve-dep-cflags
$(if $(filter undefined,$(origin _DEP_LIB_CXX[$(strip $1)])),\
$(error I have no CXXFLAGS for $1!),\
$(_DEP_LIB_CXX[$(strip $1)]))
endef
define resolve-dep-ldflags
$(if $(filter undefined,$(origin _DEP_LIB_LD[$(strip $1)])),\
$(error I have no LDFLAGS for $1!),\
$(_DEP_LIB_LD[$(strip $1)]))
endef
define resolve-dep-deps
$(if $(filter undefined,$(origin _DEP_LIB_DEPS[$(strip $1)])),\
$(error I have no library dependencies for $1!),\
$(_DEP_LIB_DEPS[$(strip $1)]))
endef
define define-dep-lib
$(strip
$(eval _DEP_LIB_CXX[$(strip $1)] = $(strip $2))
$(eval _DEP_LIB_LD[$(strip $1)] = $(strip $(or $4, $3)))
$(eval _DEP_LIB_DEPS[$(strip $1)] = $(strip $3))
$(eval $(strip $3): ))
endef
define define-dep-lib-system
$(strip
$(if $(shell pkg-config --exists $2 || echo fail),
$(error Could not find library $2 in system!))
$(call define-dep-lib,
$1,
$(shell pkg-config --cflags $2),
$(shell pkg-config --libs $2)))
endef
# don't bother to search the system for libraries if we only run `make clean'
# this also has the nice side effect that libraries needn't be present in the system
# when `make clean' is run - if we override dependency resolution to not do anything.
ifeq ($(strip $(MAKECMDGOALS)),clean)
resolve-dep-cflags :=
resolve-dep-ldflags :=
resolve-dep-deps :=
else
$(call define-dep-lib, common,\
-I $(BEEGFS_COMMON_PATH)/source \
-I $(BEEGFS_CLIENT_PATH), \
-ldl $(BEEGFS_COMMON_PATH)/build/libbeegfs-common.a)
$(call define-dep-lib, client-devel,\
-I $(BEEGFS_DEVEL_INCLUDE_PATH),)
$(call define-dep-lib, dl, , , -ldl)
$(call define-dep-lib, rdma, , -lrdmacm -libverbs)
$(call define-dep-lib, gtest,\
-isystem $(GTEST_INC_PATH)/include,\
$(GTEST_LIB_PATH)/libgtest.a)
$(call define-dep-lib, cassandra, -I$(BEEGFS_THIRDPARTY_PATH)/source/datastax)
$(call define-dep-lib-system, curl, libcurl)
$(call define-dep-lib-system, z, zlib)
$(call define-dep-lib, blkid, , , -lblkid)
$(call define-dep-lib, uuid, , , -luuid)
$(call define-dep-lib-system, nl3-route, libnl-route-3.0)
endif
clean:
@$(RM) -rf $(if $V,,-v) $(CLEANUP_FILES)
NONDEP_MAKEFILES = $(filter-out %.d,$(MAKEFILE_LIST))
%.autogen.h:
@# Generate a proxy-header for precompilation.
@true > $@ # truncate file
@echo '/* Autogenerated precompiled header (PCH)' >> $@
@echo ' * For each set of compiler options we need to compile ' >> $@
@echo ' * a PCH separately. To realize that, we create ' >> $@
@echo ' * proxy PCHs like this file and compile these. */' >> $@
@echo '#include "$(BEEGFS_COMMON_PCH_H)"' >> $@
%.h.gch: %.h
@echo "[CXX] $@"
$V$(CXX) $(CXXFLAGS) -c $< -E -MMD -MP -MF$<.d -MT$@ -o/dev/null
$V$(DISTCC) $(CXX) $(CXXFLAGS) -o$@ -c $(realpath $<)
%.cpp.o: %.cpp $(NONDEP_MAKEFILES)
@echo "[CXX] $<"
$V$(DISTCC) $(CXX) $(CXXFLAGS) -MMD -MF$<.d -MT$<.o -MP -o $<.o -c $(realpath $<)
%.c.o: %.c $(NONDEP_MAKEFILES)
@echo "[CXX] $<"
$V$(DISTCC) $(CXX) $(CXXFLAGS) -MMD -MF$<.d -MT$<.o -MP -o$<.o -c $(realpath $<)
# first partial list: checks we want to exclude on a general basis right now
# second list: very minor problems we don't want to be bugged about yet, but want to fix over time
# third list: definite errors, fix as soon as possible
define -clang_tidy_checks
-clang-analyzer-alpha.deadcode.UnreachableCode
-fuchsia-default-arguments
-fuchsia-overloaded-operator
-google-build-using-namespace
-google-readability-braces-around-statements
-google-readability-casting
-google-readability-namespace-comments
-hicpp-braces-around-statements
-llvm-header-guard
-llvm-include-order
-llvm-namespace-comment
-readability-braces-around-statements
-readability-implicit-bool-conversion
-android-cloexec-accept
-android-cloexec-creat
-android-cloexec-dup
-android-cloexec-epoll-create
-android-cloexec-fopen
-android-cloexec-open
-boost-use-to-string
-bugprone-branch-clone
-bugprone-exception-escape
-bugprone-narrowing-conversions
-bugprone-sizeof-expression
-cert-oop54-cpp
-clang-analyzer-core.CallAndMessage
-clang-analyzer-core.uninitialized.Assign
-clang-analyzer-cplusplus.NewDeleteLeaks
-clang-analyzer-deadcode.DeadStores
-clang-analyzer-optin.cplusplus.UninitializedObject
-clang-diagnostic-deprecated-copy
-cppcoreguidelines-avoid-c-arrays
-cppcoreguidelines-avoid-goto
-cppcoreguidelines-avoid-magic-numbers
-cppcoreguidelines-init-variables
-cppcoreguidelines-interfaces-global-init
-cppcoreguidelines-macro-usage
-cppcoreguidelines-narrowing-conversions
-cppcoreguidelines-non-private-member-variables-in-classes
-cppcoreguidelines-pro-bounds-array-to-pointer-decay
-cppcoreguidelines-pro-bounds-constant-array-index
-cppcoreguidelines-pro-bounds-pointer-arithmetic
-cppcoreguidelines-pro-type-const-cast
-cppcoreguidelines-pro-type-cstyle-cast
-cppcoreguidelines-pro-type-member-init
-cppcoreguidelines-pro-type-reinterpret-cast
-cppcoreguidelines-pro-type-static-cast-downcast
-cppcoreguidelines-pro-type-union-access
-cppcoreguidelines-pro-type-vararg
-cppcoreguidelines-special-member-functions
-fuchsia-default-arguments-calls
-fuchsia-default-arguments-declarations
-fuchsia-statically-constructed-objects
-google-default-arguments
-google-explicit-constructor
-google-readability-avoid-underscore-in-googletest-name
-google-readability-redundant-smartptr-get
-google-readability-todo
-google-runtime-int
-google-runtime-references
-hicpp-avoid-c-arrays
-hicpp-avoid-goto
-hicpp-deprecated-headers
-hicpp-explicit-conversions
-hicpp-member-init
-hicpp-multiway-paths-covered
-hicpp-no-array-decay
-hicpp-no-assembler
-hicpp-no-malloc
-hicpp-signed-bitwise
-hicpp-special-member-functions
-hicpp-uppercase-literal-suffix
-hicpp-use-auto
-hicpp-use-emplace
-hicpp-use-equals-default
-hicpp-use-equals-delete
-hicpp-use-noexcept
-hicpp-use-nullptr
-hicpp-vararg
-llvm-qualified-auto
-misc-misplaced-widening-cast
-misc-move-constructor-init
-misc-non-private-member-variables-in-classes
-misc-redundant-expression
-misc-string-compare
-misc-unused-parameters
-modernize-avoid-bind
-modernize-avoid-c-arrays
-modernize-loop-convert
-modernize-make-shared
-modernize-make-unique
-modernize-pass-by-value
-modernize-raw-string-literal
-modernize-replace-random-shuffle
-modernize-return-braced-init-list
-modernize-use-auto
-modernize-use-default
-modernize-use-default-member-init
-modernize-use-nodiscard
-modernize-use-emplace
-modernize-use-equals-default
-modernize-use-equals-delete
-modernize-use-noexcept
-modernize-use-nullptr
-modernize-use-trailing-return-type
-modernize-use-using
-performance-faster-string-find
-performance-inefficient-string-concatenation
-performance-unnecessary-copy-initialization
-performance-unnecessary-value-param
-readability-const-return-type
-readability-convert-member-functions-to-static
-readability-else-after-return
-readability-implicit-bool-cast
-readability-isolate-declaration
-readability-magic-numbers
-readability-make-member-function-const
-readability-named-parameter
-readability-non-const-parameter
-readability-qualified-auto
-readability-redundant-control-flow
-readability-redundant-smartptr-get
-readability-redundant-string-cstr
-readability-string-compare
-readability-uppercase-literal-suffix
-cert-err58-cpp
-cert-err60-cpp
-cert-msc30-c
-cert-msc50-cpp
-clang-analyzer-alpha.cplusplus.VirtualCall
-clang-analyzer-core.DivideZero
-clang-analyzer-optin.cplusplus.VirtualCall
-cppcoreguidelines-no-malloc
-cppcoreguidelines-owning-memory
-readability-misleading-indentation
endef
clang_tidy_checks := *,$(shell echo $(strip $(-clang_tidy_checks)) | tr ' ' ',')
# make-tidy-rule
#
# add a rule to invoke clang-tidy for the given source files
# arguments:
# #1: identifier for library/executable
# #2: source files
# #3: include paths and defines
make-tidy-rule = $(eval $(call -make-tidy-rule,$(strip $1),$2,$3))
define -specific-tidy-rule
$1:
@echo "[TIDY] $2"
$V$(CLANG_TIDY) -checks='$(clang_tidy_checks)' -quiet $2 -- $$(CXXFLAGS) $3
endef
define -make-tidy-rule
.PHONY: tidy
tidy: tidy-$1
.PHONY: tidy-$1 $(foreach file,$2,$(file).tidy-$1)
tidy-$1: $(foreach file,$2,$(file).tidy-$1)
$(foreach file,$2,$(eval $(call -specific-tidy-rule,$(file).tidy-$1,$(file),$3)))
endef
define -build-pch-fragment
ifneq ($(BEEGFS_USE_PCH),)
# .o files depend on precompiled headers.
$(addsuffix .o,$2): CXXFLAGS += -include $(1).autogen.h
$(addsuffix .o,$2): $(1).autogen.h.gch
endif
# not behind conditional -- let's delete these always
CLEANUP_FILES += $(1).autogen.h $(1).autogen.h.gch
CLEANUP_FILES += $(1).autogen.h.d # "dependency" files that get produced when compiling the header
endef
# build-executable
#
# define a new executable for the build
# arguments:
# #1: name of the executable
# #2: sources
# #3: required libraries
# #4: include directories
build-executable = $(eval $(call -build-executable-fragment,$(strip $1),$2,$3,$4))
define -build-executable-fragment
all: $1
$(call -build-pch-fragment,$1,$2)
CLEANUP_FILES += $1 $(addsuffix .o,$2) $(addsuffix .d,$2)
$(addsuffix .o .tidy-%,$2): CXXFLAGS += \
$(foreach lib,$3,$(call resolve-dep-cflags,$(lib))) $(addprefix -I, $4)
$1: LDFLAGS += \
-Wl,--start-group $(foreach lib,$3,$(call resolve-dep-ldflags,$(lib))) -Wl,--end-group
$1: $(addsuffix .o,$2) $(foreach lib,$3,$(call resolve-dep-deps,$(lib)))
@echo "[LD] $$@"
$$V$$(CXX) -o $$@ $(addsuffix .o,$2) $$(LDFLAGS)
-include $(addsuffix .d,$2)
$(call make-tidy-rule, $1, $2,\
$(foreach lib,$3,$(call resolve-dep-cflags,$(lib))) $(addprefix -I, $4))
endef
# build-test
#
# build a test runner from specified test files. acts much like build-executable, except that it
# includes gtest in the build as a non-library .a
# #1: name if the test executable
# #2: sources
# #3: required libraries (not including gtest)
# #4: included directories (not including gtest)
define build-test
$(call build-executable, $1, $2, $3, $4 -isystem $(GTEST_INC_PATH))
$1: LDFLAGS += $(GTEST_LIB_PATH)/libgtest.a
endef
# build-static-library
#
# define a new (static) library for the build
# arguments:
# #1: name of the library
# #2: sources
# #3: required libraries
# #4: include directories
build-static-library = $(eval $(call -build-static-library-fragment,lib$(strip $1).a,$2,$3,$4))
define -build-static-library-fragment
all: $1
$(call -build-pch-fragment,$1,$2)
CLEANUP_FILES += $1 $(addsuffix .o,$2) $(addsuffix .d,$2)
$(addsuffix .o .tidy-%,$2): CXXFLAGS += \
$(foreach lib,$3,$(call resolve-dep-cflags,$(lib))) $(addprefix -I, $4)
$(build_dir)/$1: $(addsuffix .o,$2)
@echo "[AR] $1"
@rm -f $$@
$$V$(AR) -rcs $$@ $$^
$1: $(build_dir)/$1
-include $(addsuffix .d,$2)
$(call make-tidy-rule, $1, $2,\
$(foreach lib,$3,$(call resolve-dep-cflags,$(lib))) $(addprefix -I, $4))
endef
# build-shared-library
#
# define a new (shared) library for the build
# arguments:
# #1: name of the library
# #2: sources
# #3: required libraries
# #4: include directories
build-shared-library = $(eval $(call -build-shared-library-fragment,lib$(strip $1).so,$2,$3,$4))
define -build-shared-library-fragment
all: $1
$(call -build-pch-fragment,$1,$2)
CLEANUP_FILES += $1 $(addsuffix .o,$2) $(addsuffix .d,$2)
$(addsuffix .o .tidy-%,$2): CXXFLAGS += \
-fPIC $(foreach lib,$3,$(call resolve-dep-cflags,$(lib))) $(addprefix -I, $4)
$1: LDFLAGS += \
-Wl,--start-group $(foreach lib,$3,$(call resolve-dep-ldflags,$(lib))) -Wl,--end-group
$(build_dir)/$1: $(addsuffix .o,$2) $(foreach lib,$3,$(call resolve-dep-deps,$(lib)))
@echo "[LD] $1"
$$V$$(CXX) -shared -o $$@ $(addsuffix .o,$2) \
-Wl,--whole-archive $$(LDFLAGS) -Wl,--no-whole-archive
$1: $(build_dir)/$1
-include $(addsuffix .d,$2)
$(call make-tidy-rule, $1, $2,\
$(foreach lib,$3,$(call resolve-dep-cflags,$(lib))) $(addprefix -I, $4))
endef

3
build/filter-requires.sh Executable file
View File

@@ -0,0 +1,3 @@
#!/bin/sh
$* | sed -e '/libibverbs|librdmacm/ d'

28
build/make-deb-common Normal file
View File

@@ -0,0 +1,28 @@
export TOP_PID=$$
function die() {
echo "${*}" >&2
kill $TOP_PID
}
function getVersion() {
dpkg-query -f '${Version}' -W "${1}" 2>/dev/null || die "Package ${1} is not installed."
}
function isNewerVersion() {
local v=$(getVersion "${1}")
dpkg --compare-versions "${v}" \>= "${2}"
}
function runDebuild() {
# build the package and supress lintian warnings. Lintian in Lenny cannot
# do that itself yet
# NOTE: package not signed yet! (-us -uc)`
yes | debuild -us -uc 2>&1 | egrep -v "dir-or-file-in-opt | file-in-unusual-dir"
if $(isNewerVersion devscripts 2.16.10); then
yes | debuild -- clean
else
yes | debuild clean
fi
}

View File

@@ -0,0 +1,11 @@
install(
FILES "include/beegfs/beegfs.h" "include/beegfs/beegfs_ioctl.h" "include/beegfs/beegfs_ioctl_functions.h"
DESTINATION "usr/include/beegfs"
COMPONENT "client-devel"
)
install(
FILES "build/dist/usr/share/doc/beegfs-client-devel/examples/createFileWithStripePattern.cpp"
DESTINATION "usr/share/doc/beegfs/examples/createFileWithStripePattern"
COMPONENT "client-devel"
)

View File

@@ -0,0 +1,34 @@
BEEGFS_COMMON_PATH ?= ../../common/
ifneq ($(BEEGFS_VERSION),)
BEEGFS_EXTRA_FLAGS += 'BEEGFS_VERSION="$(BEEGFS_VERSION)"'
endif
ifneq ($(BEEGFS_DEBUG),)
BEEGFS_EXTRA_FLAGS += 'BEEGFS_DEBUG=$(BEEGFS_DEBUG)'
endif
all:
clean:
help:
@echo 'Optional Arguments:'
@echo ' BEEGFS_DEBUG=1:'
@echo ' Enables debug information and symbols.'
@echo ' CXX=<compiler>:'
@echo ' Specifies a c++ compiler.'
@echo ' BEEGFS_COMMON_PATH=<path>:'
@echo ' Path to the common directory.'
@echo
@echo 'Targets:'
@echo ' all (default) - build only'
@echo ' help - print this help message'
# Include dependency files
ifneq ($(DEPENDENCY_FILES),)
include $(DEPENDENCY_FILES)
endif

View File

@@ -0,0 +1,81 @@
#include <beegfs/beegfs.h>
#include <dirent.h>
#include <errno.h>
#include <iostream>
#include <libgen.h>
#include <stdlib.h>
static const mode_t MODE_FLAG = S_IRWXU | S_IRGRP | S_IROTH;
static const unsigned numtargets = 8;
static const unsigned chunksize = 1048576; // 1 Mebibyte
int main(int argc, char** argv)
{
// check if a path to the file is provided
if(argc != 2)
{
std::cout << "Usage: " << argv[0] << " $PATH_TO_FILE" << std::endl;
exit(-1);
}
std::string file(argv[1]);
std::string fileName(basename(argv[1]) );
std::string parentDirectory(dirname(argv[1]) );
// check if we got a file name from the given path
if(fileName.empty() )
{
std::cout << "Can not get file name from given path: " << file << std::endl;
exit(-1);
}
// check if we got the parent directory path from the given path
if(parentDirectory.empty() )
{
std::cout << "Can not get parent directory path from given path: " << file << std::endl;
exit(-1);
}
// open the directory to get a directory stream
DIR* parentDir = opendir(parentDirectory.c_str() );
if(parentDir == NULL)
{
std::cout << "Can not get directory stream of directory: " << parentDirectory
<< " errno: " << errno << std::endl;
exit(-1);
}
// get a fd of the parent directory
int fd = dirfd(parentDir);
if(fd == -1)
{
std::cout << "Can not get fd from directory: " << parentDirectory
<< " errno: " << errno << std::endl;
exit(-1);
}
// check if the parent directory is located on a BeeGFS, because the striping API works only on
// BeeGFS (Results of BeeGFS ioctls on other file systems are undefined.)
bool isBeegfs = beegfs_testIsBeeGFS(fd);
if(!isBeegfs)
{
std::cout << "The given file is not located on an BeeGFS: " << file << std::endl;
exit(-1);
}
// create the file with the given stripe pattern
bool isFileCreated = beegfs_createFile(fd, fileName.c_str(), MODE_FLAG, numtargets, chunksize);
if(isFileCreated)
{
std::cout << "File successful created: " << file << std::endl;
}
else
{
std::cout << "Can not create file: " << file << " errno: " << errno << std::endl;
exit(-1);
}
}

View File

@@ -0,0 +1,108 @@
#include <beegfs/beegfs.h>
#include <errno.h>
#include <iostream>
#include <stdlib.h>
static const mode_t MODE_FLAG = S_IRWXU | S_IRGRP | S_IROTH;
static const int OPEN_FLAGS = O_RDWR;
int main(int argc, char** argv)
{
// check if a path to the file is provided
if(argc != 2)
{
std::cout << "Usage: " << argv[0] << " $PATH_TO_FILE" << std::endl;
exit(-1);
}
std::string file(argv[1]);
// open the provided file
int fd = open(file.c_str(), OPEN_FLAGS, MODE_FLAG);
if(fd == -1)
{
std::cout << "Open: can not open file: " << file << " errno: " << errno << std::endl;
exit(-1);
}
// check if the file is located on a BeeGFS, because the striping API works only on a BeeGFS
// (Results of BeeGFS ioctls on other file systems are undefined.)
bool isBeegfs = beegfs_testIsBeeGFS(fd);
if(!isBeegfs)
{
std::cout << "The given file is not located on an BeeGFS: " << file << std::endl;
exit(-1);
}
unsigned outPatternType = 0;
unsigned outChunkSize = 0;
uint16_t outNumTargets = 0;
// retrive the stripe pattern of the file and print them to the console
bool stripeInfoRetVal = beegfs_getStripeInfo(fd, &outPatternType, &outChunkSize, &outNumTargets);
if(stripeInfoRetVal)
{
std::string patternType;
switch(outPatternType)
{
case BEEGFS_STRIPEPATTERN_RAID0:
patternType = "RAID0";
break;
case BEEGFS_STRIPEPATTERN_RAID10:
patternType = "RAID10";
break;
case BEEGFS_STRIPEPATTERN_BUDDYMIRROR:
patternType = "BUDDYMIRROR";
break;
default:
patternType = "INVALID";
}
std::cout << "Stripe pattern of file: " << file << std::endl;
std::cout << "+ Type: " << patternType << std::endl;
std::cout << "+ Chunksize: " << outChunkSize << " Byte" << std::endl;
std::cout << "+ Number of storage targets: " << outNumTargets << std::endl;
std::cout << "+ Storage targets:" << std::endl;
// get the targets which are used for the file and print them to the console
for (int targetIndex = 0; targetIndex < outNumTargets; targetIndex++)
{
struct BeegfsIoctl_GetStripeTargetV2_Arg outTargetInfo;
bool stripeTargetRetVal = beegfs_getStripeTargetV2(fd, targetIndex, &outTargetInfo);
if(stripeTargetRetVal)
{
if(outPatternType == BEEGFS_STRIPEPATTERN_BUDDYMIRROR)
{
std::cout << " + " << outTargetInfo.targetOrGroup
<< " @ " << outTargetInfo.primaryTarget
<< " @ " << outTargetInfo.primaryNodeAlias
<< " [ID: "<< outTargetInfo.primaryNodeID << "]" << std::endl;
std::cout << " + " << outTargetInfo.targetOrGroup
<< " @ " << outTargetInfo.secondaryTarget
<< " @ " << outTargetInfo.secondaryNodeAlias
<< " [ID: "<< outTargetInfo.secondaryNodeID << "]" << std::endl;
}
else
{
std::cout << " + " << outTargetInfo.targetOrGroup
<< " @ " << outTargetInfo.primaryNodeAlias
<< " [ID: "<< outTargetInfo.primaryNodeID << "]" << std::endl;
}
}
else
{
std::cout << "Can not get stripe targets of file: " << file << std::endl;
exit(-1);
}
}
}
else
{
std::cout << "Can not get stripe info of file: " << file << std::endl;
exit(-1);
}
}

View File

@@ -0,0 +1,6 @@
#ifndef __BEEGFS_H__
#define __BEEGFS_H__
#include <beegfs/beegfs_ioctl.h>
#endif /* __BEEGFS_H__ */

View File

@@ -0,0 +1,11 @@
#ifndef __BEEGFS_IOCTL_H__
#define __BEEGFS_IOCTL_H__
#include <stdint.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <uapi/beegfs_client.h>
#include <beegfs/beegfs_ioctl_functions.h>
#endif /* __BEEGFS_IOCTL_H__ */

View File

@@ -0,0 +1,335 @@
#ifndef __BEEGFS_IOCTL_FUNCTIONS_H__
#define __BEEGFS_IOCTL_FUNCTIONS_H__
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#ifndef __cplusplus
#include <stdbool.h>
#endif
#define BEEGFS_API_MAJOR_VERSION 1 // major version number of the API, different major version
// are incompatible
#define BEEGFS_API_MINOR_VERSION 1 // minor version number of the API, the minor versions of the
// same major version are backward compatible
#define beegfs_api_version_check() { return beegfs_checkApiVersion(); } // backward compatibility
static inline bool beegfs_getConfigFile(int fd, char** outCfgFile);
static inline bool beegfs_getRuntimeConfigFile(int fd, char** outCfgFile);
static inline bool beegfs_testIsBeeGFS(int fd);
static inline bool beegfs_getMountID(int fd, char** outMountID);
static inline bool beegfs_getStripeInfo(int fd, unsigned* outPatternType, unsigned* outChunkSize,
uint16_t* outNumTargets);
static inline bool beegfs_getStripeTarget(int fd, uint16_t targetIndex, uint16_t* outTargetNumID,
uint16_t* outNodeNumID, char** outNodeStrID);
static inline bool beegfs_getStripeTargetV2(int fd, uint32_t targetIndex,
struct BeegfsIoctl_GetStripeTargetV2_Arg* outTargetInfo);
static inline bool beegfs_createFile(int fd, const char* filename, mode_t mode,
unsigned numtargets, unsigned chunksize);
static inline bool beegfs_getInodeID(int fd, const char* entryID, uint64_t* outInodeID);
static inline bool beegfs_getEntryInfo(int fd, uint32_t* ownerID, char* parentEntryID,
char* entryID, int* entryType, int* featureFlags);
static inline bool beegfs_checkApiVersion(const unsigned required_major_version,
const unsigned required_minor_version);
static inline bool beegfs_pingNode(int fd, struct BeegfsIoctl_PingNode_Arg* ping);
/**
* Get the path to the client config file of an active BeeGFS mountpoint.
*
* @param fd filedescriptor pointing to file or dir inside BeeGFS mountpoint.
* @param outCfgFile buffer for config file path; will be malloc'ed and needs to be free'd by
* caller if success was returned.
* @return true on success, false on error (in which case errno will be set).
*/
bool beegfs_getConfigFile(int fd, char** outCfgFile)
{
struct BeegfsIoctl_GetCfgFile_Arg getCfgFile;
getCfgFile.length = BEEGFS_IOCTL_CFG_MAX_PATH;
int res = ioctl(fd, BEEGFS_IOC_GET_CFG_FILE, &getCfgFile);
if(res)
return false;
*outCfgFile = strndup(getCfgFile.path, BEEGFS_IOCTL_CFG_MAX_PATH);
if(!*outCfgFile)
return false;
return true;
}
/**
* Get the path to the client runtime config file in procfs.
*
* @param fd filedescriptor pointing to file or dir inside BeeGFS mountpoint.
* @param outCfgFile buffer for config file path; will be malloc'ed and needs to be free'd by
* caller if success was returned.
* @return true on success, false on error (in which case errno will be set).
*/
bool beegfs_getRuntimeConfigFile(int fd, char** outCfgFile)
{
struct BeegfsIoctl_GetCfgFile_Arg getCfgFile;
getCfgFile.length = BEEGFS_IOCTL_CFG_MAX_PATH;
int res = ioctl(fd, BEEGFS_IOC_GET_RUNTIME_CFG_FILE, &getCfgFile);
if(res)
return false;
*outCfgFile = strndup(getCfgFile.path, BEEGFS_IOCTL_CFG_MAX_PATH);
if(!*outCfgFile)
return false;
return true;
}
/**
* Test if the underlying file system is a BeeGFS.
*
* @param fd filedescriptor pointing to some file or dir that should be checked for whether it is
* located inside a BeeGFS mount.
* @return true on success, false on error (in which case errno will be set).
*/
bool beegfs_testIsBeeGFS(int fd)
{
char testArray[sizeof(BEEGFS_IOCTL_TEST_STRING)];
#ifdef BEEGFS_DEBUG
// just calm valgrind; it does not detect that the array is initialized by the ioctl
memset(testArray, 0, sizeof(BEEGFS_IOCTL_TEST_STRING) );
#endif
int ioctlRes = ioctl(fd, BEEGFS_IOC_TEST_IS_BEEGFS, testArray);
if(ioctlRes)
return false;
int memCmpRes = memcmp(testArray, BEEGFS_IOCTL_TEST_STRING, sizeof(BEEGFS_IOCTL_TEST_STRING) );
if(memCmpRes)
{ // ioctl was accepted by underlying fs, but buffer wasn't filled correctly
errno = EPROTO;
return false; // verification through buffer failed, probably just not a beegfs
}
return true;
}
/**
* Get the mountID aka clientID aka nodeID of client mount aka sessionID.
*
* @param fd filedescriptor pointing to some file or dir that should be checked for whether it is
* located inside a BeeGFS mount.
* @return true on success, false on error (in which case errno will be set).
*/
bool beegfs_getMountID(int fd, char** outMountID)
{
char mountIDBuf[BEEGFS_IOCTL_MOUNTID_BUFLEN];
#ifdef BEEGFS_DEBUG
// just calm valgrind; it does not detect that the array is initialized by the ioctl
memset(mountIDBuf, 0, sizeof(mountIDBuf) );
#endif
int ioctlRes = ioctl(fd, BEEGFS_IOC_GET_MOUNTID, mountIDBuf);
if(ioctlRes)
return false;
*outMountID = strndup(mountIDBuf, sizeof(mountIDBuf) );
if(!*outMountID)
return false;
return true;
}
/**
* Get the stripe info of a file.
*
* @param fd filedescriptor pointing to some file inside a BeeGFS mount.
* @param outPatternType type of stripe pattern (BEEGFS_STRIPEPATTERN_...)
* @param outChunkSize chunk size for striping.
* @param outNumTargets number of targets for striping.
* @return true on success, false on error (in which case errno will be set).
*/
bool beegfs_getStripeInfo(int fd, unsigned* outPatternType, unsigned* outChunkSize,
uint16_t* outNumTargets)
{
struct BeegfsIoctl_GetStripeInfo_Arg getStripeInfo;
int res = ioctl(fd, BEEGFS_IOC_GET_STRIPEINFO, &getStripeInfo);
if(res)
return false;
*outPatternType = getStripeInfo.outPatternType;
*outChunkSize = getStripeInfo.outChunkSize;
*outNumTargets = getStripeInfo.outNumTargets;
return true;
}
/**
* Get the stripe target of a file (with 0-based index).
*
* @param fd filedescriptor pointing to some file inside a BeeGFS mount.
* @param targetIndex index of target that should be retrieved (start with 0 and then call this
* again with index up to "*outNumTargets-1" to retrieve remaining targets).
* @param outTargetNumID numeric ID of target at given index.
* @param outNodeNumID numeric ID to node to which this target is assigned.
* @param outNodeAlias alias (formerly string ID) of the node to which this target is assigned;
* buffer will be alloc'ed and needs to be free'd by caller if success is returned.
* @return true on success, false on error (in which case errno will be set).
*/
bool beegfs_getStripeTarget(int fd, uint16_t targetIndex, uint16_t* outTargetNumID,
uint16_t* outNodeNumID, char** outNodeAlias)
{
struct BeegfsIoctl_GetStripeTarget_Arg getStripeTarget;
getStripeTarget.targetIndex = targetIndex;
int res = ioctl(fd, BEEGFS_IOC_GET_STRIPETARGET, &getStripeTarget);
if(res)
return false;
*outTargetNumID = getStripeTarget.outTargetNumID;
*outNodeNumID = getStripeTarget.outNodeNumID;
*outNodeAlias = strndup(getStripeTarget.outNodeAlias, BEEGFS_IOCTL_CFG_MAX_PATH);
if(!*outNodeAlias)
return false;
return true;
}
/**
* Get the stripe target of a file (with 0-based index).
*
* @param fd filedescriptor pointing to some file inside a BeeGFS mount.
* @param targetIndex index of target that should be retrieved (start with 0 and then call this
* again with index up to "*outNumTargets-1" to retrieve remaining targets).
* @param outTargetInfo pointer to struct that will be filled with information about the selected
* stripe target
* @return true on success, false on error (in which case errno will be set).
*/
bool beegfs_getStripeTargetV2(int fd, uint32_t targetIndex,
struct BeegfsIoctl_GetStripeTargetV2_Arg* outTargetInfo)
{
memset(outTargetInfo, 0, sizeof(*outTargetInfo));
outTargetInfo->targetIndex = targetIndex;
return ioctl(fd, BEEGFS_IOC_GET_STRIPETARGET_V2, outTargetInfo) == 0;
}
/**
* Create a new regular file with stripe hints.
*
* As the stripe pattern cannot be changed when a file is already created, this is an exclusive
* create, so it will return an error if the file already existed.
*
* @param fd filedescriptor pointing to parent directory for the new file.
* @param filename name of created file.
* @param mode permission bits of new file (i.e. symbolic constants like S_IRWXU or 0644).
* @param numtargets desired number of storage targets for striping; 0 for directory default; ~0 to
* use all available targets.
* @param chunksize chunksize per storage target for striping in bytes; 0 for directory default;
* must be 2^n >= 64KiB.
* @return true on success, false on error (in which case errno will be set).
*/
bool beegfs_createFile(int fd, const char* filename, mode_t mode, unsigned numtargets,
unsigned chunksize)
{
struct BeegfsIoctl_MkFileWithStripeHints_Arg createFileArg;
createFileArg.filename = filename;
createFileArg.mode = mode;
createFileArg.numtargets = numtargets;
createFileArg.chunksize = chunksize;
int res = ioctl(fd, BEEGFS_IOC_MKFILE_STRIPEHINTS, &createFileArg);
if(res)
return false;
return true;
}
bool beegfs_getInodeID(int fd, const char* entryID, uint64_t* outInodeID)
{
struct BeegfsIoctl_GetInodeID_Arg getInodeIDArg;
getInodeIDArg.entryID[BEEGFS_IOCTL_ENTRYID_MAXLEN] = '\0';
strncpy(getInodeIDArg.entryID, entryID, BEEGFS_IOCTL_ENTRYID_MAXLEN);
if(ioctl(fd, BEEGFS_IOC_GETINODEID, &getInodeIDArg))
{
*outInodeID = 0;
return false;
}
*outInodeID = getInodeIDArg.inodeID;
return true;
}
/**
* Get entryInfo data for given file.
*
* @param fd filedescriptor pointing to some file inside a BeeGFS mount.
* @param ownerID pointer to an uint32_t in which the ownerID shall be stored
* @param parentEntryID pointer to a buffer for the parent entryID. The buffer must
* be at least BEEGFS_IOCTL_ENTRYID_MAXLEN + 1 bytes long.
* @param entryID pointer to a buffer for the entryID. The buffer must
* be at least BEEGFS_IOCTL_ENTRYID_MAXLEN + 1 bytes long.
* @param entryType pointer to an int in which the entryType shall be stored
* @param featureFlags pointer to an int in which the feature flags shall be stored
* @return success/failure
*/
bool beegfs_getEntryInfo(int fd, uint32_t* ownerID, char* parentEntryID,
char* entryID, int* entryType, int* featureFlags)
{
struct BeegfsIoctl_GetEntryInfo_Arg arg;
if(ioctl(fd, BEEGFS_IOC_GETENTRYINFO, &arg))
{
return false;
}
*ownerID = arg.ownerID;
strncpy(parentEntryID, arg.parentEntryID, BEEGFS_IOCTL_ENTRYID_MAXLEN + 1);
strncpy(entryID, arg.entryID, BEEGFS_IOCTL_ENTRYID_MAXLEN + 1);
*entryType = arg.entryType;
*featureFlags = arg.featureFlags;
return true;
}
/**
* Checks if the required API version of the application is compatible to current API version
*
* @param required_major_version the required major API version of the user application
* @param required_minor_version the minimal required minor API version of the user application
* @return true if the required version and the API version are compatible, if not false is returned
*/
bool beegfs_checkApiVersion(const unsigned required_major_version,
const unsigned required_minor_version)
{
if(required_major_version != BEEGFS_API_MAJOR_VERSION)
return false;
if(required_minor_version > BEEGFS_API_MINOR_VERSION)
return false;
return true;
}
static inline bool beegfs_pingNode(int fd, struct BeegfsIoctl_PingNode_Arg* inoutPing)
{
if(ioctl(fd, BEEGFS_IOC_PINGNODE, inoutPing))
{
return false;
}
return true;
}
#endif /* __BEEGFS_IOCTL_FUNCTIONS_H__ */

View File

@@ -0,0 +1,102 @@
if(NOT BEEGFS_SKIP_CLIENT)
include(ExternalProject)
ExternalProject_Add(
client-module
BUILD_IN_SOURCE ON
URL "${CMAKE_CURRENT_SOURCE_DIR}"
CONFIGURE_COMMAND ""
BUILD_COMMAND make -C build -j $(nproc) "KDIR=${BEEGFS_KERNELDIR}" "OFED_INCLUDE_PATH=${BEEGFS_OFEDDIR}"
INSTALL_COMMAND ""
)
endif()
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/build/dkms.conf.client"
"${CMAKE_CURRENT_BINARY_DIR}/dkms.conf.client"
)
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/build/dkms.conf.compat"
"${CMAKE_CURRENT_BINARY_DIR}/dkms.conf.compat"
)
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/build/postinst.in"
"${CMAKE_CURRENT_BINARY_DIR}/postinst"
)
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/build/prerm.in"
"${CMAKE_CURRENT_BINARY_DIR}/prerm"
)
install(
DIRECTORY ""
DESTINATION "usr/src/beegfs-${BEEGFS_VERSION}"
COMPONENT "client"
USE_SOURCE_PERMISSIONS
PATTERN "CMakeLists.txt" EXCLUDE
PATTERN "dkms.conf.*" EXCLUDE
)
install(
FILES "${CMAKE_CURRENT_BINARY_DIR}/dkms.conf.client"
DESTINATION "usr/src/beegfs-${BEEGFS_VERSION}"
RENAME "dkms.conf"
COMPONENT "client"
)
install(
FILES "build/dist/etc/beegfs-client.conf"
DESTINATION "etc/beegfs"
COMPONENT "client"
)
install(
DIRECTORY ""
DESTINATION "usr/src/beegfs-compat-${BEEGFS_VERSION}"
COMPONENT "client-compat"
USE_SOURCE_PERMISSIONS
PATTERN "CMakeLists.txt" EXCLUDE
PATTERN "dkms.conf.*" EXCLUDE
)
install(
FILES "${CMAKE_CURRENT_BINARY_DIR}/dkms.conf.compat"
DESTINATION "usr/src/beegfs-compat-${BEEGFS_VERSION}"
RENAME "dkms.conf"
COMPONENT "client-compat"
)
# Debian package settings
set(CPACK_DEBIAN_CLIENT_PACKAGE_DEPENDS "dkms" PARENT_SCOPE)
set(
CPACK_DEBIAN_CLIENT_PACKAGE_CONTROL_EXTRA
"${CMAKE_CURRENT_BINARY_DIR}/prerm;${CMAKE_CURRENT_BINARY_DIR}/postinst;${CMAKE_CURRENT_BINARY_DIR}/dkms.conf.client"
PARENT_SCOPE
)
# currently no dkms in compat package
# set(
# CPACK_DEBIAN_CLIENT-COMPAT_PACKAGE_CONTROL_EXTRA
# "${CMAKE_CURRENT_BINARY_DIR}/dkms.conf.compat"
# PARENT_SCOPE
# )
# RPM package settings
set(CPACK_RPM_CLIENT_PACKAGE_REQUIRES "dkms" PARENT_SCOPE)
set(
CPACK_RPM_PRE_UNINSTALL_SCRIPT_FILE
"${CMAKE_CURRENT_BINARY_DIR}/prerm"
PARENT_SCOPE
)
set(
CPACK_RPM_POST_INSTALL_SCRIPT_FILE
"${CMAKE_CURRENT_BINARY_DIR}/postinst"
PARENT_SCOPE
)

View File

@@ -0,0 +1,52 @@
# Automatic rebuild of BeeGFS client modules on kernel change.
AUTO_REBUILD_KVER_FILE := auto_rebuild_kernel.ver
AUTO_REBUILD_KVER_CURRENT = $(shell uname -srvmpi)
AUTO_REBUILD_LOG_PREFIX := "BeeGFS Client Auto-Rebuild:"
# config file (keys)
AUTO_REBUILD_CONF_FILE := /etc/beegfs/beegfs-client-autobuild.conf
AUTO_REBUILD_CONF_ENABLED_KEY := buildEnabled
AUTO_REBUILD_CONF_BUILDARGS_KEY := buildArgs
# config file (values)
AUTO_REBUILD_CONF_ENABLED = $(shell \
grep -s "^\s*$(AUTO_REBUILD_CONF_ENABLED_KEY)\s*=" "$(AUTO_REBUILD_CONF_FILE)" | \
cut --delimiter="=" --fields="2-" )
AUTO_REBUILD_CONF_BUILDARGS = $(shell \
grep "^\s*$(AUTO_REBUILD_CONF_BUILDARGS_KEY)\s*=" "$(AUTO_REBUILD_CONF_FILE)" | \
cut --delimiter="=" --fields="2-" )
# add build dependency if rebuild has been enabled in config file
ifeq ($(AUTO_REBUILD_CONF_ENABLED), true)
AUTO_REBUILD_CONFIGURED_DEPS := auto_rebuild_install
endif
# environment variables (intentionally commented out here; just to mention
# them somewhere)
# - AUTO_REBUILD_KVER_STORED: internally for target auto_rebuild
auto_rebuild:
$(MAKE) auto_rebuild_clean $(AUTO_REBUILD_CONF_BUILDARGS)
$(MAKE) $(AUTO_REBUILD_CONF_BUILDARGS)
# checked rebuild and install
auto_rebuild_install: auto_rebuild
$(MAKE) install $(AUTO_REBUILD_CONF_BUILDARGS)
# run checked rebuild and install if enabled in config file
auto_rebuild_configured: $(AUTO_REBUILD_CONFIGURED_DEPS)
@ /bin/true
auto_rebuild_clean: clean
@ /bin/true
auto_rebuild_help:
@echo 'No Auto-Rebuild Arguments defined.'

View File

@@ -0,0 +1,334 @@
# All detected features are included in "KERNEL_FEATURE_DETECTION"
# parameters:
# $1: name to define when grep finds something
# $2: grep flags and expression
# $3: input files in linux source tree
define define_if_matches
$(eval \
KERNEL_FEATURE_DETECTION += $$(shell \
grep -q -s $2 $(addprefix ${KSRCDIR_PRUNED_HEAD}/include/linux/,$3) \
&& echo "-D$(strip $1)"))
endef
ifneq ($(OFED_INCLUDE_PATH),)
OFED_DETECTION_PATH := $(OFED_INCLUDE_PATH)
else
OFED_DETECTION_PATH := ${KSRCDIR_PRUNED_HEAD}/include
endif
# Find out whether rdma_create_id function has qp_type argument.
# This is tricky because the function declaration spans multiple lines.
# Note: Was introduced in vanilla 3.0
KERNEL_FEATURE_DETECTION += $(shell \
grep -sA2 "struct rdma_cm_id \*rdma_create_id(" ${OFED_DETECTION_PATH}/rdma/rdma_cm.h 2>&1 \
| grep -qs "ib_qp_type qp_type);" \
&& echo "-DOFED_HAS_RDMA_CREATE_QPTYPE")
# Find out whether rdma_set_service_type function has been declared.
# Note: Was introduced in vanilla 2.6.24
KERNEL_FEATURE_DETECTION += $(shell \
grep -qs "rdma_set_service_type(struct rdma_cm_id \*id, int tos)" \
${OFED_DETECTION_PATH}/rdma/rdma_cm.h \
&& echo "-DOFED_HAS_SET_SERVICE_TYPE")
# Find out whether ib_create_cq function has cq_attr argument
# This is tricky because the function declaration spans multiple lines.
# Note: Was introduced in vanilla 4.2
KERNEL_FEATURE_DETECTION += $(shell \
grep -sA4 "struct ib_cq \*ib_create_cq(struct ib_device \*device," ${OFED_DETECTION_PATH}/rdma/ib_verbs.h 2>&1 \
| grep -qs "const struct ib_cq_init_attr \*cq_attr);" \
&& echo "-DOFED_HAS_IB_CREATE_CQATTR")
# Find out whether rdma_reject function has reason argument
# This is tricky because the function declaration spans multiple lines.
# Note: Was introduced in MLNX OFED 5.1
KERNEL_FEATURE_DETECTION += $(shell \
grep -sA1 "int rdma_reject(" ${OFED_DETECTION_PATH}/rdma/rdma_cm.h 2>&1 \
| grep -qs "u8 reason);" \
&& echo "-DOFED_RDMA_REJECT_NEEDS_REASON")
# kernels >=v4.4 expect a netns argument for rdma_create_id
KERNEL_FEATURE_DETECTION += $(shell \
grep -qs "struct rdma_cm_id \*rdma_create_id.struct net \*net," \
${OFED_DETECTION_PATH}/rdma/rdma_cm.h \
&& echo "-DOFED_HAS_NETNS")
# kernels >=v4.4 split up ib_send_wr into a lot of other structs
KERNEL_FEATURE_DETECTION += $(shell \
grep -qs -F "struct ib_atomic_wr {" \
${OFED_DETECTION_PATH}/rdma/ib_verbs.h \
&& echo "-DOFED_SPLIT_WR")
KERNEL_FEATURE_DETECTION += $(shell \
grep -qs -F "IB_PD_UNSAFE_GLOBAL_RKEY" \
${OFED_DETECTION_PATH}/rdma/ib_verbs.h \
&& echo "-DOFED_UNSAFE_GLOBAL_RKEY")
KERNEL_FEATURE_DETECTION += $(shell \
grep -qs -F "ib_get_dma_mr" \
${OFED_DETECTION_PATH}/rdma/ib_verbs.h \
&& echo "-DOFED_IB_GET_DMA_MR")
KERNEL_FEATURE_DETECTION += $(shell \
grep -qs -F "static inline void ib_destroy_cq" \
${OFED_DETECTION_PATH}/rdma/ib_verbs.h \
&& echo "-DOFED_IB_DESTROY_CQ_IS_VOID")
# Find out whether the kernel has a scsi/fc_compat.h file, which defines
# vlan_dev_vlan_id.
# Note: We need this, because some kernels (e.g. RHEL 5.9's 2.6.18) forgot this
# include in their rdma headers, leading to implicit function declarations.
$(call define_if_matches, KERNEL_HAS_SCSI_FC_COMPAT, "vlan_dev_vlan_id", scsi/fc_compat.h)
# Find out whether the kernel has a ihold function.
# Note: Was added in vanilla 2.6.37, but RedHat adds it to their 2.6.32.
$(call define_if_matches, KERNEL_HAS_IHOLD, ' ihold(struct inode.*)', fs.h)
# Find out whether the kernel has fsync start and end range arguments.
# Note: fsync start and end were added in vanilla 3.1, but SLES11SP3 adds it to its 3.0 kernel.
$(call define_if_matches, KERNEL_HAS_FSYNC_RANGE, \
-F "int (*fsync) (struct file *, loff_t, loff_t, int datasync);", fs.h)
# Find out whether the kernel has define struct dentry_operations *s_d_op
# in struct super_block. If it has it used that to check if the file system
# needs to revalidate dentries.
$(call define_if_matches, KERNEL_HAS_S_D_OP, -F "struct dentry_operations *s_d_op;", fs.h)
# Find out whether the kernel has d_materialise_unique() to
# add dir dentries.
#
# Note: d_materialise_unique was added in vanilla 2.6.19 (backported to rhel5
# 2.6.18) and got merged into d_splice_alias in vanilla 3.19.
$(call define_if_matches, KERNEL_HAS_D_MATERIALISE_UNIQUE, \
-F "d_materialise_unique(struct dentry *, struct inode *)", dcache.h)
# Find out whether the kernel has a PDE_DATA method.
#
# Note: This method was added in vanilla linux-3.10
$(call define_if_matches, KERNEL_HAS_PDE_DATA, -F "PDE_DATA(const struct inode *)", proc_fs.h)
# Find out whether the kernel has i_uid_read
#
# Note: added to 3.5
$(call define_if_matches, KERNEL_HAS_I_UID_READ, "i_uid_read", fs.h)
# Find out whether the kernel has atomic_open
#
# Note: added to 3.5
$(call define_if_matches, KERNEL_HAS_ATOMIC_OPEN, "atomic_open", fs.h)
# Find out whether the kernel used umode_t
#
# Note: added to 3.3
$(call define_if_matches, KERNEL_HAS_UMODE_T, -E "(\*mkdir).*umode_t", fs.h)
# Find out if the kernel has a file_inode() method.
$(call define_if_matches, KERNEL_HAS_FILE_INODE, " file_inode(.*)", fs.h)
# Find out whether the kernel has a strnicmp function.
#
# Note: strnicmp was switched to strncasecmp in linux-4.0. strncasecmp existed
# before, but was wrong, so we only use strncasecmp if strnicmp doesn't exist.
$(call define_if_matches, KERNEL_HAS_STRNICMP, "strnicmp", string.h)
# Find out whether the kernel has BDI_CAP_MAP_COPY defined.
$(call define_if_matches, KERNEL_HAS_BDI_CAP_MAP_COPY, "define BDI_CAP_MAP_COPY", backing-dev.h)
# Find out whether xattr_handler** s_xattr in super_block is const.
$(call define_if_matches, KERNEL_HAS_CONST_XATTR_CONST_PTR_HANDLER, \
-F "const struct xattr_handler * const *s_xattr;", fs.h)
$(call define_if_matches, KERNEL_HAS_CONST_XATTR_HANDLER, \
-F "const struct xattr_handler **s_xattr;", fs.h)
# Find out whether xattr_handler functions need a dentry* (otherwise they need an inode*).
# Note: grepping for "(*set).struct..." instead of "(*set)(struct..." because make complains about
# the missing ")" otherwise.
$(call define_if_matches, KERNEL_HAS_DENTRY_XATTR_HANDLER, \
"int (\*set).struct dentry \*dentry", xattr.h)
# address_space.assoc_mapping went away in vanilla 3.8, but SLES11 backports that change
$(call define_if_matches, KERNEL_HAS_ADDRSPACE_ASSOC_MAPPING, -F "assoc_mapping", fs.h)
# current_umask() was added in 2.6.30
$(call define_if_matches, KERNEL_HAS_CURRENT_UMASK, -F "current_umask", fs.h)
# super_operations.show_options was changed to struct dentry* in 3.3
$(call define_if_matches, KERNEL_HAS_SHOW_OPTIONS_DENTRY, -F "int (*show_options)(struct seq_file *, struct dentry *);", fs.h)
# xattr handlers >=v4.4 also receive pointer to struct xattr_handler
KERNEL_FEATURE_DETECTION += $(shell \
grep -s -F "int (*get)" ${KSRCDIR_PRUNED_HEAD}/include/linux/xattr.h \
| grep -q -s -F "const struct xattr_handler *" \
&& echo "-DKERNEL_HAS_XATTR_HANDLER_PTR_ARG -DKERNEL_HAS_DENTRY_XATTR_HANDLER")
# 4.5 introduces name in xattr_handler, which can be used instead of prefix
KERNEL_FEATURE_DETECTION += $(shell \
grep -sFA1 "struct xattr_handler {" ${KSRCDIR_PRUNED_HEAD}/include/linux/xattr.h \
| grep -qsF "const char *name;" \
&& echo "-DKERNEL_HAS_XATTR_HANDLER_NAME")
# locks_lock_inode_wait is used for flock since 4.4 (before flock_lock_file_wait was used)
# since 6.3 locks_lock_inode_wait moved from file fs.h to filelock.h
$(call define_if_matches, KERNEL_HAS_LOCKS_FILELOCK_INODE_WAIT, -F "static inline int locks_lock_inode_wait(struct inode *inode, struct file_lock *fl)", filelock.h)
$(call define_if_matches, KERNEL_HAS_LOCKS_LOCK_INODE_WAIT, -F "static inline int locks_lock_inode_wait(struct inode *inode, struct file_lock *fl)", fs.h)
# get_link() replaces follow_link() in 4.5
$(call define_if_matches, KERNEL_HAS_GET_LINK, -F "const char * (*get_link) (struct dentry *, struct inode *, struct delayed_call *);", fs.h)
$(call define_if_matches, KERNEL_HAS_I_MMAP_LOCK, -F "i_mmap_lock_read", fs.h)
$(call define_if_matches, KERNEL_HAS_I_MMAP_RWSEM, -F "i_mmap_rwsem", fs.h)
$(call define_if_matches, KERNEL_HAS_I_MMAP_MUTEX, -F "i_mmap_mutex", fs.h)
$(call define_if_matches, KERNEL_HAS_I_MMAP_RBTREE, -P "struct rb_root\s+i_mmap", fs.h)
$(call define_if_matches, KERNEL_HAS_I_MMAP_CACHED_RBTREE, -P "struct rb_root_cached\s+i_mmap", fs.h)
$(call define_if_matches, KERNEL_HAS_I_MMAP_NONLINEAR, -F "i_mmap_nonlinear", fs.h)
$(call define_if_matches, KERNEL_HAS_INODE_LOCK, "static inline void inode_lock", fs.h)
#<linuy-4.8
$(call define_if_matches, KERNEL_HAS_PAGE_ENDIO, \
-F "void page_endio(struct page *page, int rw, int err);", pagemap.h)
#>=linux-4.8
$(call define_if_matches, KERNEL_HAS_PAGE_ENDIO, \
-F "void page_endio(struct page *page, bool is_write, int err);", pagemap.h)
# kernels <= 2.7.27 use remove_suid, others use file_remove_suid.
# except linux-3.10.0-514.el7, which uses file_remove_privs.
$(call define_if_matches, KERNEL_HAS_FILE_REMOVE_SUID, \
-F "int file_remove_suid(struct file *);", fs.h)
$(call define_if_matches, KERNEL_HAS_FILE_REMOVE_PRIVS, \
-F "int file_remove_privs(struct file *);", fs.h)
KERNEL_FEATURE_DETECTION += $(shell \
grep -sFA1 "sock_recvmsg" ${KSRCDIR_PRUNED_HEAD}/include/linux/net.h \
| grep -qsF "size_t size" \
&& echo "-DKERNEL_HAS_RECVMSG_SIZE")
$(call define_if_matches, KERNEL_HAS_MEMDUP_USER, "memdup_user", string.h)
$(call define_if_matches, KERNEL_HAS_FAULTATTR_DNAME, -F "struct dentry *dname", fault-inject.h)
$(call define_if_matches, KERNEL_HAS_SYSTEM_UTSNAME, "system_utsname", utsname.h)
$(call define_if_matches, KERNEL_HAS_SOCK_CREATE_KERN_NS, "sock_create_kern.struct net", net.h)
$(call define_if_matches, KERNEL_HAS_SOCK_SENDMSG_NOLEN, "sock_sendmsg.*msg.;", net.h)
$(call define_if_matches, KERNEL_HAS_IOV_ITER_INIT_DIR, "iov_iter_init.*direction", uio.h)
$(call define_if_matches, KERNEL_HAS_ITER_KVEC, "ITER_KVEC", uio.h)
$(call define_if_matches, KERNEL_HAS_IOV_ITER_TYPE, "iov_iter_type", uio.h)
$(call define_if_matches, KERNEL_HAS_ITER_BVEC, "ITER_BVEC", uio.h)
$(call define_if_matches, KERNEL_HAS_ITER_PIPE, "ITER_PIPE", uio.h)
$(call define_if_matches, KERNEL_HAS_IOV_ITER_IS_PIPE, "iov_iter_is_pipe", uio.h)
$(call define_if_matches, KERNEL_HAS_ITER_IS_IOVEC, "iter_is_iovec", uio.h)
$(call define_if_matches, KERNEL_HAS_IOV_ITER_IOVEC, "iov_iter_iovec", uio.h)
# iov_iter_iovec removed from 6.4 kernel and used iter_iov_addr & iter_iov_len macro's
$(call define_if_matches, KERNEL_HAS_ITER_IOV_ADDR, "iter_iov_addr", uio.h)
$(call define_if_matches, KERNEL_HAS_GET_SB_NODEV, "get_sb_nodev", fs.h)
$(call define_if_matches, KERNEL_HAS_GENERIC_FILE_LLSEEK_UNLOCKED, "generic_file_llseek_unlocked", \
fs.h)
$(call define_if_matches, KERNEL_HAS_SET_NLINK, "set_nlink", fs.h)
$(call define_if_matches, KERNEL_HAS_DENTRY_PATH_RAW, "dentry_path_raw", dcache.h)
$(call define_if_matches, KERNEL_HAS_FSYNC_DENTRY, -P "(\*fsync).*dentry", fs.h)
$(call define_if_matches, KERNEL_HAS_ITER_FILE_SPLICE_WRITE, "iter_file_splice_write", fs.h)
$(call define_if_matches, KERNEL_HAS_ITER_GENERIC_FILE_SENDFILE, "generic_file_sendfile", fs.h)
$(call define_if_matches, KERNEL_HAS_ITERATE_DIR, "iterate_dir", fs.h)
$(call define_if_matches, KERNEL_HAS_ENCODE_FH_INODE, -P "\(\*encode_fh\).struct inode", exportfs.h)
$(call define_if_matches, KERNEL_HAS_D_DELETE_CONST_ARG, \
-F "int (*d_delete)(const struct dentry *);", dcache.h)
$(call define_if_matches, KERNEL_HAS_FILE_F_VFSMNT, -P "struct vfsmount\s*\*f_vfsmnt", fs.h)
$(call define_if_matches, KERNEL_HAS_POSIX_ACL_XATTR_USERNS_ARG, \
-P "posix_acl_from_xattr.struct user_namespace", posix_acl_xattr.h)
$(call define_if_matches, KERNEL_HAS_D_MAKE_ROOT, d_make_root, dcache.h)
$(call define_if_matches, KERNEL_HAS_GENERIC_WRITE_CHECKS_ITER, \
-P "generic_write_checks.*iov_iter", fs.h)
$(call define_if_matches, KERNEL_HAS_INVALIDATEPAGE_RANGE, \
-P "void \(\*invalidatepage\) \(struct page \*. unsigned int. unsigned int\);", fs.h)
$(call define_if_matches, KERNEL_HAS_PERMISSION_2, \
-P "int \(\*permission\) \(struct inode \*. int\);", fs.h)
$(call define_if_matches, KERNEL_HAS_PERMISSION_FLAGS, \
-P "int \(\*permission\) \(struct inode \*. int. unsigned int\);", fs.h)
KERNEL_FEATURE_DETECTION += $(shell \
grep -sFA5 "kmem_cache_create" ${KSRCDIR_PRUNED_HEAD}/include/linux/slab.h \
| grep -qsF "void (*)(void *, struct kmem_cache *, unsigned long)" \
&& echo "-DKERNEL_HAS_KMEMCACHE_CACHE_FLAGS_CTOR")
KERNEL_FEATURE_DETECTION += $(shell \
grep -sFA5 "kmem_cache_create" ${KSRCDIR_PRUNED_HEAD}/include/linux/slab.h \
| grep -qsF "void (*)(struct kmem_cache *, void *)" \
&& echo "-DKERNEL_HAS_KMEMCACHE_CACHE_CTOR")
KERNEL_FEATURE_DETECTION += $(shell \
grep -sFA5 "kmem_cache_create" ${KSRCDIR_PRUNED_HEAD}/include/linux/slab.h \
| grep -qsxP "\s+void \(\*\)\(.*?\)," \
&& echo "-DKERNEL_HAS_KMEMCACHE_DTOR")
$(call define_if_matches, KERNEL_HAS_SB_BDI, -F "struct backing_dev_info *s_bdi", fs.h)
$(call define_if_matches, KERNEL_HAS_BDI_SETUP_AND_REGISTER, "bdi_setup_and_register", \
backing-dev.h)
$(call define_if_matches, KERNEL_HAS_FOLLOW_LINK_COOKIE, \
-P "const char \* \(\*follow_link\) \(struct dentry \*. void \*\*\);", fs.h)
$(call define_if_matches, KERNEL_HAS_FSYNC_2, \
-F "int (*fsync) (struct file *, int datasync);", fs.h)
KERNEL_FEATURE_DETECTION += $(shell \
grep -sFA20 "struct address_space {" ${KSRCDIR_PRUNED_HEAD}/include/linux/fs.h \
| grep -qsP "struct backing_dev_info *backing_dev_info;" \
&& echo "-DKERNEL_HAS_ADDRESS_SPACE_BDI")
$(call define_if_matches, KERNEL_HAS_COPY_FROM_ITER, "copy_from_iter", uio.h)
$(call define_if_matches, KERNEL_HAS_ALLOC_WORKQUEUE, "alloc_workqueue", workqueue.h)
$(call define_if_matches, KERNEL_HAS_WQ_RESCUER, "WQ_RESCUER", workqueue.h)
$(call define_if_matches, KERNEL_HAS_WAIT_QUEUE_ENTRY_T, "wait_queue_entry_t", wait.h)
$(call define_if_matches, KERNEL_HAS_CURRENT_FS_TIME, "current_fs_time", fs.h)
$(call define_if_matches, KERNEL_HAS_64BIT_TIMESTAMPS, "struct timespec64 ia_atime;", fs.h)
$(call define_if_matches, KERNEL_HAS_SB_NODIRATIME, "SB_NODIRATIME", fs.h)
$(call define_if_matches, KERNEL_HAS_GENERIC_GETXATTR, "generic_getxattr", xattr.h)
KERNEL_FEATURE_DETECTION += $(shell \
grep -sA1 "(*rename) " $(KSRCDIR_PRUNED_HEAD)/include/linux/fs.h \
| grep -qsF "unsigned int" \
&& echo "-DKERNEL_HAS_RENAME_FLAGS")
KERNEL_FEATURE_DETECTION += $(shell \
grep -qsF "static inline ino_t parent_ino" $(KSRCDIR_PRUNED_HEAD)/include/linux/fs.h \
&& echo "-DKERNEL_HAS_PARENT_INO")
KERNEL_FEATURE_DETECTION += $(shell \
grep -qsF "define SLAB_MEM_SPREAD" $(KSRCDIR_PRUNED_HEAD)/include/linux/slab.h \
&& echo "-DKERNEL_HAS_SLAB_MEM_SPREAD")
$(call define_if_matches, KERNEL_ACCESS_OK_WANTS_TYPE, "define access_ok(type, addr, size)" \
$(KSRCDIR_PRUNED_HEAD)/include/asm-generic/uaccess.h)
$(call define_if_matches, KERNEL_SPIN_RELEASE_HAS_3_ARGUMENTS, "\#define spin_release(l, n, i)", lockdep.h)
$(call define_if_matches, KERNEL_HAS_NEW_PDE_DATA, "pde_data", proc_fs.h)
# From linux-5.18, .readpages, .invalidatepage, .set_page_dirty, .launder_page
# are replaced by.readahead, .invalidate_folio, .dirty_folio, launder_folio
#$(call define_if_matches, KERNEL_HAS_READAHEAD, -F "void (*readahead)", fs.h)
$(call define_if_matches, KERNEL_HAS_FOLIO, -F "bool (*dirty_folio)", fs.h)
$(call define_if_matches, KERNEL_HAS_READ_FOLIO, -F "int (*read_folio)", fs.h)
KERNEL_FEATURE_DETECTION += $(shell \
grep -sFA1 "int (*writepage_t)" ${KSRCDIR_PRUNED_HEAD}/include/linux/writeback.h \
| grep -qsF "struct folio *" \
&& echo "-DKERNEL_WRITEPAGE_HAS_FOLIO")
KERNEL_FEATURE_DETECTION += $(shell \
grep -sFA1 "int (*write_begin)" ${KSRCDIR_PRUNED_HEAD}/include/linux/fs.h \
| grep -qsF "unsigned flags" \
&& echo "-DKERNEL_WRITE_BEGIN_HAS_FLAGS")
# Matching: int posix_acl_chmod(struct user_namespace *, struct dentry *, umode_t)
KERNEL_FEATURE_DETECTION += $(shell \
grep -sF "int posix_acl_chmod" ${KSRCDIR_PRUNED_HEAD}/include/linux/posix_acl.h \
| grep -qs "struct user_namespace\s*.*struct dentry" \
&& echo "-DKERNEL_HAS_POSIX_ACL_CHMOD_NS_DENTRY")
# linux-6.0 has iov_iter_get_pages2
$(call define_if_matches, KERNEL_HAS_IOV_ITER_GET_PAGES2, "iov_iter_get_pages2", uio.h)
$(call define_if_matches, KERNEL_HAS_GET_RANDOM_INT, "get_random_int", random.h)
# Detect if write_begin() uses struct folio**
KERNEL_FEATURE_DETECTION += $(shell \
grep -sFA2 "int (*write_begin)" ${KSRCDIR_PRUNED_HEAD}/include/linux/fs.h \
| grep -qs "struct folio **" \
&& echo "-DKERNEL_WRITE_BEGIN_USES_FOLIO")

View File

@@ -0,0 +1,309 @@
# This is the BeeGFS client makefile.
# It creates the client kernel module (beegfs.ko).
#
# Use "make help" to find out about configuration options.
#
# Note: This is the Makefile for internal use, there is a separate Release.mk
# file for release packages (to handle the closed source tree properly).
TARGET ?= beegfs
export TARGET
export OFED_INCLUDE_PATH
export BEEGFS_NO_RDMA
BEEGFS_DKMS_BUILD=0
ifdef KERNELRELEASE
BEEGFS_DKMS_BUILD=1
endif
ifeq ($(BEEGFS_DKMS_BUILD),1)
-include /etc/beegfs/beegfs-client-build.mk
endif
-include Version.mk
ifeq ($(obj),)
BEEGFS_BUILDDIR := $(shell pwd)
else
BEEGFS_BUILDDIR := $(obj)
endif
ifeq ($(KRELEASE),)
KRELEASE := $(shell uname -r)
endif
ifneq ($(BEEGFS_NO_RDMA),)
BEEGFS_CFLAGS += -DBEEGFS_NO_RDMA
else
$(info $$OFED_INCLUDE_PATH = [${OFED_INCLUDE_PATH}])
ifneq ($(OFED_INCLUDE_PATH),)
BEEGFS_CFLAGS += -I$(OFED_INCLUDE_PATH)
export KBUILD_EXTRA_SYMBOLS += $(OFED_INCLUDE_PATH)/../Module.symvers
endif
endif
# The following section deals with the auto-detection of the kernel
# build directory (KDIR)
# Guess KDIR based on running kernel.
# - "/usr/src/linux-headers-*" for Ubuntu
# - "/usr/src/kernels/*" for RHEL
# - "/lib/modules/*/build" for Debian, SLES
ifeq ($(KDIR),)
override KDIR = \
/lib/modules/$(KRELEASE)/build \
/lib/modules/default/build \
/usr/src/linux-headers-$(KRELEASE) \
/usr/src/linux-headers-default \
/usr/src/kernels/$(KRELEASE) \
/usr/src/kernels/default
endif
# Prune the KDIR list down to paths that exist and have an
# /include/linux/version.h file
# Note: linux-3.7 moved version.h to generated/uapi/linux/version.h
test_dir = $(shell [ -e $(dir)/include/linux/version.h -o \
-e $(dir)/include/generated/uapi/linux/version.h ] && echo $(dir) )
KDIR_PRUNED := $(foreach dir, $(KDIR), $(test_dir) )
# We use the first valid entry of the pruned KDIR list
KDIR_PRUNED_HEAD := $(firstword $(KDIR_PRUNED) )
# The following section deals with the auto-detection of the kernel
# source path (KSRCDIR) which is required e.g. for KERNEL_FEATURE_DETECTION.
# Guess KSRCDIR based on KDIR
# (This is usually KDIR or KDIR/../source, so you can specify multiple
# directories here as a space-separated list)
ifeq ($(KSRCDIR),)
# Note: "KSRCDIR += $(KDIR)/../source" is not working here
# because of the symlink ".../build"), so we do it with substring
# replacement
KSRCDIR := $(subst /build,/source, $(KDIR_PRUNED_HEAD) )
KSRCDIR += $(KDIR)
endif
# Prune the KSRCDIR list down to paths that exist and contain an
# include/linux/fs.h file
test_dir = $(shell [ -e $(dir)/include/linux/fs.h ] && echo $(dir) )
KSRCDIR_PRUNED := $(foreach dir, $(KSRCDIR), $(test_dir) )
# We use the first valid entry of the pruned KSRCDIR list
KSRCDIR_PRUNED_HEAD := $(firstword $(KSRCDIR_PRUNED) )
ifeq ($(BEEGFS_NO_RDMA),)
# OFED
ifneq ($(OFED_INCLUDE_PATH),)
BEEGFS_CFLAGS += -I$(OFED_INCLUDE_PATH)
module: $(OFED_INCLUDE_PATH)/rdma/rdma_cm.h
$(OFED_INCLUDE_PATH)/rdma/rdma_cm.h:
$(error OFED_INCLUDE_PATH not valid: $(OFED_INCLUDE_PATH))
endif
endif
# Include kernel feature auto-detectors
include KernelFeatureDetection.mk
KMOD_INST_DIR ?= $(DESTDIR)/lib/modules/$(KRELEASE)/updates/fs/beegfs
# Prepare CFLAGS:
# (Note: "-Wsign-compare" included in "-Wextra", but must be explicit here,
# because kernel Makefile adds "-Wno-sign-compare" by default. But we can't
# make it permanent here, because it generates a lot of warnings from kernel
# includes.)
BEEGFS_CFLAGS := $(BUILD_ARCH) $(KERNEL_FEATURE_DETECTION) \
-I$(BEEGFS_BUILDDIR)/../source \
-I$(BEEGFS_BUILDDIR)/../include \
-Wextra -Wno-sign-compare -Wno-empty-body -Wno-unused-parameter -Wno-missing-field-initializers \
-DBEEGFS_MODULE_NAME_STR='\"$(TARGET)\"'
# Update 2022-12: BeeGFS module source code had already switched to -std=gnu99,
# but now the kernel has caught up with us - kernel moved from gnu89 to
# gnu11.
# So we're switching from gnu99 to gnu11, to not break the build with the newer
# kernels. We still need to specify this flag because that would break the
# client module build with older kernels, where gnu89 is the default.
BEEGFS_CFLAGS += -std=gnu11
ifeq ($(shell echo | gcc -Wtype-limits -E - >/dev/null 2>&1 && echo 1),1)
BEEGFS_CFLAGS += -Wno-type-limits
endif
# -O0 would be better, but is not allowed by kernel includes (will not work)
BEEGFS_CFLAGS_DEBUG := -O1 -ggdb3 -rdynamic -fno-inline -DBEEGFS_DEBUG \
-DLOG_DEBUG_MESSAGES -DDEBUG_REFCOUNT -DBEEGFS_LOG_CONN_ERRORS
BEEGFS_CFLAGS_RELEASE := -Wuninitialized
ifeq ($(BEEGFS_DEBUG),)
BEEGFS_CFLAGS += $(BEEGFS_CFLAGS_RELEASE)
else
BEEGFS_CFLAGS += $(BEEGFS_CFLAGS_DEBUG)
endif
ifeq ($(BEEGFS_NO_RDMA),)
# NVFS
ifneq ($(NVFS_INCLUDE_PATH),)
$(NVFS_INCLUDE_PATH)/nvfs-dma.h:
$(error NVFS_INCLUDE_PATH missing nvfs-dma.h: $(NVFS_INCLUDE_PATH))
$(NVFS_INCLUDE_PATH)/config-host.h:
$(error NVFS_INCLUDE_PATH missing config-host.h: $(NVFS_INCLUDE_PATH))
$(NVIDIA_INCLUDE_PATH)/nv-p2p.h:
$(error NVIDIA_INCLUDE_PATH missing nv-p2p.h: $(NVIDIA_INCLUDE_PATH))
module: $(NVFS_INCLUDE_PATH)/nvfs-dma.h $(NVFS_INCLUDE_PATH)/config-host.h \
$(NVIDIA_INCLUDE_PATH)/nv-p2p.h
BEEGFS_CFLAGS += -DBEEGFS_NVFS
BEEGFS_CFLAGS += -I$(NVFS_INCLUDE_PATH) -I$(NVIDIA_INCLUDE_PATH)
endif
endif
# if path to strip command was not given, use default
# (alternative strip is important when cross-compiling)
ifeq ($(STRIP),)
STRIP=strip
endif
BEEGFS_CFLAGS += '-DBEEGFS_VERSION=\"$(BEEGFS_VERSION)\"'
# Prepare RELEASE_PATH extension
ifneq ($(RELEASE_PATH),)
RELEASE_PATH_CLIENT := $(RELEASE_PATH)/client_module_$(shell echo '$(BEEGFS_VERSION)' | cut -d. -f1)
endif
all: module
@ /bin/true
module: $(TARGET_ALL_DEPS)
ifeq ($(KDIR_PRUNED_HEAD),)
$(error Linux kernel build directory not found. Please check if\
the kernel module development packages are installed for the current kernel\
version. (RHEL: kernel-devel; SLES: kernel-default-devel; Debian: linux-headers))
endif
ifeq ($(KSRCDIR_PRUNED_HEAD),)
$(error Linux kernel source directory not found. Please check if\
the kernel module development packages are installed for the current kernel\
version. (RHEL: kernel-devel; SLES: kernel-default-devel; Debian: linux-headers))
endif
@echo "Building beegfs client module"
$(MAKE) -C $(KDIR_PRUNED_HEAD) "M=$(BEEGFS_BUILDDIR)/../source" \
"EXTRA_CFLAGS=$(BEEGFS_CFLAGS) $(EXTRA_CFLAGS)" modules
@cp ../source/$(TARGET).ko .
@ cp ${TARGET}.ko ${TARGET}-unstripped.ko
@ ${STRIP} --strip-debug ${TARGET}.ko;
coccicheck:
$(MAKE) -C $(KDIR_PRUNED_HEAD) "M=$(BEEGFS_BUILDDIR)" coccicheck MODE=report \
M=$(BEEGFS_BUILDDIR)/../source KBUILD_EXTMOD="$(BEEGFS_BUILDDIR)/../source"
include AutoRebuild.mk # adds auto_rebuild targets
prepare_release:
ifeq ($(RELEASE_PATH),)
$(error RELEASE_PATH not defined)
endif
@ echo "Creating release directory:" $(RELEASE_PATH_CLIENT)
mkdir --parents $(RELEASE_PATH_CLIENT)/build \
$(RELEASE_PATH_CLIENT)/source \
$(RELEASE_PATH_CLIENT)/include
@ echo "Storing beegfs version:" $(BEEGFS_VERSION)
echo "BEEGFS_VERSION =" $(BEEGFS_VERSION) > $(RELEASE_PATH_CLIENT)/build/Version.mk
@ echo "Copying beegfs client release files to" $(RELEASE_PATH_CLIENT) "..."
cp Makefile $(RELEASE_PATH_CLIENT)/build/Makefile
cp KernelFeatureDetection.mk $(RELEASE_PATH_CLIENT)/build/
cp AutoRebuild.mk $(RELEASE_PATH_CLIENT)/build/
cp feature-detect.sh $(RELEASE_PATH_CLIENT)/build/
cp ../source/Makefile $(RELEASE_PATH_CLIENT)/source/
find ../source -mount -name '*.h' -type f | \
xargs -I {} cp --parents {} $(RELEASE_PATH_CLIENT)/build
find ../source -mount -name '*.c' -type f | \
xargs -I {} cp --parents {} $(RELEASE_PATH_CLIENT)/build
find ../include -mount -name '*.h' -type f | \
xargs -I {} cp --parents {} $(RELEASE_PATH_CLIENT)/build
# When used for development where the full BeeGFS source is available, this install target handles
# ensuring the mount.beegfs script is installed. If the mount.script is not present in the source,
# for example if the install target was invoked via the BeeGFS client service and AutoRebuild.mk, it
# just checks the script already exists at /sbin/mount.beegfs since the script should have been
# installed by the package manager. If it does not exist an error is returned as this is likely a
# bug elsewhere related to installing the script, or somebody is trying to use this Makefile in an
# unsupported/unexpected manner and further investigation is required.
install:
install -D -m 644 $(TARGET).ko $(KMOD_INST_DIR)/$(TARGET).ko
@if [ -f dist/sbin/mount.beegfs ]; then \
install -D -m 755 dist/sbin/mount.beegfs /sbin/mount.beegfs; \
echo "Info: Installed mount script at /sbin/mount.beegfs."; \
elif [ ! -f /sbin/mount.beegfs ]; then \
echo "Error: mount.beegfs does not already exist at /sbin/mount.beegfs (this is likely a bug elsewhere)."; \
exit 1; \
fi
depmod -a $(KRELEASE)
clean:
rm -f *~ .${TARGET}??*
rm -f .*.cmd *.mod.c *.mod.o *.o *.ko *.ko.unsigned
rm -f ../source/Module*.symvers ../source/modules.order ../source/Module.markers
rm -f Module*.symvers modules.order Module.markers
rm -f $(AUTO_REBUILD_KVER_FILE)
rm -rf .tmp_versions/
find ../source/ -mount -name '*.o' -type f -delete
find ../source/ -mount -name '.*.o.cmd' -type f -delete
find ../source/ -mount -name '.*.o.d' -type f -delete
find ../source/ -mount -name '*.gcno' -type f -delete
help:
@echo "This makefile creates the kernel module: $(TARGET) (beegfs-client)"
@echo ' '
@echo 'client Arguments (required):'
@echo ' RELEASE_PATH=<path> (Target: prepare_release)'
@echo ' The path to the client release directory.'
@echo ' '
@echo 'client Arguments (optional):'
@echo ' KRELEASE=<release>: Kernel release'
@echo ' (The output of "uname -r" will be used if undefined.'
@echo ' This option is useful when building for a kernel different'
@echo ' from the one currently running (e.g. in a chroot).)'
@echo ' KDIR=<path>: Kernel build directory.'
@echo ' (Will be guessed based on running kernel or KRELEASE if undefined.)'
@echo ' KSRCDIR=<path>: Kernel source directory containing the kernel include '
@echo ' directory. (Will be guessed based on KDIR if undefined.)'
@echo ' BEEGFS_DEBUG=1:'
@echo ' Enables file sytem debug log messages etc.'
@echo ' TARGET=<MODULE_NAME>'
@echo ' Set a different module and file system name.'
@echo ' '
@echo 'Infiniband (RDMA) arguments (optional):'
@echo ' OFED_INCLUDE_PATH=<path>:'
@echo ' Path to OpenFabrics Enterpise Distribution kernel include directory, e.g.'
@echo ' "/usr/src/openib/include". (If not defined, the standard kernel headers'
@echo ' will be used.)'
@echo ''
@echo 'NVIDIA GPUDirect Storage (GDS) arguments (optional):'
@echo ' NVFS_INCLUDE_PATH=<path>:'
@echo ' Path to directory that contains nvfs-dma.h. If not defined, GDS support is'
@echo ' disabled.'
@echo ' NVIDIA_INCLUDE_PATH=<path>:'
@echo ' Path to NVIDIA driver source. Required when NVFS_INCLUDE_PATH is specifed.'
@echo ''
@echo 'Targets:'
@echo ' all (default) - build only'
@echo ' install - install the kernel modules'
@echo ' clean - delete previously compiled files'
@echo ' prepare_release - build and copy files into the RELEASE_PATH directory'

View File

@@ -0,0 +1,92 @@
# This is a config file for the automatic build process of BeeGFS client kernel
# modules.
# http://www.beegfs.com
#
# --- Section: [Notes] ---
#
# General Notes
# =============
# To force a rebuild of the client modules:
# $ /etc/init.d/beegfs-client rebuild
#
# To see a list of available build arguments:
# $ make help -C /opt/beegfs/src/client/client_module_${BEEGFS_MAJOR_VERSION}/build
#
# Help example for BeeGFS 2015.03 release:
# $ make help -C /opt/beegfs/src/client/client_module_2015.03/build
# RDMA Support Notes
# ==================
# If you installed InfiniBand kernel modules from OpenFabrics OFED, then also
# define the correspsonding header include path by adding
# "OFED_INCLUDE_PATH=<path>" to the "buildArgs", where <path> usually is
# "/usr/src/openib/include" or "/usr/src/ofa_kernel/default/include" for
# Mellanox OFED.
#
# OFED headers are automatically detected even if OFED_INCLUDE_PATH is not
# defined. To build the client without RDMA support, define BEEGFS_NO_RDMA=1.
#
# NVIDIA GPUDirect Storage Support Notes
# ==================
# If you want to build BeeGFS with NVIDIA GPUDirect Storage support, add
# "NVFS_INCLUDE_PATH=<path>" to the "buildArgs" below, where path is the directory
# that contains nvfs-dma.h. This is usually the nvidia-fs source directory:
# /usr/src/nvidia-fs-VERSION.
#
# If config-host.h is not present in NVFS_INCLUDE_PATH, execute the configure
# script. Example:
# $ cd /usr/src/nvidia-fs-2.13.5
# $ ./configure
#
# NVIDIA_INCLUDE_PATH must be defined and point to the NVIDIA driver source:
# /usr/src/nvidia-VERSION/nvidia
#
# OFED_INCLUDE_PATH must be defined and point to Mellanox OFED.
#
#
# --- Section: [Build Settings] ---
#
# Build Settings
# ==============
# These are the arguments for the client module "make" command.
#
# Note: Quotation marks and equal signs can be used without escape characters
# here.
#
# Example1:
# buildArgs=-j8
#
# Example2 (see "RDMA Support Notes" above):
# buildArgs=-j8 OFED_INCLUDE_PATH=/usr/src/openib/include
#
# Example3 (see "NVIDIA GPUDirect Storage Support Notes" above):
# buildArgs=-j8 OFED_INCLUDE_PATH=/usr/src/ofa_kernel/default/include \
# NVFS_INCLUDE_PATH=/usr/src/nvidia-fs-2.13.5 \
# NVIDIA_INCLUDE_PATH=/usr/src/nvidia-520.61.05/nvidia
#
# Default:
# buildArgs=-j8
buildArgs=-j8
# Turn Autobuild on/off
# =====================
# Controls whether modules will be built on "/etc/init.d/beegfs-client start".
#
# Note that even if autobuild is enabled here, the modules will only be built
# if no beegfs kernel module for the current kernel version exists in
# "/lib/modules/<kernel_version>/updates/".
#
# Default:
# buildEnabled=true
buildEnabled=true

View File

@@ -0,0 +1,19 @@
# BeeGFS client module DKMS build configuration
# This file is only used when building via DKMS.
# The module needs to be rebuilt after this file has been changed.
# If using thirdparty OFED specify the path to the installation here.
# Examples:
#OFED_INCLUDE_PATH=/usr/src/ofa_kernel/default/include
#OFED_INCLUDE_PATH=/usr/src/openib/include
# To disable RDMA support, define BEEGFS_NO_RDMA
#BEEGFS_NO_RDMA=1
# If building nvidia-fs support, specify path to nvfs-dma.h.
# This directory must also have config-host.h, which is created
# by the nvidia-fs configure script.
# Example:
#NVFS_INCLUDE_PATH=/usr/src/nvidia-fs-2.13.5
# If building nvidia-fs support, specify path to NVIDIA driver
# source.
# Example:
#NVIDIA_INCLUDE_PATH=/usr/src/nvidia-520.61.05/nvidia

View File

@@ -0,0 +1,37 @@
#!/bin/bash -e
# BeeGFS client mount hook script
action="${1}"
mountpoint="${2}"
# THIS IS AN EXAMPLE SCRIPT.
# Copy and modify it, and remove the following line:
exit 1
if [ ! -d "${mountpoint}" ]
then
echo "${0}: Mount point does not exist: ${mountpoint}"
exit 1
fi
case "${action}" in
pre-mount)
;;
post-mount)
mount -o bind "${mountpoint}/foo" "${mountpoint}/bar"
;;
pre-unmount)
umount "${mountpoint}/bar"
;;
post-unmount)
;;
*)
echo "${0}: Unrecognized option supplied to client mount hook: ${action}"
exit 1
;;
esac

View File

@@ -0,0 +1,755 @@
# This is a config file for BeeGFS clients.
# http://www.beegfs.com
# --- [Table of Contents] ---
#
# 1) Settings
# 2) Mount Options
# 3) Basic Settings Documentation
# 4) Advanced Settings Documentation
#
# --- Section 1.1: [Basic Settings] ---
#
sysMgmtdHost =
#
# --- Section 1.2: [Advanced Settings] ---
#
connAuthFile = /etc/beegfs/conn.auth
connDisableAuthentication = false
connClientPort = 8004
connMgmtdPort = 8008
connPortShift = 0
connCommRetrySecs = 600
connFallbackExpirationSecs = 900
connInterfacesFile =
connRDMAInterfacesFile =
connMaxInternodeNum = 12
connMaxConcurrentAttempts = 0
connNetFilterFile =
connUseRDMA = true
connTCPFallbackEnabled = true
connTCPRcvBufSize = 0
connUDPRcvBufSize = 0
connRDMABufNum = 70
connRDMABufSize = 8192
connRDMAFragmentSize = page
connRDMATypeOfService = 0
connTcpOnlyFilterFile =
logClientID = false
logLevel = 3
quotaEnabled = false
sysCacheInvalidationVersion = true
sysCreateHardlinksAsSymlinks = false
sysMountSanityCheckMS = 11000
sysSessionCheckOnClose = false
sysSyncOnClose = false
sysTargetOfflineTimeoutSecs = 900
sysUpdateTargetStatesSecs = 30
sysXAttrsEnabled = false
tuneFileCacheType = buffered
tunePreferredMetaFile =
tunePreferredStorageFile =
tuneRemoteFSync = true
tuneUseGlobalAppendLocks = false
tuneUseGlobalFileLocks = false
#
# --- Section 1.3: [Enterprise Features] ---
#
# See end-user license agreement for definition and usage limitations of
# enterprise features.
#
sysACLsEnabled = false
#
# --- Section 2: [Mount Options] ---
#
# Valid mount options are:
# cfgFile, logLevel, connPortShift, connMgmtdPort,
# sysMgmtdHost, sysMountSanityCheckMS, connInterfacesList.
#
# Use the mount option "cfgFile" to specify a different config file
# for the beegfs client.
# Example:
# $ /bin/mount -t beegfs beegfs_nodev /beegfs -ocfgFile=/etc/anotherconfig.conf
#
# Use the mount option "connInterfacesList" to pass the list of interfaces names.
# These interfaces names should be space-separated.
# Example:
# $ /bin/mount -t beegfs beegfs_nodev /beegfs \
# -ocfgFile=/etc/anotherconfig.conf,connInterfacesList='ib0 eth0'
#
# Mount options override the corresponding config file values.
# Example:
# $ /bin/mount -ocfgFile=/etc/anotherconfig.conf,logLevel=3 ...
#
# --- Section 3: [Basic Settings Documentation] ---
#
# [sysMgmtdHost]
# Hostname (or IP) of the host running the management service.
# (See also "connMgmtdPort".)
# Default: <none>
#
# --- Section 4: [Advanced Settings Documentation] ---
#
#
# --- Section 4.1: [Connections & Communication] ---
#
# [connAuthFile]
# The path to a file that contains a shared secret for connection based
# authentication. Only peers that use the same shared secret will be able to
# connect.
# Default: <none>
# [connDisableAuthentication]
# If set to true, explicitly disables connection authentication and allow the
# service to run without a connAuthFile. Running BeeGFS without connection
# authentication is considered insecure and is not recommended.
# Default: false
# [connClientPort]
# The UDP port of the client.
# Default: 8004
# [connMgmtdPort]
# The UDP and TCP port of the management node.
# Default: 8008
# [connPortShift]
# Shifts all following UDP and TCP ports according to the specified value.
# Intended to make port configuration easier in case you do not want to
# configure each port individually.
# Default: 0
# [connCommRetrySecs]
# The time (in seconds) for retries in case a network communication fails
# (e.g. if a server is down). After this time, the I/O operation will fail
# and the calling process will receive an error.
# Note: Set this value to 0 for infinite retries. In this case, a process
# accessing the file system will block until the corresponding server
# becomes available (or until it is interrupted by a signal).
# Default: 600
# [connFallbackExpirationSecs]
# The time in seconds after which a connection to a fallback interface expires.
# When a fallback connection expires, the system will try to establish a new
# connection to the other hosts primary interface (falling back to another
# interface again if necessary).
# Note: The priority of node interfaces can be configured using the
# "connInterfacesFile" parameter.
# Default: 900
# [connInterfacesFile]
# The path to a text file that specifies the names of the interfaces, which
# may be used for communication by other nodes. One interface per line. The
# line number also defines the priority of an interface.
# Example: "ib0" in the first line, "eth0" in the second line.
# Values: This setting is optional. If unspecified, all available interfaces
# will be published and priorities will be assigned automatically.
# Note: This has no influence on outgoing connections. The information is sent
# to other hosts to inform them about possible communication paths.
# Default: <none>
# [connInterfacesList]
# Comma-separated list of interface names. Performs the same function as
# connInterfacesFile.
# If use as the mount option "connInterfacesList" to pass the list of interfaces
# names then it override the corresponding config file/list values..
# The interfaces names should be space-separated.
# Example:
# $ /bin/mount -t beegfs beegfs_nodev /beegfs \
# -ocfgFile=/etc/anotherconfig.conf,connInterfacesList='ib0 eth0'
#
# Default: <none>
# [connRDMAInterfacesFile]
# The path to a text file that specifies the names of IPoIB interfaces, which
# may be used for outbound RDMA communication with other nodes. One interface
# per line. These interfaces must be RDMA-capable NICs.
#
# All storage and metadata servers must be IP-reachable from each specified
# interface.
#
# Specifying interfaces in this file limits which RDMA NICs are used for outbound
# RDMA. Specifying multiple interfaces allows the client to use multiple RDMA
# interfaces for outbound communication.
#
# Example: "ib0" in the first line, "ib1" in the second line.
# Values: This setting is optional. When none are specified, the client will use
# the first client host interface that can reach the remote node via IPoIB,
# as decided by rdma_cm. When multiple interfaces are specified, the client
# round-robins creation of outbound RDMA connections across the specified
# interfaces.
# Default: <none>
# [connMaxInternodeNum]
# The maximum number of simultaneous connections to the same node.
# Default: 12
# [connMaxConcurrentAttempts]
# The maximum number of simultaneous connection attempts. This may help in case
# establishing new connections keeps failing and produces fallbacks.
# It may happen particularly when using RDMA in an Omni-Path setup. If you
# don't have failing connection attempts, tuning this option might still lead
# to a faster connection process. This option is experimental, so there is no
# experience with different values. Setting it to 0 disables it, which means
# concurrent connection attempts are not limited.
# Default: 0
# [connNetFilterFile]
# The path to a text file that specifies allowed IP subnets, which may be used
# for outgoing communication. One subnet per line in classless notation (IP
# address and number of significant bits).
# Example: "192.168.10.0/24" in the first line, "192.168.20.0/24" in the second
# line.
# This value is optional. If unspecified, all addresses are allowed for
# outgoing communication.
# Default: <none>
# [connUseRDMA]
# Enables the use of Remote Direct Memory Access (RDMA) for InfiniBand or RoCE.
# For this setting to be effective, OFED ibverbs support also has to be enabled
# at compile time of the beegfs client modules (typically via
# beegfs-client-autobuild.conf).
# Default: true
# [connTCPFallbackEnabled]
# Enables fallback from RDMA to TCP sockets when there is a problem connecting
# via RDMA to a storage or meta node.
# Default: true
# [connTCPRcvBufSize], [connUDPRcvBufSize]
# Sets the size for TCP and UDP socket receive buffers (SO_RCVBUF). The maximum
# allowed value is determined by sysctl net.core.rmem_max. This value is ignored
# if it is less than the default value determined by net.core.rmem_default.
# For legacy reasons, the default value 0 indicates that the buffer size is set
# to connRDMABufNum * connRDMABufSize.
# -1 indicates that the buffer size should be left at the system default.
# Default: 0
# [connRDMABufNum], [connRDMABufSize], [connRDMAFragmentSize]
# InfiniBand RDMA buffer settings.
# connRDMABufSize is the maximum size of a buffer (in bytes) that will be sent
# over the network; connRDMABufNum is the number of available buffers that can
# be in flight for a single connection. These client settings are also applied
# on the server side for each connection. Ideally, the largest, commonly used
# filesytem chunksize should be < connRDMABufNum * connRDMABufSize to achieve
# the best performance.
#
# The minimum usable value for connRDMABufNum is 3, which is required by the
# BeeGFS RDMA protocol. Lower values will immediately result in communication
# failures.
#
# connRDMAFragmentSize determines how contiguous memory is allocated per
# buffer. If connRDMAFragmentSize=4096 and connRDMABufSize=8192, each buffer
# is allocated in 2 regions of 4096 contiguous bytes. Less fragmentation
# improves performance. The value "none" indicates that buffers will not be
# fragmented, resulting in allocation of contiguous regions of
# connRDMABufSize. The value "page" uses the Linux PAGE_SIZE as the
# fragmentation value.
# The reason for using fragmentation is that large allocations
# are more likely to fail if there is a shortage of heap memory. The minimum
# fragmentation value is PAGE_SIZE. Using larger values (or 0) should improve
# performance and allows for larger values of connRDMABufSize.
#
# Note: RAM usage per connection is connRDMABufSize x connRDMABufNum x 2. Keep
# resulting RAM usage (x connMaxInternodeNum x number_of_clients) on the
# server in mind when increasing these values.
# Default: 70, 8192, page
# [connRDMAMetaBufNum], [connRDMAMetaBufSize], [connRDMAMetaFragmentSize]
# InfiniBand RDMA buffer settings for connections to beegfs-meta.
# These settings behave in the same way as connRDMABufNum, connRDMABufSize
# and connRDMAFragmentize except that they are used for connections to
# beegfs-meta.
# Metadata messages are usuallly small and do not require the large amount
# of buffer space that is typically configured for connections to
# beegfs-storage. One exception to this would be if large extended attributes
# are added to files.
# connRDMAMetaBufNum = "default" indicates that connRDMABufNum should be used.
# connRDMAMetaBufSize = "default" indicates that connRDMABufSize should be used.
# connRDMAMetaFragmentSize = "default" indicates that connRDMAFragmentSize
# should be used.
# The minimum value for connRDMAMetaBufNum is 3.
# Default: default, default, default
# [connRDMATypeOfService]
# InfiniBand provides the option to set a type of service for an application.
# This type of service can be used by your subnet manager to provide Quality of
# Service functionality (e.g. setting different service levels).
# In openSM the service type will be mapped to the parameter qos-class, which
# can be handled in your QoS configuration.
# See
# www.openfabrics.org/downloads/OFED/ofed-1.4/OFED-1.4-docs/
# QoS_management_in_OpenSM.txt
# for more information on how to configure openSM for QoS.
# This parameter sets the type of service for all outgoing connections of this
# daemon.
# Default: 0 (Max: 255)
# [connRDMAKeyType]
# In RDMA, an "rkey" is used to provide an access token for a peer to access
# local memory regions that are registered for RDMA. Historically,
# BeeGFS used either a "DMA key" or an "unsafe global rkey" depending upon
# whether or not "unsafe global rkey" is supported by the operating system.
# This is now selectable. "DMA key" is not supported on kernel >= 4.9
# unless MOFED is installed. If an unsupported option is specified, there
# will be warnings in syslog and RDMA connections will not be established.
# Use of "unsafe global rkey" is preferred, but generates a syslog message
# every time an RDMA connection is established: "enabling unsafe global rkey".
# Neither option is considered "safe" because they both provide access
# to all DMA mapped memory for a given connection. This technique is
# used to provide better performance for small I/O requests.
# "register" uses a memory registration per connection to provide an rkey.
# "register" is not compatible with NVIDIA GPUDirect Storage.
# Specify "dma" or "register" to squelch the syslog warning.
# Values: "global" (unsafe global rkey), "dma" (DMA key), "register"
# (memory registration)
# Default: "global"
# [connTcpOnlyFilterFile]
# The path to a text file that specifies IP address ranges to which no RDMA
# connection should be established. This is useful e.g. for environments where
# all hosts support RDMA, but some hosts cannot connect via RDMA to some other
# hosts.
# Example: "192.168.10.0/24" in the first line, "192.168.20.0/24" in the second
# line.
# Values: This setting is optional.
# Default: <none>
# [connMessagingTimeouts]
# These constants are used to set some of the connection timeouts for sending
# and receiving data between services in the cluster. They used to be hard-coded
# (CONN_LONG_TIMEOUT, CONN_MEDIUM_TIMEOUT and CONN_SHORT_TIMEOUT) but are now
# made configurable for experimentation purposes.
# This option takes three integer values of milliseconds, separated by a comma
# in the order long, medium, short.
# WARNING: This is an EXPERIMENTAL configuration option that should not be
# changed in production environments unless properly tested and validated.
# Some configurations can lead to service lockups and other subtle issues.
# Please make sure that you know exactly what you are doing and properly
# test any changes you make.
# Default: 600000,90000,30000
# [connRDMATimeouts]
# These constants are used to set some of the timeouts for sending and receiving
# data between services in the cluster via RDMA. They used to be
# hard-coded IBVSOCKET_CONN_TIMEOUT_MS, IBVSOCKET_COMPLETION_TIMEOUT_MS,
# IBVSOCKET_FLOWCONTROL_ONSEND_TIMEOUT_MS,
# IBVSOCKET_FLOWCONTROL_ONRECV_TIMEOUT_MS and a 10000 literal for poll timeout
# but are now made configurable for experimentation purposes.
# This option takes five integer values of milliseconds, separated by a comma
# in the order connectMS, completionMS, flowSendMS, flowRecvMS and pollMS.
# WARNING: This is an EXPERIMENTAL configuration option that should not be
# changed in production environments unless properly tested and validated.
# Some configurations can lead to service lockups and other subtle issues.
# Please make sure that you know exactly what you are doing and properly
# test any changes you make.
# Default: 5000,300000,180000,180000,10000
# --- Section 4.2: [Logging] ---
#
# [logClientID]
# Defines whether the ClientID should appear in each log line.
# This is mainly helpful if BeeGFS is mounted multiple times on this machine.
# Default: false
# [logLevel]
# Defines the amount of log messages. The higher this level, the more detailed
# the log messages will be.
# Level 3 will print connection messages, level 4 will print syscall messages,
# level 5 will print debug messages.
# Note: Levels above 3 might decrease performance.
# Default: 3 (Max: 5)
#
# --- Section 4.3: [Quota Settings] ---
#
# [quotaEnabled]
# Enables user and group quota support by transferring extra user data to the
# servers. This uses quota information of the underlying file systems on the
# storage servers, which needs to be enabled by the server administrator.
# Note: In the first implementation, only quota monitoring is available.
# Note: Get quota information with "beegfs-ctl --getquota".
# Note: If this option is true, performance might be slightly decreased due to
# extra information tracking.
# Default: false
#
# --- Section 4.4: [System Settings] ---
#
# [sysCacheInvalidationVersion]
#
# Enable the client to invalidate its cache and reload the inode of a file when
# the version parameter of the file on metadata changes due to internal metadata
# operations such as stripe pattern change. This is done by comparing the
# version parameters on client and metadata on the first lookup after internal
# metadata changes. If the versions differ, the client invalidates the cache and
# reloads the inode.
# Note: If this option is set to true, performance may be decreased.
# Default: true
# [sysCreateHardlinksAsSymlinks]
# Create a symlink when an application tries to create a hardlink for files in
# different directories.
# Default: false
# [sysMountSanityCheckMS]
# Perform some basic checks during mount (e.g. whether the client helper daemon
# and storage servers are reachable). Mounting will fail if a problem is
# detected.
# Values: Set the time (in ms) you want to spend waiting for the servers
# (especially the management daemon) to respond. Use 0 to disable all checks
# and allow mounting even if no servers are reachable.
# Default: 11000
# [sysSessionCheckOnClose]
# Checks for a valid session on the storage servers when a file is closed. If
# this option is set to true, a potential cache loss from a crash of a storage
# server can be detected. This will be reported to the user application as a
# close() error code.
# Note: There is also a session check included in all read/write/fsync messages,
# which is independent of this setting.
# Note: If this option is set to true, more network messages are required on
# close(), so performance will decreased.
# Default: false
# [sysSessionChecksEnabled]
# Enable session checks in read/write/fsync operations to be able to detect
# server crashes that could have caused a loss of server side caches. Disabling
# these checks is useful in certain system configurations to be able to cleanly
# resume I/O after a server crash/unclean failover.
# WARNING: Disabling session checks can lead to undetected cache loss and
# therefore silent data corruption on the storage servers. Only disable the
# checks if absolutely necessary and if there are measures in place to prevent
# cache loss (synchronous mounts, battery backed caches) on the storage servers.
# Default: true
# [sysSyncOnClose]
# Sync file contents on close. If this option is set to true, the storage
# servers will flush the write cache of a file to disk immediately when it is
# closed by the application. If this option is set to false, the write cache
# will be flushed to disk asynchronously after a few seconds.
# Note: If this option is true, performance will be decreased.
# Default: false
# [sysTargetOfflineTimeoutSecs]
# Timeout until all storage targets and metadata nodes are considered offline
# when no target state updates can be fetched from the management server.
# If this value is 0, targets will never be set to offline due to an
# unreachable management node and will stay in state probably-offline.
# Note: This must be at least twice as large as the value of
# sysTargetOfflineTimoutSecs in the server config files.
# Values: time in seconds
# Default: 900
# [sysUpdateTargetStatesSecs]
# Interval in which the states of the storage targets are checked.
# Note: This must be significantly shorter than the sysTargetOfflineTimeoutSecs
# value set in the server (recommendation: maximum 1/3 of it).
# Values: time in seconds
# Default: 30
# [sysXAttrsEnabled]
# Enable extended attributes (also know as EAs/xattrs).
# Default: false
# [sysXAttrsCheckCapabilities]
# Check inodes for existing "security.capability" extended attribute and
# optionally cache to reduce metadata requests and increase write performance.
# The Linux kernel uses a security mechanism that automatically removes
# setuid/setgid bits and capabilities from files when they are changed. This is
# done to prevent users from executing binaries with elevated privileges that
# were changed after the privileges were originally set. That mechanism requires
# that, by default, the kernel has to check each file for existing capabilities
# on every write which leads to a large overhead in metadata RPCs to fetch the
# "security.capability" extended attribute. To optimize this, Linux allows file
# systems to set a flag (S_NOSEC) on the file, which short-circuits these
# checks.
# This configuration option configures the file system mount to allow the
# client to either always check, check once and cache that flag after a first
# lookup of the extended attribute returns an empty result, or set the flag on
# inode creation and never check. The flag will automatically be cleared when
# capabilities are modified on this client. It will, however, currently not
# be cleared when a different client modifies capabilities or sets setuid/setgid
# bits, which can lead to capabilities not being cleared, even after the file is
# written to. If this is a concern, this option should be set to "always".
# As long as BeeGFS is mounted using the "nosuid" mount option (which is
# recommended and the default setting), elevating privileges via setuid/setgid
# bits and capabilities is disabled and it is safe to set this option to "never".
# Possible values:
# always (always check for security xattr, never cache the result)
# cache (check for security xattr once, then cache)
# never (mark new inodes immediately, never check security xattr)
# Default: never
# [sysBypassFileAccessCheckOnMeta]
# Allow this client to bypass file access restrictions enforced by metadata
# servers. When enabled, the client is permitted to open files even if access
# restrictions are currently in place (e.g., file marked read-only,
# write-locked, or fully restricted). This setting is primarily intended for
# specialized clients in controlled environments, such as HSM (Hierarchical
# Storage Management) systems that need to restore file data, or backup/recovery
# tools that require access to otherwise locked files.
# Note: This setting only affects metadata-level access checks and has no effect
# on other security or permission mechanisms.
# Default: false
# [sysACLsEnabled]
# Allow the creation and enforcement of Access Control Lists (ACLs).
# Note: Only works if sysXAttrsEnabled=true.
# Note: Requires at least Linux kernel version 3.2.
# Note: Enabling this setting can affect metadata performance.
# Default: false
# [sysFileEventLogMask]
# Specifies which file system events shall be logged by the metadata servers. If
# unset, this client doesn't send log events at all. This can either be "none"
# or a comma separated list of event types to log. The following event types
# (and any comma-separated combination) are possible:
# "flush" (explicit data flushes on files), "close" (close writable file),
# "trunc" (file truncation), "setattr" (set attributes),
# "link-op" (create,mkdir,mknod,create symlink,create hardlink,rmdir,unlink, rename),
# "read" (deprecated, see notes) or "open-read" (file opened in read-only mode),
# "open-write" (file opened in write only mode),
# "open-readwrite" (file opened for both read and write),
# Note: If a client opens a file multiple times, "close" will only generate an
# event if the last fd is closed. If events for each fd shall be generated,
# "flush" needs to be used. However, "flush" might have a small performance
# impact. Also note that "read" is deprecated for file opening in read-only mode,
# but it is still allowed for backward compatibility. It is recommended to use
# "open-read" instead of "read" for clarity and consistency.
# Example: sysFileEventLogMask = close,trunc,setattr,link-op,open-read
# Default: none
# [sysRenameEbusyAsXdev]
# Changes the semantics of rename() to return an EXDEV error if a file could not
# be moved because it is in use (instead of the default EBUSY). Applications and
# tools like mv can handle EXDEV and fall back to copy/unlink for the files.
# This is mostly useful for NFS exports, where files may not be closed by the
# server until after the last open file handle has been closed by clients. This
# can cause spurious EBUSY errors in clients that close a file and rename it
# immediately afterwards.
# Default: false
#
# --- Section 4.5: [Tuning] ---
#
# [tuneFileCacheType]
# Sets the file read/write cache type.
# Values: "none" (disable client caching), "buffered" (use a pool of small
# static buffers for write-back and read-ahead), "native" (use the kernel
# pagecache), "paged" (experimental, deprecated).
# Note: The cache protocols are currently non-coherent (but caches are
# automatically flushed when a file is closed).
# Note: When client and servers are running on the same machine, "paged" mode
# contains the typical potential for memory allocation deadlocks (also known
# from local NFS server mounts). So do not use "paged" mode for clients that
# run on a metadata or storage server machine.
# Default: buffered
# [tunePreferredMetaFile], [tunePreferredStorageFile]
# Path to a text file that contains the numeric IDs of preferred storage targets
# and metadata servers. These will be preferred when the client creates new file
# system entries. This is useful e.g. to take advantage of data locality in the
# case of multiple data centers. If unspecified, all available targets and
# servers will be used equally.
# Usage: One targetID per line for storage servers, one nodeID per line for
# metadata servers.
# Note: TargetIDs and nodeIDs can be queried with the beegfs-ctl tool.
# Default: <none>
# [tuneRemoteFSync]
# Controls whether fsync() syscalls from a user application should only be
# executed on the client to transfer data from the client cache to server
# cache (=false); or also on the servers to flush the server's cached file
# data to the disks (=true).
# Default: true
# [tuneUseGlobalAppendLocks]
# Controls whether files opened in append mode should be protected by locks on
# the local machine only (=false) or globally on the servers (=true).
# Default: false
# [tuneUseGlobalFileLocks]
# Controls whether application advisory file locks via flock() and fcntl()
# should be checked for conflicts on the local machine only (=false) or
# globally on the servers (=true).
# Default: false
# [tuneCoherentBuffers]
# Enables or disables coherence between the buffers used by
# tuneFileCacheType=buffered and the page cache.
# If a file is concurrently accessed via mmap() regions and read()/write()
# system calls, the buffers used by tuneFileCacheType=buffered and the page
# cache used by mmap() may go out of sync - changes made in an mmap()ed region
# may not be visible to read() calls immediately, or changes made by write()
# calls may not be immediately reflected in mmap()ed regions.
# Many programs that use both methods of accessing a file assume that
# read()/write() and mmap() present the same view of the file, if this is not
# the case, those programs may not work correctly. Programs that have been
# observed to misbehave with non-coherent buffers are, for example, git and
# some in-memory database applications.
# When this option is enabled, files that are currently mmap()ed will behave as
# though they had been opened with tuneFileCacheType=none
# Default: true
#
# --- Section 5: [Expert options]
#
# [connUnmountRetries]
# Retry communications during unmount.
# If this option is set to `true` and a communication error occurs during
# unmont, for example due to a transient network fault, the unsuccessful
# communications will be retried normally. When set to `false` they will not be
# retried; this leads to a quicker unmount, but resources allocated to current
# client will not be freed for a few hours.
# Default: true
# [tuneFileCacheBufSize]
# When using buffered mode: maximum size of the (contiguous) data cache for an
# open file.
# When using native mode: threshold for direct operations. If a read() or
# write() passes a buffer size larger than tuneFileCacheBufSize the client will
# bypass the page cache and send/receive the data directly to/from the storage
# servers.
# Default: 524288 (512KiB)
# [tuneFileCacheBufNum]
# When using buffered mode: maximum number of file caches to preallocate
# for the mount. When a file is opened a cache is allocated, up to this number.
# If the maximum number of caches is reached no cache is allocated and all
# read/write operations for the file go to the storage servers directly.
# Default: 4*(number of CPUs)
# [tunePageCacheValidityMS]
# Maximum lifetime of cached data in the page cache.
# In buffered mode the page cache is used for mmap(), in native mode the page
# cache is used for all data. Data in the page cache that was not yet written
# to the storage server is written after at most this time, data that was read
# but not modified is discarded.
# Default: 2000000000 (approx. 23 days)
# [tuneDirSubentryCacheValidityMS]
# Validity time of directory attribute data, in milliseconds.
# Attributes of directories (eg stat() data) that have been loaded from the
# metadata servers are assumed to be valid for this amount of time without
# requiring a refresh. Once the time has passed the next access will cause a
# refresh.
# Default: 1000
# [tuneFileSubentryCacheValidityMS]
# Validity time of file attribute data, in milliseconds.
# Attributes of files (eg stat() data) that have been loaded from the metadata
# servers are assumed to be valid for this amount of time without requiring a
# refresh. Once the time has passed the next access will cause a refresh.
# Default: 0
# [tuneENOENTCacheValidityMS]
# Validity time of the non-existing file in milliseconds.
# A negative result of a stat call indicating "No such file or directory"
# (ENOENT) is assumed to be valid for this amount of time without requiring a
# new request to the meta server. Once the time has passed the next access will
# cause a refresh.
# Default: 0
# [tunePathBufSize]
# Size of buffers used for constructing paths.
# Whenever a full path must be constructed (eg for log messages) a preallocated
# buffer of this size will be used.
# Default: 4096
# [tunePathBufNum]
# Number of path buffers for path construction.
# Determines how many path buffers are preallocated during mount. If no buffers
# are available for an operation the operation must wait for another thread to
# free enough buffers.
# Default: 8
# [tuneMsgBufSize]
# Size of buffers used for messaging.
# Messages sent and received by the client (except logging messages) use
# buffers preallocated at mount time. Buffers are allocated with the size
# given here.
# Default: 65536
# [tuneMsgBufNum]
# Number of message buffers.
# During mount this many message buffers are preallocated. If an operation
# requires communication with a server but all buffers are used, the operation
# must wait until a buffer is released.
# Default: 4*(number of CPUs) + 1
# [tuneRefreshOnGetAttr]
# If set to `true`, file attributes will be loaded from the server on each call
# to fstat(). When set to `false` a call to fstat() may return stale
# information for files that are not currently open; this can happen mainly
# when NFS exports are used.
# Default: false
# [tuneInodeBlockBits]
# Sets the block size of file on the mountpoint to 2**tuneInodeBlockBits.
# Default: 19 (512KiB)
# [tuneEarlyCloseResponse]
# Request close responses from the metadata server before the file is fully closed.
# This may improve close() performance, but closed files may be accounted as
# open for a short time after close() has returned. Files accounted as open
# cannot be moved.
# Default: false
# [tuneUseBufferedAppend]
# Used only buffered mode. If set, writes to files opened with O_APPEND will be
# cached. Ignored unless tuneUseGlobalAppendLocks is also set.
# Default: true
# [tuneStatFsCacheSecs]
# Validity time of statfs() results, in seconds.
# Results of statfs(), once queried from the storage servers, will be cached
# for this amount of time.
# Default: 10
# [sysInodeIDStyle]
# Sets the hash function used to compute inode numbers from metadata IDs.
# The *32 options produce 32 bit inodes numbers, the *64 variants produce 64
# bit inode numbers.
# Possible values:
# hash32
# hash64
# md4hash32
# md4hash64
# Default: md4hash64

View File

@@ -0,0 +1 @@
/mnt/beegfs /etc/beegfs/beegfs-client.conf

View File

@@ -0,0 +1,26 @@
# BeeGFS client service configuration.
# Set to "NO" to disable start of the BeeGFS client via the init script.
START_SERVICE="YES"
# Set to "YES" if you want to start multiple clients with different
# configuration files on this machine.
#
# Create a subdirectory with the ending ".d" in "/etc/beegfs/" for every config
# file. The subdirectory name will be used to identify a particular client
# instance for init script start/stop.
#
# Note: The original config file in /etc/beegfs will not be used when multi-mode
# is enabled.
#
# Example: /etc/beegfs/scratch.d/beegfs-client.conf
# $ /etc/init.d/beegfs-client start scratch
MULTI_MODE="NO"
# Mount hook will be executed before any mount or unmount operation,
# and additionally after the operation succeeded.
# The first argument passed is either 'pre-mount', 'post-mount', 'pre-unmount',
# or 'post-unmount'.
# The second argument is the mount point. This can be useful to set up bind
# mounts on top of a BeeGFS, for example.
#MOUNT_HOOK=/etc/beegfs/beegfs-client-mount-hook.example

View File

@@ -0,0 +1,439 @@
#!/bin/bash
# NOTE: We expclicitly use "bash" here, as rc.status is not shell compliant
# and will complain with the message below, if "/bin/sh" is given
#
# /etc/rc.status: line 43: test: -eq: unary operator expected
# /etc/rc.status: line 44: test: -eq: unary operator expected
#
set -e
#
### BEGIN INIT INFO
# Provides: beegfs-client
# Required-Start:
# Required-Stop:
# Should-Start: $network $local_fs $syslog $time beegfs-helperd beegfs-mgmtd beegfs-meta beegfs-storage openib openibd rdma opensmd opensm $named slapd autofs ypbind nscd nslcd sshd
# Should-Stop: $network $local_fs $syslog $time beegfs-helperd beegfs-mgmtd beegfs-meta beegfs-storage openib openibd rdma opensmd opensm $named slapd autofs ypbind nscd nslcd sshd
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# chkconfig: 35 99 5
# Short-Description: BeeGFS Client
# Description: Start BeeGFS Client
### END INIT INFO
SERVICE_NAME="BeeGFS Client"
# Check for missing binaries (stale symlinks should not happen)
# Note: Special treatment of stop for LSB conformance
CLIENT_MOD=beegfs
SYSCONFIG_FILE=/etc/default/beegfs-client
BEEGFS_MOUNT_CONF="/etc/beegfs/beegfs-mounts.conf"
FORCE_AUTO_BUILD="/var/lib/beegfs/client/force-auto-build"
SUBSYS=/var/lock/subsys/beegfs-client
AUTOBUILD_CONF="/etc/beegfs/beegfs-client-autobuild.conf"
AUTOBUILD_CONF_SAVED="/var/lib/beegfs/client/beegfs-client-autobuild.conf.old"
CLIENT_SRC_PATH="/opt/beegfs/src/client"
SELINUX_OPT=""
DEFAULT_FS_TYPE="beegfs"
BUILD_FSTYPE_FILE="beegfs.fstype"
# we add "/usr/sbin" & co because "su" doesn't automatically add them
# on some systems.
EXTRA_PATH="/sbin:/usr/sbin/:/bin:/usr/bin:/usr/local/bin:/usr/local/sbin"
PATH="$EXTRA_PATH:$PATH"
# source function library
. /etc/beegfs/lib/init-multi-mode.beegfs-client
# Return values acc. to LSB for all commands but status:
# 0 - success
# 1 - generic or unspecified error
# 2 - invalid or excess argument(s)
# 3 - unimplemented feature (e.g. "reload")
# 4 - user had insufficient privileges
# 5 - program is not installed
# 6 - program is not configured
# 7 - program is not running
# 8--199 - reserved (8--99 LSB, 100--149 distrib, 150--199 appl)
#
# Note that starting an already running service, stopping
# or restarting a not-running service as well as the restart
# with force-reload (in case signaling is not supported) are
# considered a success.
handle_selinux()
{
selinuxenabled 2>/dev/null || return
# we do not support SELINUX right now and it only causes trouble, so
# we try to deactivate it
SELINUX_OPT="fscontext=system_u:object_r:tmp_t:s0"
echo
echo "WARNING: SELINUX IS ENABLED. BeeGFS might not work!"
echo " Before you consider to contact BeeGFS support, please try to"
echo " disable selinux (Usually in /etc/selinux/config)!"
echo
}
rmmod_beegfs()
{
for module in `lsmod |egrep "^beegfs" | sed -e 's/\s.*$//g'`; do rmmod $module; done
}
# Build beegfs. The autobuild will install modules to
# /lib/modules/`uname -r`/updates/fs/beegfs_autobuild
# if the build was successful and it will also run depmod.
build_beegfs()
{
echo "- BeeGFS module autobuild"
mkdir -p `dirname $SUBSYS`
# locked section (to avoid build problems when this script is called from
# multiple processes concurrently)
(
# (note: fd 16 is a more or less arbitrary number)
flock 16 || echo "WARNING: flock for build failed (continuing without lock...)" >&2
for dir in ${CLIENT_SRC_PATH}/*; do
set +e
echo $dir | grep opentk >/dev/null 2>&1
[ $? -ne 0 ] || continue # we ignore opentk
# ingore paths with missing Makfile
[ -f ${dir}/build/Makefile ] || continue
if [ -f ${dir}/build/${BUILD_FSTYPE_FILE} ]; then
fstype=`cat ${dir}/build/${BUILD_FSTYPE_FILE}`
TARGET_PARAM="TARGET=${fstype}"
else
TARGET_PARAM=""
fi
set -e
MAKE_ARGS="KMOD_INST_DIR=/lib/modules/$(uname -r)/updates/fs/beegfs_autobuild"
make -C ${dir}/build auto_rebuild_configured ${MAKE_ARGS} ${TARGET_PARAM} --silent
make -C ${dir}/build clean ${MAKE_ARGS} --silent # always clean up
done
set -e # ensure -e here (continue conditions above didn't restore it)
install -D $AUTOBUILD_CONF $AUTOBUILD_CONF_SAVED
) 16>$SUBSYS.init-autobuild
# we do not want to delete the $FORCE_AUTO_BUILD file here yet,
# as we do not test here, if the modules we just built will load at all
}
# Test if the user updated the build config. If so, we touch
# the $FORCE_AUTO_BUILD, which will trigger a rebuild
test_updated_autobuild_conf()
{
set +e
RC=0
# diskless installations might not have those files
if [ -e $AUTOBUILD_CONF -a -e $AUTOBUILD_CONF_SAVED ]; then
diff $AUTOBUILD_CONF $AUTOBUILD_CONF_SAVED >/dev/null 2>&1
RC=$?
fi
[ $RC -eq 0 ] || touch $FORCE_AUTO_BUILD
set -e
}
# Test and warn if user specified OFED_INCLUDE_PATH but appears to use in-tree
# drivers or other way around.
warn_on_ofed_mismatch()
{
set +e
modinfo ib_core > /dev/null 2>&1
if [ $? -ne 0 ]; then
# "modinfo ib_core" not working => cancel (because the user
# might have special mechanisms to load ib modules).
set -e
return
fi
# ibverbs enabled => check if include path set or not
grep '^buildArgs.*OFED_INCLUDE_PATH' $AUTOBUILD_CONF > /dev/null 2>&1
if [ $? -eq 0 ]; then
# ofed include path specified => warn if in-tree modules used
modinfo ib_core | grep 'filename:.*updates/' > /dev/null 2>&1
if [ $? -ne 0 ]; then
echo "WARNING: You probably should not specify OFED_INCLUDE_PATH in $AUTOBUILD_CONF"
fi
else
# no ofed include path specified => warn if out-of-tree modules
modinfo ib_core | grep 'filename:.*updates/' > /dev/null 2>&1
if [ $? -eq 0 ]; then
echo "WARNING: You probably need to specify" \
"OFED_INCLUDE_PATH in $AUTOBUILD_CONF"
fi
fi
set -e
}
source ${SYSCONFIG_FILE}
if [ "${MULTI_MODE}" = "YES" -o "${MULTI_MODE}" = "yes" ]; then
set +e
init_multi_mode $1 $2
exit $?
fi
RETVAL=0
case "$1" in
start)
if [ -f "${SYSCONFIG_FILE}" ]; then
if [ "${START_SERVICE}" = "NO" -o "${START_SERVICE}" = "no" ]; then
echo "${SERVICE_NAME} not set to be started"
exit 0
fi
fi
set +e
handle_selinux
set -e
echo "Starting ${SERVICE_NAME}: "
test_updated_autobuild_conf
set +e
echo "- Loading BeeGFS modules"
if [ -f "$FORCE_AUTO_BUILD" ]; then
# a new version was installed or the user updated the
# auto-build config, so we force a rebuild
rmmod_beegfs
rc=1
else
modprobe $CLIENT_MOD
rc=$?
fi
if [ $rc -ne 0 ]; then
set -e
build_beegfs
modprobe $CLIENT_MOD || (warn_on_ofed_mismatch && false)
rm -f $FORCE_AUTO_BUILD
fi
set -e
echo "- Mounting directories from $BEEGFS_MOUNT_CONF"
mkdir -p `dirname $SUBSYS`
touch $SUBSYS
OLDIFS="$IFS"
IFS=$'\n'
file=`tr -d '\r' < $BEEGFS_MOUNT_CONF` # read all lines at once and remove CR from dos files
for line in $file; do
if [ -z "$line" ]; then
continue # ignore empty line
elif echo "$line" | grep -qs "^\s*#" ; then
continue # ignore shell style comments
fi
mnt=`echo $line | awk '{print $1}'`
cfg=`echo $line | awk '{print $2}'`
fstype=`echo $line | awk '{print $3}'`
extra_mount_opts=`echo $line | awk '{print $4}'`
if [ -z "$mnt" -o -z "$cfg" ]; then
echo "Invalid config line: \"$line\""
continue
fi
if [ -z "$fstype" ]; then
fstype=${DEFAULT_FS_TYPE}
fi
set +e
mount -t ${fstype} | grep "${mnt} " >/dev/null 2>&1
if [ $? -eq 0 ]; then
# already mounted
set -e
continue
fi
set -e
# mkdir required for admon-based installation
if [ ! -e ${mnt} ]; then
mkdir -p ${mnt}
fi
exec_mount_hook pre-mount "${mnt}"
mount -t ${fstype} beegfs_nodev ${mnt} \
-ocfgFile=${cfg},_netdev,nosuid,${SELINUX_OPT},${extra_mount_opts}
exec_mount_hook post-mount "${mnt}"
done
RETVAL=$?
IFS="$OLDIFS"
;;
stop)
echo "Shutting down ${SERVICE_NAME}: "
RETVAL=$?
echo "- Unmounting directories from $BEEGFS_MOUNT_CONF"
OLDIFS="$IFS"
IFS=$'\n'
file=`cat $BEEGFS_MOUNT_CONF` # we have to read all lines at once
for line in $file; do
if [ -z "$line" ]; then
continue # ignore empty line
elif echo "$line" | grep -qs "^\s*#" ; then
continue # ignore shell style comments
fi
mnt=`echo $line | awk '{print $1}'`
cfg=`echo $line | awk '{print $2}'`
if [ -z "$mnt" -o -z "$cfg" ]; then
echo "Invalid config line: \"$line\""
continue
fi
exec_mount_hook pre-unmount "${mnt}"
set +e
res=`umount ${mnt} 2>&1`
if [ $? -ne 0 ]; then
# umount failed, ignore the failure if not mounted at all
echo $res | grep "not mounted" >/dev/null 2>&1
if [ $? -ne 0 ]; then
# Is mounted, abort.
echo "umount failed: $res"
exit 1
fi
fi
set -e
exec_mount_hook post-unmount "${mnt}"
done
IFS="$OLDIFS"
echo "- Unloading modules"
set +e
res=`rmmod_beegfs`
if [ $? -ne 0 ]; then
# rmmod failed, ignore it if the module is not loaded at all
echo $res | grep "does not exist in" >/dev/null 2>&1
if [ $? -ne 0 ]; then
# Is loaded, check if a BeeGFS is still mounted (all from the list are unmounted, so
# it must be a BeeGFS, which was manually mounted)
STILL_MOUNTED=$(mount -t beegfs | wc -l)
if [ ${STILL_MOUNTED} -eq 0 ]; then
# no more BeeGFS instances, no reason why rmmod should be failing, abort
echo "rmmod failed: $res"
exit 1
else
# BeeGFS instances mounted, so failure to rmmod is normal
echo "WARNING: Unloading BeeGFS modules failed. There are still mounted BeeGFS" \
"instances, which do not seem to be managed by the init-script mechanism" \
"(beegfs-mounts.conf)."
fi
fi
fi
RETVAL=$?
set -e
if [ $RETVAL -eq 0 ]; then rm -f $SUBSYS; fi
# Remember status and be verbose
;;
restart)
## Stop the service and regardless of whether it was
## running or not, start it again.
$0 stop
$0 start
RETVAL=$?
# Remember status and be quiet
;;
rebuild)
# Just rebuild modules. The user needs to call "restart" to make use
# of those new modules.
build_beegfs
RETVAL=$?
if [ $RETVAL -eq 0 ]; then
rm -f $FORCE_AUTO_BUILD
fi
;;
try-restart|condrestart)
## Do a restart only if the service was active before.
## Note: try-restart is now part of LSB (as of 1.9).
## RH has a similar command named condrestart.
set +e
$0 status
if test $? = 0
then
set -e
$0 restart
RETVAL=$?
else
set -e
RETVAL=7
fi
;;
status)
# Return value is slightly different for the status command:
# 0 - service up and running
# 1 - service dead, but /var/run/ pid file exists
# 2 - service dead, but /var/lock/ lock file exists
# 3 - service not running (unused)
# 4 - service status unknown :-(
# 5--199 reserved (5--99 LSB, 100--149 distro, 150--199 appl.)
set +e
echo -n "Checking for service $SERVICE_NAME: "
lsmod | grep $CLIENT_MOD >/dev/null 2>&1
if [ $? -eq 0 ]
then
echo "is running..."
mount -t beegfs | grep beegfs >/dev/null 2>&1
if [ $? -eq 0 ]; then
mount -t beegfs | cut "-d " -f1-3
echo
RETVAL=0
else
echo ">> No active beegfs mounts detected."
echo
RETVAL=4
fi
else
echo "is stopped."
echo
RETVAL=3
fi
set -e
;;
*)
echo "Usage: $0 {start|stop|status|restart|rebuild|condrestart|try-restart}"
exit 3
;;
esac
exit $RETVAL

View File

@@ -0,0 +1,128 @@
#!/bin/bash
# License: BeeGFS EULA
# constant definitions
# (for configurables see below)
DEFAULT_CFG_PATH="/etc/beegfs/beegfs-client.conf"
MGMTD_CFG_KEY="sysMgmtdHost"
QUOTA_ENABLED_CFG_KEY="quotaEnabled"
print_usage()
{
echo
echo "DESCRIPTION: Initialize or update the beegfs-client config file."
echo
echo "USAGE: `basename $0` [options]"
echo
echo " Recommended Options:"
echo
echo " -m <host> - Hostname (or IP address) of management server."
echo " (Will be stored in client config file.)"
echo
echo " Other Options:"
echo
echo " -C - Do not update client config file."
echo
echo " -c <path> - Path to client config file."
echo " (Default: ${DEFAULT_CFG_PATH})"
echo
echo " -f - Force actions, ignore warnings."
echo
echo " -h - Print this help."
echo
echo " -q - Enable quota support in config file."
echo " (Default: Quota support disabled)"
echo
echo "EXAMPLES:"
echo " * Example 1) Set \"storage01\" as management daemon host in config file:"
echo " $ `basename $0` -m storage01"
echo
}
# update config file (if enabled)
update_config_file()
{
# check if config file is defined
if [ -z "${CFG_PATH}" ]; then
return 0
fi
echo "Updating config file: ${CFG_PATH}"
if [ ! -f "${CFG_PATH}" ]; then
echo " * ERROR: Config file not found: ${CFG_PATH}"
exit 1
fi
if [ -n "${MGMTD_HOST}" ]; then
echo " * Setting management host: ${MGMTD_HOST}"
sed -i "s/\(^${MGMTD_CFG_KEY}.*=\).*/\1 ${MGMTD_HOST}/" ${CFG_PATH}
fi
if [ -n "${QUOTA_ENABLED}" ]; then
echo " * Setting quota enabled: ${QUOTA_ENABLED}"
sed -i "s/\(^${QUOTA_ENABLED_CFG_KEY}.*=\).*/\1 ${QUOTA_ENABLED}/" ${CFG_PATH}
fi
}
################## end of function definitions ##############
# configurable values and their defaults
# (for constants see above)
CFG_PATH="$DEFAULT_CFG_PATH" # empty path means "don't update cfg file"
FORCE_ACTIONS=""
MGMTD_HOST=""
QUOTA_ENABLED=""
# parse command line arguments
# (see print_usage() for description of parameters)
while getopts "Cc:fhm:q" opt; do
case $opt in
C)
CFG_PATH=""
;;
c)
CFG_PATH="$OPTARG"
;;
f)
FORCE_ACTIONS="1"
;;
h)
print_usage
exit 0
;;
m)
MGMTD_HOST="$OPTARG"
;;
q)
QUOTA_ENABLED="true"
;;
*)
echo "ERROR: Invalid argument" >&2
print_usage
exit 1
;;
esac
done
set -e
# don't do anything if no arguments are provided
if [ $# -eq 0 ]; then
print_usage
exit 1
fi
# update config file
update_config_file
echo "All done."

94
client_module/build/dist/sbin/mount.beegfs vendored Executable file
View File

@@ -0,0 +1,94 @@
#!/usr/bin/env bash
# BeeGFS Client Mount Utility / External Mount Helper
# If placed in /sbin, this script is called automatically by `mount` whenever a filesystem with type
# `beegfs` is being mounted. It's main purpose is to do name resolution of the management hostname
# as the kernel module can't do that by itself. The hostname is taken from either the mount option
# string itself ('sysMgmtdHost=') or from the config file given by the mount options ('cfgFile=').
function usage() {
echo "Usage: $(basename "$0") <fs_name> <directory> [-sfnv] [-o options]"
exit 1
}
SPEC="$1"
shift
DIR="$1"
shift
[[ -n "$SPEC" && -n "$DIR" ]] || usage
FLAGS=
OPTIONS=
# Read in all possible flags (see `man mount 8`)
while getopts 'hsfnvo:t:' FLAG; do
case "$FLAG" in
s|f|n|v)
FLAGS+=("-$FLAG")
;;
o)
OPTIONS="$OPTARG"
;;
h|*)
usage
;;
esac
done
shift "$((OPTIND -1))"
# If there is a config file available and sysMgmtdHost is set, load the management hostname from the
# config file
CFG_FILE=$(echo "$OPTIONS" | grep -oP 'cfgFile=[^,]+' | cut -d= -f2)
if [[ -n "$CFG_FILE" ]]; then
[[ -f "$CFG_FILE" ]] || {
echo "Can not open config file '$CFG_FILE'"
exit 1
}
H=$(grep -oP '^\s*sysMgmtdHost\s*=\s*\S+\s*$' "$CFG_FILE" | tr -d ' ' | cut -d= -f2)
if [[ $H == *$'\n'* ]]; then
echo "Multiple definitions of 'sysMgmtdHost' found in '$CFG_FILE'."
exit 1
elif [[ -n "$H" ]]; then
HOST_NAME="$H"
fi
fi
# If it has explicitly been set as a mount option, use that (overrides config file).
HOST_NAME_OPTION=$(echo "$OPTIONS" | grep -oP 'sysMgmtdHost=[^,]+' | cut -d= -f2)
if [[ -n "$HOST_NAME_OPTION" ]]; then
HOST_NAME="$HOST_NAME_OPTION"
fi
# A management host must be provided
[[ -n "$HOST_NAME" ]] || {
echo "Can not determine management host - neither through a mount option ('sysMgmtdHost') nor through \
a client config file ('cfgFile')."
exit 1
}
# Resolve management address
MGMTD_ADDR=$(getent ahostsv4 "$HOST_NAME" | cut -f1 -d' ' | head -n1)
# If resolve fails, error out
[[ -n "$MGMTD_ADDR" ]] || {
echo "Can not resolve management host address using hostname '$HOST_NAME'"
exit 1
}
# If the host argument was given, replace it with the resolved address, otherwise append
if [[ -n "$HOST_NAME_OPTION" ]]; then
# shellcheck disable=SC2001
OPTIONS=$(echo "$OPTIONS" | sed "s/sysMgmtdHost=[^,]\\+/sysMgmtdHost=$MGMTD_ADDR/g")
else
OPTIONS="$OPTIONS,sysMgmtdHost=$MGMTD_ADDR"
fi
# Take the part behind the "." as fstype (typically "beegfs"). This allows multiple mount utilities
# and client modules being installed at the same time.
FS_TYPE=$(basename "$0" | sed 's/^.*\.//')
set -ex
mount --internal -t "$FS_TYPE" --source "$SPEC" --target "$DIR" ${FLAGS[*]} -o"$OPTIONS"

View File

@@ -0,0 +1,21 @@
[Unit]
Description=Start BeeGFS Client
Requires=network-online.target
# We disable the wants service, because it spams the log files
#Wants=local-fs.target time-sync.target beegfs-mgmtd.service \
#beegfs-meta.service beegfs-storage.service openib.service openibd.service rdma.service \
#opensmd.service opensm.service nss-lookup.target nss-user-lookup.target slapd.service \
#autofs.service ypbind.service nscd.service nslcd.service sshd.service
After=network-online.target local-fs.target time-sync.target \
beegfs-mgmtd.service beegfs-meta.service beegfs-storage.service openib.service openibd.service \
rdma.service opensmd.service opensm.service nss-lookup.target nss-user-lookup.target \
slapd.service autofs.service ypbind.service nscd.service nslcd.service sshd.service
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/opt/beegfs/sbin/beegfs-client start
ExecStop=/opt/beegfs/sbin/beegfs-client stop
[Install]
WantedBy=multi-user.target

View File

@@ -0,0 +1,21 @@
[Unit]
Description=Start BeeGFS Client
Requires=network-online.target
# We disable the wants service, because it spams the log files
#Wants=local-fs.target time-sync.target beegfs-mgmtd.service \
#beegfs-meta.service beegfs-storage.service openib.service openibd.service rdma.service \
#opensmd.service opensm.service nss-lookup.target nss-user-lookup.target slapd.service \
#autofs.service ypbind.service nscd.service nslcd.service sshd.service
After=network-online.target local-fs.target time-sync.target \
beegfs-mgmtd.service beegfs-meta.service beegfs-storage.service openib.service openibd.service \
rdma.service opensmd.service opensm.service nss-lookup.target nss-user-lookup.target \
slapd.service autofs.service ypbind.service nscd.service nslcd.service sshd.service
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/opt/beegfs/sbin/beegfs-client start %I
ExecStop=/opt/beegfs/sbin/beegfs-client stop %I
[Install]
WantedBy=multi-user.target

View File

@@ -0,0 +1,478 @@
#!/bin/bash
set -e
# NOTE, we're using the argument array as part of this string here. As is
# often the case in shell scripts (especially when used with Makefiles) the
# quoting here is not correct in the sense that it can be broken for example
# with arguments that contain spaces. But it is expected to work with our input
# data.
CFLAGS="-D__KERNEL__ $LINUXINCLUDE $* -DKBUILD_BASENAME=\"beegfs\" -DKBUILD_MODNAME=\"beegfs\""
_generate_includes() {
for i in "$@"; do
echo "#include <$i>"
done
}
_marker_if_compiles() {
local marker=$1
shift
if $CC $CFLAGS -x c -o /dev/null -c - 2>/dev/null
then
echo -D$marker
fi
}
_check_type_input() {
local tp=$1
shift 1
_generate_includes "$@"
cat <<EOF
void want_tp(void) {
$tp name;
}
EOF
}
check_type() {
local tp=$1
local marker=$2
shift 2
_check_type_input "$tp" "$@" | _marker_if_compiles "$marker"
}
_check_struct_field_input() {
local field=$1
shift 1
_generate_includes "$@"
cat <<EOF
void want_symbol(void) {
struct ${field%%::*} s;
(void) (s.${field##*::});
}
EOF
}
check_struct_field() {
local field=$1
local marker=$2
shift 2
_check_struct_field_input "$field" "$@" | _marker_if_compiles "$marker"
}
_check_struct_field_type_input() {
local field=$1
local ftype=$2
shift 2
_generate_includes "$@"
cat <<EOF
void want_symbol(void) {
struct ${field%%::*} s;
char predicate[
2 * __builtin_types_compatible_p(__typeof(s.${field##*::}), $ftype) - 1
];
}
EOF
}
check_struct_field_type() {
local field=$1
local ftype=$2
local marker=$3
shift 3
_check_struct_field_type_input "$field" "$ftype" "$@" | _marker_if_compiles "$marker"
}
_check_expr_type_input() {
local name=$1
local signature=$2
shift 2
_generate_includes "$@"
cat <<EOF
void want_fn(void) {
char predicate[
2 * __builtin_types_compatible_p(__typeof($name), $signature) - 1
];
}
EOF
}
check_expr_type() {
local name=$1
local signature=$2
local marker=$3
shift 3
_check_expr_type_input "$name" "$signature" "$@" | _marker_if_compiles "$marker"
}
check_function() {
check_expr_type "$@"
}
_check_symbol_input() {
local name=$1
shift
_generate_includes "$@"
cat <<EOF
__typeof__($name) predicate = $name;
EOF
}
check_header() {
local header=$1
local marker=$2
shift 2
_generate_includes "$header" | _marker_if_compiles "$marker"
}
check_symbol() {
local name=$1
local marker=$2
shift 2
_check_symbol_input "$name" "$@" | _marker_if_compiles "$marker"
}
check_struct_field \
inode::i_ctime \
KERNEL_HAS_INODE_CTIME \
linux/fs.h
check_struct_field \
inode::i_mtime \
KERNEL_HAS_INODE_MTIME \
linux/fs.h
check_struct_field \
dentry::d_subdirs \
KERNEL_HAS_DENTRY_SUBDIRS \
linux/dcache.h
check_function \
generic_readlink "int (struct dentry *, char __user *, int)" \
KERNEL_HAS_GENERIC_READLINK \
linux/fs.h
check_header \
linux/sched/signal.h \
KERNEL_HAS_SCHED_SIG_H
check_header \
linux/stdarg.h \
KERNEL_HAS_LINUX_STDARG_H
check_header \
linux/filelock.h \
KERNEL_HAS_LINUX_FILELOCK_H
# cryptohash does not include linux/types.h, so the type comparison fails
check_function \
half_md4_transform "__u32 (__u32[4], __u32 const in[8])" \
KERNEL_HAS_HALF_MD4_TRANSFORM \
linux/types.h linux/cryptohash.h
check_function \
vfs_getattr "int (const struct path *, struct kstat *, u32, unsigned int)" \
KERNEL_HAS_STATX \
linux/fs.h
check_function \
kref_read "unsigned int (const struct kref*)" \
KERNEL_HAS_KREF_READ \
linux/kref.h
check_function \
file_dentry "struct dentry* (const struct file *file)" \
KERNEL_HAS_FILE_DENTRY \
linux/fs.h
check_function \
super_setup_bdi_name "int (struct super_block *sb, char *fmt, ...)" \
KERNEL_HAS_SUPER_SETUP_BDI_NAME \
linux/fs.h
check_function \
have_submounts "int (struct dentry *parent)" \
KERNEL_HAS_HAVE_SUBMOUNTS \
linux/dcache.h
check_function \
kernel_read "ssize_t (struct file *, void *, size_t, loff_t *)" \
KERNEL_HAS_KERNEL_READ \
linux/fs.h
check_function \
skwq_has_sleeper "bool (struct socket_wq*)" \
KERNEL_HAS_SKWQ_HAS_SLEEPER \
net/sock.h
check_struct_field_type \
sock::sk_data_ready "void (*)(struct sock*, int)" \
KERNEL_HAS_SK_DATA_READY_2 \
net/sock.h
check_struct_field \
sock::sk_sleep \
KERNEL_HAS_SK_SLEEP \
net/sock.h
check_function \
current_time "struct timespec64 (struct inode *)" \
KERNEL_HAS_CURRENT_TIME_SPEC64 \
linux/fs.h
check_function \
sk_has_sleeper "int (struct sock*)" \
KERNEL_HAS_SK_HAS_SLEEPER \
net/sock.h
check_function \
__wake_up_sync_key "void (struct wait_queue_head* , unsigned int, void*)" \
KERNEL_WAKE_UP_SYNC_KEY_HAS_3_ARGUMENTS \
linux/wait.h
check_expr_type \
'get_fs()' "mm_segment_t" \
KERNEL_HAS_GET_FS \
linux/uaccess.h
check_function \
iov_iter_kvec 'void (struct iov_iter *i, int direction, const struct kvec *iov, unsigned long nr_segs, size_t count)' \
KERNEL_HAS_IOV_ITER_KVEC \
linux/uio.h
# The iov_iter_kvec() function has the same API but differing behaviour
# across Linux versions:
#
# Linux < 4.20 requires ITER_KVEC to be set in "direction"
# Linux >= 4.20 issues a warning (including stacktrace) if it _is_ set.
#
# We can't detect this from the headers, only by looking at the source.
# BUT: The source is not guaranteed to be available when building.
#
# We have tried to check for this "feature" by looking at the Linux version
# as reported by the LINUX_VERSION_CODE macro.
#
# BUT: Some non-vanilla < 4.20 kernels have backported the >= 4.20
# functionality to < 4.20 kernels. So relying on the version code doesn't
# work either.
#
# What we're doing here now is our current best attempt to detect how the API
# must be used. We're checking something that is not really related to the
# actual function, but which seems to give the right results.
check_function \
iov_iter_is_kvec 'bool(const struct iov_iter *)' \
KERNEL_HAS_IOV_ITER_KVEC_NO_TYPE_FLAG_IN_DIRECTION \
linux/uio.h
# print_stack_trace() found on older Linux kernels < 5.2
check_function \
print_stack_trace 'void (struct stack_trace *trace, int spaces)' \
KERNEL_HAS_PRINT_STACK_TRACE \
linux/stacktrace.h
# Starting from kernel 5.2, print_stack_trace() is demoted to tools/ directory
# so not available to us.
# Starting from kernel 5.16 print_stack_trace() is removed completely, but
# stack_trace_print() can be used instead.
# Notably, the identifier stack_trace_print() existed even in older Linux
# versions, but with a different signature and different functionality.
check_function \
stack_trace_print 'void (unsigned long *trace, unsigned int nr_entries, int spaces)' \
KERNEL_HAS_STACK_TRACE_PRINT \
linux/stacktrace.h \
check_type 'struct file_lock_core' KERNEL_HAS_FILE_LOCK_CORE linux/filelock.h
check_type 'struct proc_ops' KERNEL_HAS_PROC_OPS linux/proc_fs.h
check_type sockptr_t KERNEL_HAS_SOCKPTR_T linux/sockptr.h
check_function \
sock_setsockopt 'int (struct socket *, int, int, sockptr_t, unsigned int)' \
KERNEL_HAS_SOCK_SETSOCKOPT_SOCKPTR_T_PARAM \
net/sock.h
check_type time64_t KERNEL_HAS_TIME64 linux/ktime.h
check_function ktime_get_ts64 'void (struct timespec64 *)' KERNEL_HAS_KTIME_GET_TS64 linux/ktime.h
check_function ktime_get_real_ts64 'void (struct timespec64 *)' KERNEL_HAS_KTIME_GET_REAL_TS64 linux/ktime.h
check_function ktime_get_coarse_real_ts64 'void (struct timespec64 *)' KERNEL_HAS_KTIME_GET_COARSE_REAL_TS64 linux/ktime.h
# latest kernel from 6.3 changes moved to timekeeping.h
check_function \
ktime_get_ts64 "void (struct timespec64 *ts)" \
KERNEL_HAS_KTIME_GET_TS64 \
linux/timekeeping.h
check_function \
ktime_get_real_ts64 "void (struct timespec64 *tv)" \
KERNEL_HAS_KTIME_GET_REAL_TS64 \
linux/timekeeping.h
check_function \
ktime_get_coarse_real_ts64 "void (struct timespec64 *ts)" \
KERNEL_HAS_KTIME_GET_COARSE_REAL_TS64 \
linux/timekeeping.h
check_function \
generic_file_splice_read "ssize_t (struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int)" \
KERNEL_HAS_GENERIC_FILE_SPLICE_READ \
linux/fs.h
check_function \
generic_permission "int (struct inode *, int)" \
KERNEL_HAS_GENERIC_PERMISSION_2 \
linux/fs.h
check_function \
generic_permission "int (struct inode *, int, int (*check_acl)(struct inode *, int)" \
KERNEL_HAS_GENERIC_PERMISSION_4 \
linux/fs.h
check_function \
setattr_prepare "int (struct mnt_idmap *, struct dentry *, struct iattr *)" \
KERNEL_HAS_SETATTR_PREPARE \
linux/fs.h
check_function \
setattr_prepare "int (struct dentry *dentry, struct iattr *attr)" \
KERNEL_HAS_SETATTR_PREPARE \
linux/fs.h
check_function \
setattr_prepare "int (struct user_namespace *, struct dentry *, struct iattr *)" \
KERNEL_HAS_SETATTR_PREPARE \
linux/fs.h
check_struct_field \
inode_operations::get_acl \
KERNEL_HAS_GET_ACL \
linux/fs.h
check_struct_field_type \
inode_operations::get_acl "struct posix_acl* (*)(struct mnt_idmap *, struct dentry *, int)" \
KERNEL_HAS_POSIX_GET_ACL_IDMAP \
linux/fs.h
check_struct_field_type \
inode_operations::get_acl "struct posix_acl* (*)(struct user_namespace *, struct dentry *, int)" \
KERNEL_HAS_POSIX_GET_ACL_NS \
linux/fs.h
check_symbol \
"extern const struct xattr_handler posix_acl_default_xattr_handler;" \
KERNEL_HAS_POSIX_ACL_DEFAULT_XATTR_HANDLER \
linux/posix_acl_xattr.h
check_struct_field_type \
inode_operations::get_acl "struct posix_acl* (*)(struct inode *, int, bool)" \
KERNEL_POSIX_GET_ACL_HAS_RCU \
linux/fs.h
check_struct_field_type \
inode_operations::get_inode_acl "struct posix_acl* (*)(struct inode *, int, bool)" \
KERNEL_HAS_GET_INODE_ACL \
linux/fs.h
check_struct_field \
inode_operations::set_acl \
KERNEL_HAS_SET_ACL \
linux/fs.h
check_struct_field_type \
inode_operations::set_acl "int (*)(struct user_namespace *, struct inode *, struct posix_acl *, int)" \
KERNEL_HAS_SET_ACL_NS_INODE \
linux/fs.h
check_struct_field_type \
inode_operations::set_acl "int (*)(struct mnt_idmap *, struct dentry *, struct posix_acl *, int)" \
KERNEL_HAS_SET_ACL_DENTRY \
linux/fs.h
check_struct_field_type \
inode_operations::set_acl "int (*)(struct user_namespace *, struct dentry *, struct posix_acl *, int)" \
KERNEL_HAS_SET_ACL_DENTRY \
linux/fs.h
check_function \
vfs_create "int (struct user_namespace *, struct inode *, struct dentry *, umode_t, bool)" \
KERNEL_HAS_USER_NS_MOUNTS \
linux/fs.h
check_function \
vfs_create "int (struct mnt_idmap *, struct inode *, struct dentry *, umode_t, bool)" \
KERNEL_HAS_IDMAPPED_MOUNTS \
linux/fs.h
check_struct_field_type \
file_operations::iterate "int (*)(struct file *, struct dir_context *)" \
KERNEL_HAS_FOPS_ITERATE \
linux/fs.h
check_struct_field_type \
xattr_handler::set "int (*)(const struct xattr_handler *, struct dentry *, struct inode *, const char *, const void *, size_t, int)" \
KERNEL_HAS_XATTR_HANDLERS_INODE_ARG \
linux/xattr.h
check_struct_field_type \
xattr_handler::set "int (*)(const struct xattr_handler *, struct user_namespace *, struct dentry *, struct inode *, const char *, const void *, size_t, int)" \
KERNEL_HAS_XATTR_HANDLERS_INODE_ARG \
linux/xattr.h
check_struct_field_type \
xattr_handler::set "int (*)(const struct xattr_handler *, struct mnt_idmap *, struct dentry *, struct inode *, const char *, const void *, size_t, int)" \
KERNEL_HAS_XATTR_HANDLERS_INODE_ARG \
linux/xattr.h
check_struct_field \
thread_info::cpu \
KERNEL_HAS_CPU_IN_THREAD_INFO \
linux/thread_info.h
check_function \
generic_fillattr "void (struct mnt_idmap *, u32, struct inode *, struct kstat *)" \
KERNEL_HAS_GENERIC_FILLATTR_REQUEST_MASK \
linux/fs.h
# Kernel 6.5 introduced getters and setters for struct inode's ctime field
check_function \
inode_get_ctime "struct timespec64 (const struct inode *inode)" \
KERNEL_HAS_INODE_GET_SET_CTIME \
linux/fs.h
# Kernel 6.6 introduced more getters and setters, also for atime and mtime
check_function \
inode_get_mtime "struct timespec64 (const struct inode *inode)" \
KERNEL_HAS_INODE_GET_SET_CTIME_MTIME_ATIME \
linux/fs.h
# From Linux kernel 6.12 onward, unaligned.h has been moved from <asm/> to <linux/> include path
check_header \
linux/unaligned.h \
KERNEL_HAS_LINUX_UNALIGNED_H
# we have to communicate with the calling makefile somehow. since we can't really use the return
# code of this script, we'll echo a special string at the end of our output for the caller to
# detect and remove again.
# this string has to be something that will, on its own, never be a valid compiler option. so let's
# choose something really, really unlikely like
echo "--~~success~~--"

View File

@@ -0,0 +1,8 @@
PACKAGE_NAME="__NAME__"
PACKAGE_VERSION="__VERSION__"
BUILT_MODULE_NAME[0]="__MODNAME__"
BUILT_MODULE_LOCATION[0]="build/"
DEST_MODULE_LOCATION[0]="/kernel/fs/beegfs/"
MAKE[0]="make -C build module 'KDIR=$kernel_source_dir' TARGET=__MODNAME__ BEEGFS_VERSION=__VERSION__"
CLEAN="make -C build clean"
AUTOINSTALL="yes"

View File

@@ -0,0 +1,300 @@
#ifndef _BEEGFS_CLIENT_H_INCLUDED
#define _BEEGFS_CLIENT_H_INCLUDED
#define BEEGFS_IOCTL_CFG_MAX_PATH 4096 // just an arbitrary value, has to be identical in user space
#define BEEGFS_IOCTL_TEST_STRING "_FhGFS_" /* copied to user space by BEEGFS_IOC_TEST_IS_FHGFS to
to confirm an FhGFS mount */
#define BEEGFS_IOCTL_TEST_BUFLEN 6 /* note: char[6] is actually the wrong size for the
BEEGFS_IOCTL_TEST_STRING that is exchanged, but that is no problem
in this particular case and so we keep it for compatibility */
#define BEEGFS_IOCTL_MOUNTID_BUFLEN 256
#define BEEGFS_IOCTL_NODEALIAS_BUFLEN 256 // The alias (formerly string ID) buffer length.
#define BEEGFS_IOCTL_NODETYPE_BUFLEN 16
#define BEEGFS_IOCTL_FILENAME_MAXLEN 256 // max supported filename len (incl terminating zero)
// entryID string is made of three 32 bit values in hexadecimal form plus two dashes
// (see common/toolkit/StorageTk.h)
#define BEEGFS_IOCTL_ENTRYID_MAXLEN 26
// stripe pattern types
#define BEEGFS_STRIPEPATTERN_INVALID 0
#define BEEGFS_STRIPEPATTERN_RAID0 1
#define BEEGFS_STRIPEPATTERN_RAID10 2
#define BEEGFS_STRIPEPATTERN_BUDDYMIRROR 3
#define BEEGFS_IOCTL_PING_MAX_COUNT 10
#define BEEGFS_IOCTL_PING_MAX_INTERVAL 2000
#define BEEGFS_IOCTL_PING_NODE_BUFLEN 64
#define BEEGFS_IOCTL_PING_SOCKTYPE_BUFLEN 8
/*
* General notes:
* - the _IOR() macro is for ioctls that read information, _IOW refers to ioctls that write or make
* modifications (e.g. file creation).
*
* - _IOR(type, number, data_type) meanings:
* - note: _IOR() encodes all three values (type, number, data_type size) into the request number
* - type: 8 bit driver-specific number to identify the driver if there are multiple drivers
* listening to the same fd (e.g. such as the TCP and IP layers).
* - number: 8 bit integer command number, so different numbers for different routines.
* - data_type: the data type (size) to be exchanged with the driver (though this number can
* also rather be seen as a command number subversion, because the actual number given here is
* not really exchanged unless the drivers' ioctl handler explicity does the exchange).
*/
#define BEEGFS_IOCTYPE_ID 'f'
#define BEEGFS_IOCNUM_GETVERSION_OLD 1 // value from FS_IOC_GETVERSION in linux/fs.h
#define BEEGFS_IOCNUM_GETVERSION 3
#define BEEGFS_IOCNUM_GET_CFG_FILE 20
#define BEEGFS_IOCNUM_CREATE_FILE 21
#define BEEGFS_IOCNUM_TEST_IS_FHGFS 22
#define BEEGFS_IOCNUM_TEST_IS_BEEGFS 22
#define BEEGFS_IOCNUM_GET_RUNTIME_CFG_FILE 23
#define BEEGFS_IOCNUM_GET_MOUNTID 24
#define BEEGFS_IOCNUM_GET_STRIPEINFO 25
#define BEEGFS_IOCNUM_GET_STRIPETARGET 26
#define BEEGFS_IOCNUM_MKFILE_STRIPEHINTS 27
#define BEEGFS_IOCNUM_CREATE_FILE_V2 28
#define BEEGFS_IOCNUM_CREATE_FILE_V3 29
#define BEEGFS_IOCNUM_GETINODEID 30
#define BEEGFS_IOCNUM_GETENTRYINFO 31
#define BEEGFS_IOCNUM_PINGNODE 32
#define BEEGFS_IOC_GETVERSION _IOR( \
BEEGFS_IOCTYPE_ID, BEEGFS_IOCNUM_GETVERSION, long)
#define BEEGFS_IOC32_GETVERSION _IOR( \
BEEGFS_IOCTYPE_ID, BEEGFS_IOCNUM_GETVERSION, int)
#define BEEGFS_IOC_GET_CFG_FILE _IOR( \
BEEGFS_IOCTYPE_ID, BEEGFS_IOCNUM_GET_CFG_FILE, struct BeegfsIoctl_GetCfgFile_Arg)
#define BEEGFS_IOC_CREATE_FILE _IOW( \
BEEGFS_IOCTYPE_ID, BEEGFS_IOCNUM_CREATE_FILE, struct BeegfsIoctl_MkFile_Arg)
#define BEEGFS_IOC_CREATE_FILE_V2 _IOW( \
BEEGFS_IOCTYPE_ID, BEEGFS_IOCNUM_CREATE_FILE_V2, struct BeegfsIoctl_MkFileV2_Arg)
#define BEEGFS_IOC_CREATE_FILE_V3 _IOW( \
BEEGFS_IOCTYPE_ID, BEEGFS_IOCNUM_CREATE_FILE_V3, struct BeegfsIoctl_MkFileV3_Arg)
#define BEEGFS_IOC_TEST_IS_FHGFS _IOR( \
BEEGFS_IOCTYPE_ID, BEEGFS_IOCNUM_TEST_IS_FHGFS, char[BEEGFS_IOCTL_TEST_BUFLEN])
#define BEEGFS_IOC_TEST_IS_BEEGFS _IOR( \
BEEGFS_IOCTYPE_ID, BEEGFS_IOCNUM_TEST_IS_BEEGFS, char[BEEGFS_IOCTL_TEST_BUFLEN])
#define BEEGFS_IOC_GET_RUNTIME_CFG_FILE _IOR( \
BEEGFS_IOCTYPE_ID, BEEGFS_IOCNUM_GET_RUNTIME_CFG_FILE, struct BeegfsIoctl_GetCfgFile_Arg)
#define BEEGFS_IOC_GET_MOUNTID _IOR( \
BEEGFS_IOCTYPE_ID, BEEGFS_IOCNUM_GET_MOUNTID, char[BEEGFS_IOCTL_MOUNTID_BUFLEN])
#define BEEGFS_IOC_GET_STRIPEINFO _IOR( \
BEEGFS_IOCTYPE_ID, BEEGFS_IOCNUM_GET_STRIPEINFO, struct BeegfsIoctl_GetStripeInfo_Arg)
#define BEEGFS_IOC_GET_STRIPETARGET _IOR( \
BEEGFS_IOCTYPE_ID, BEEGFS_IOCNUM_GET_STRIPETARGET, struct BeegfsIoctl_GetStripeTarget_Arg)
#define BEEGFS_IOC_GET_STRIPETARGET_V2 _IOR( \
BEEGFS_IOCTYPE_ID, BEEGFS_IOCNUM_GET_STRIPETARGET, struct BeegfsIoctl_GetStripeTargetV2_Arg)
#define BEEGFS_IOC_MKFILE_STRIPEHINTS _IOW( \
BEEGFS_IOCTYPE_ID, BEEGFS_IOCNUM_MKFILE_STRIPEHINTS, struct BeegfsIoctl_MkFileWithStripeHints_Arg)
#define BEEGFS_IOC_GETINODEID _IOR( \
BEEGFS_IOCTYPE_ID, BEEGFS_IOCNUM_GETINODEID, struct BeegfsIoctl_GetInodeID_Arg)
#define BEEGFS_IOC_GETENTRYINFO _IOR( \
BEEGFS_IOCTYPE_ID, BEEGFS_IOCNUM_GETENTRYINFO, struct BeegfsIoctl_GetEntryInfo_Arg)
#define BEEGFS_IOC_PINGNODE _IOR( \
BEEGFS_IOCTYPE_ID, BEEGFS_IOCNUM_PINGNODE, struct BeegfsIoctl_PingNode_Arg)
/* used to return the client config file path using an IOCTL */
struct BeegfsIoctl_GetCfgFile_Arg
{
char path[BEEGFS_IOCTL_CFG_MAX_PATH]; // (out-value) where the result path will be stored
int length; /* (in-value) length of path buffer (unused, because it's
after a fixed-size path buffer anyways) */
};
/* used to pass information for file creation */
struct BeegfsIoctl_MkFile_Arg
{
uint16_t ownerNodeID; // owner node of the parent dir
const char* parentParentEntryID; // entryID of the parent of the parent (=> the grandparentID)
int parentParentEntryIDLen;
const char* parentEntryID; // entryID of the parent
int parentEntryIDLen;
const char* parentName; // name of parent dir
int parentNameLen;
// file information
const char* entryName; // file name we want to create
int entryNameLen;
int fileType; // see linux/fs.h or man 3 readdir, DT_UNKNOWN, DT_FIFO, ...
const char* symlinkTo; // Only must be set for symlinks. The name a symlink is supposed to point to
int symlinkToLen; // Length of the symlink name
int mode; // mode (permission) of the new file
// user ID and group only will be used, if the current user is root
uid_t uid; // user ID
gid_t gid; // group ID
int numTargets; // number of targets in prefTargets array (without final 0 element)
uint16_t* prefTargets; // array of preferred targets (additional last element must be 0)
int prefTargetsLen; // raw byte length of prefTargets array (including final 0 element)
};
struct BeegfsIoctl_MkFileV2_Arg
{
uint32_t ownerNodeID; // owner node/group of the parent dir
const char* parentParentEntryID; // entryID of the parent of the parent (=> the grandparentID)
int parentParentEntryIDLen;
const char* parentEntryID; // entryID of the parent
int parentEntryIDLen;
int parentIsBuddyMirrored;
const char* parentName; // name of parent dir
int parentNameLen;
// file information
const char* entryName; // file name we want to create
int entryNameLen;
int fileType; // see linux/fs.h or man 3 readdir, DT_UNKNOWN, DT_FIFO, ...
char* symlinkTo; // Only must be set for symlinks. The name a symlink is supposed to point to
int symlinkToLen; // Length of the symlink name
int mode; // mode (permission) of the new file
// user ID and group only will be used, if the current user is root
uid_t uid; // user ID
gid_t gid; // group ID
int numTargets; // number of targets in prefTargets array (without final 0 element)
uint16_t* prefTargets; // array of preferred targets (additional last element must be 0)
int prefTargetsLen; // raw byte length of prefTargets array (including final 0 element)
};
struct BeegfsIoctl_MkFileV3_Arg
{
uint32_t ownerNodeID; // owner node/group of the parent dir
const char* parentParentEntryID; // entryID of the parent of the parent (=> the grandparentID)
int parentParentEntryIDLen;
const char* parentEntryID; // entryID of the parent
int parentEntryIDLen;
int parentIsBuddyMirrored;
const char* parentName; // name of parent dir
int parentNameLen;
// file information
const char* entryName; // file name we want to create
int entryNameLen;
int fileType; // see linux/fs.h or man 3 readdir, DT_UNKNOWN, DT_FIFO, ...
const char* symlinkTo; // Only must be set for symlinks. The name a symlink is supposed to point to
int symlinkToLen; // Length of the symlink name
int mode; // mode (permission) of the new file
// user ID and group only will be used, if the current user is root
uid_t uid; // user ID
gid_t gid; // group ID
int numTargets; // number of targets in prefTargets array (without final 0 element)
uint16_t* prefTargets; // array of preferred targets (additional last element must be 0)
int prefTargetsLen; // raw byte length of prefTargets array (including final 0 element)
uint16_t storagePoolId; // if set, this is used to override the pool id of the parent dir
};
/* used to get the stripe info of a file */
struct BeegfsIoctl_GetStripeInfo_Arg
{
unsigned outPatternType; // (out-value) stripe pattern type (STRIPEPATTERN_...)
unsigned outChunkSize; // (out-value) chunksize for striping
uint16_t outNumTargets; // (out-value) number of stripe targets of given file
};
/* used to get the stripe target of a file */
struct BeegfsIoctl_GetStripeTarget_Arg
{
uint16_t targetIndex; // index of the target that should be queried (0-based)
uint16_t outTargetNumID; // (out-value) numeric ID of target with given index
uint16_t outNodeNumID; // (out-value) numeric ID of node to which this target is mapped
char outNodeAlias[BEEGFS_IOCTL_NODEALIAS_BUFLEN]; /* (out-value) alias (formerly string ID) of the node
to which this target is mapped */
};
struct BeegfsIoctl_GetStripeTargetV2_Arg
{
/* inputs */
uint32_t targetIndex;
/* outputs */
uint32_t targetOrGroup; // target ID if the file is not buddy mirrored, otherwise mirror group ID
uint32_t primaryTarget; // target ID != 0 if buddy mirrored
uint32_t secondaryTarget; // target ID != 0 if buddy mirrored
uint32_t primaryNodeID; // node ID of target (if unmirrored) or primary target (if mirrored)
uint32_t secondaryNodeID; // node ID of secondary target, or 0 if unmirrored
char primaryNodeAlias[BEEGFS_IOCTL_NODEALIAS_BUFLEN];
char secondaryNodeAlias[BEEGFS_IOCTL_NODEALIAS_BUFLEN];
};
/* used to pass information for file creation with stripe hints */
struct BeegfsIoctl_MkFileWithStripeHints_Arg
{
const char* filename; // file name we want to create
unsigned mode; // mode (access permission) of the new file
unsigned numtargets; // number of desired targets, 0 for directory default
unsigned chunksize; // in bytes, must be 2^n >= 64Ki, 0 for directory default
};
struct BeegfsIoctl_GetInodeID_Arg
{
// input
char entryID[BEEGFS_IOCTL_ENTRYID_MAXLEN + 1];
// output
uint64_t inodeID;
};
struct BeegfsIoctl_GetEntryInfo_Arg
{
uint32_t ownerID;
char parentEntryID[BEEGFS_IOCTL_ENTRYID_MAXLEN + 1];
char entryID[BEEGFS_IOCTL_ENTRYID_MAXLEN + 1];
int entryType;
int featureFlags;
};
struct BeegfsIoctl_PingNode_Arg_Params
{
uint32_t nodeId;
char nodeType[BEEGFS_IOCTL_NODETYPE_BUFLEN];
unsigned count;
unsigned interval;
};
struct BeegfsIoctl_PingNode_Arg_Results
{
char outNode[BEEGFS_IOCTL_PING_NODE_BUFLEN];
unsigned outSuccess;
unsigned outErrors;
unsigned outTotalTime;
unsigned outPingTime[BEEGFS_IOCTL_PING_MAX_COUNT];
char outPingType[BEEGFS_IOCTL_PING_MAX_COUNT][BEEGFS_IOCTL_PING_SOCKTYPE_BUFLEN];
};
struct BeegfsIoctl_PingNode_Arg
{
struct BeegfsIoctl_PingNode_Arg_Params params;
struct BeegfsIoctl_PingNode_Arg_Results results;
};
#endif

View File

@@ -0,0 +1,367 @@
#!/bin/sh
function exec_mount_hook()
{
if [ -n "$MOUNT_HOOK" ]
then
set +e
/bin/sh -c "${MOUNT_HOOK} ${1} \"${2}\""
set -e
fi
}
function init_multi_mode()
{
ACTION=$1
CONFIG=$2
ERROR=0
if [ -z $ACTION ]
then
echo "Usage: $0 {start|stop|status|restart|rebuild|condrestart|try-restart} [CONFIGURATION_NAME]"
exit 3
fi
if [ -z $CONFIG ]
then
case "$ACTION" in
rebuild)
# Just rebuild modules. The user needs to call "restart" to make use
# of those new modules.
build_beegfs
ERROR=$?
if [ $ERROR -eq 0 ]; then
rm -f $FORCE_AUTO_BUILD
fi
;;
restart)
do_central_loop stop
do_central_loop start
ERROR=$?
;;
try-restart|condrestart)
## Do a restart only if the service was active before.
## Note: try-restart is now part of LSB (as of 1.9).
## RH has a similar command named condrestart.
do_central_loop status
if test $? = 0
then
$0 restart
ERROR=$?
else
ERROR=1
fi
;;
*)
do_central_loop $ACTION
ERROR=$?
;;
esac
else
BEEGFS_MOUNT_CONF="/etc/beegfs/${CONFIG}.d/beegfs-mounts.conf"
if [ -e "/etc/beegfs/${CONFIG}.d" ]
then
init_multi_mode_single_configuration $ACTION $CONFIG
ERROR=$?
else
echo "Configuration folder /etc/beegfs/${CONFIG}.d doesn't exist."
ERROR=1
fi
fi
return $ERROR
}
do_central_loop()
{
ACTION=$1
LOOP_ERROR=0
for CONFIG_FOLDER in $( ls -d /etc/beegfs/*.d )
do
if [ -r ${CONFIG_FOLDER}/beegfs-client.conf ]
then
CONFIG=$( basename $CONFIG_FOLDER .d )
BEEGFS_MOUNT_CONF="${CONFIG_FOLDER}/beegfs-mounts.conf"
init_multi_mode_single_configuration $ACTION $CONFIG
if [ $? -ne 0 ]
then
LOOP_ERROR=1
fi
fi
done
return $LOOP_ERROR
}
function init_multi_mode_single_configuration()
{
ACTION=$1
CONFIG=$2
if [ -z $ACTION ]
then
echo "Usage: $0 {start|stop|status|restart|rebuild|condrestart|try-restart} [CONFIGURATION_NAME]"
exit 3
fi
RETVAL=0
case "$1" in
start)
if [ -f "${SYSCONFIG_FILE}" ]
then
source ${SYSCONFIG_FILE}
if [ "${START_SERVICE}" = "NO" -o "${START_SERVICE}" = "no" ]
then
echo "BeeGFS Client not set to be started"
return 0
fi
fi
handle_selinux
echo "Starting BeeGFS Client (${CONFIG}): "
test_updated_autobuild_conf
set +e #methode test_updated_autobuild_conf set -e
echo "- Loading BeeGFS modules"
if [ -f "$FORCE_AUTO_BUILD" ]; then
# a new version was installed or the user updated the
# auto-build config, so we force a rebuild
rmmod $CLIENT_MOD 2>/dev/null
rc=1
else
modprobe $CLIENT_MOD
rc=$?
fi
if [ $rc -ne 0 ]
then
set -e
build_beegfs
modprobe $CLIENT_MOD || (warn_on_ofed_mismatch && false)
rm -f $FORCE_AUTO_BUILD
set +e
fi
echo "- Mounting directories from $BEEGFS_MOUNT_CONF"
mkdir -p /var/lock/subsys/ >/dev/null 2>&1
touch $SUBSYS >/dev/null 2>&1
if [ $? -ne 0 ]
then
echo "Couldn't create lock file."
return 1
fi
OLDIFS="$IFS"
IFS=$'\n'
if [ -r $BEEGFS_MOUNT_CONF ]
then
file=`tr -d '\r' < $BEEGFS_MOUNT_CONF` # read all lines at once and remove CR from dos files
else
echo "Couldn't read configuration file: $BEEGFS_MOUNT_CONF"
IFS="$OLDIFS"
return 1
fi
for line in $file; do
if [ -z "$line" ]; then
continue # ignore empty line
elif echo "$line" | grep -qs "^\s*#" ; then
continue # ignore shell style comments
fi
mnt=`echo $line | awk '{print $1}'`
cfg=`echo $line | awk '{print $2}'`
extra_mount_opts=`echo $line | awk '{print $3}'`
if [ -z "$mnt" -o -z "$cfg" ]; then
echo "Invalid config line: \"$line\""
RETVAL=1
continue
fi
mount -t beegfs | grep "${mnt} " >/dev/null 2>&1
if [ $? -eq 0 ]; then
# already mounted
continue
fi
# mkdir required for admon
if [ ! -e ${mnt} ]
then
mkdir -p ${mnt}
if [ $? -ne 0 ]
then
echo "Couldn't create mountpoint folder: ${mnt}"
RETVAL=1
continue
fi
fi
exec_mount_hook pre-mount "${mnt}"
mount -t beegfs beegfs_${CONFIG} ${mnt} \
-ocfgFile=${cfg},_netdev,${SELINUX_OPT},${extra_mount_opts}
if [ $? -ne 0 ]
then
echo "Couldn't mount ${mnt}."
RETVAL=1
continue
fi
exec_mount_hook post-mount "${mnt}"
done
IFS="$OLDIFS"
;;
stop)
echo "Shutting down BeeGFS Client (${CONFIG}): "
RETVAL=0
echo "- Unmounting directories from $BEEGFS_MOUNT_CONF"
OLDIFS="$IFS"
IFS=$'\n'
if [ -r $BEEGFS_MOUNT_CONF ]
then
file=`cat $BEEGFS_MOUNT_CONF` # we have to read all lines at once
else
echo "Couldn't read configuration file: $BEEGFS_MOUNT_CONF"
IFS="$OLDIFS"
return 1
fi
for line in $file
do
if [ -z "$line" ]; then
continue # ignore empty line
fi
mnt=`echo $line | awk '{print $1}'`
cfg=`echo $line | awk '{print $2}'`
if [ -z "$mnt" -o -z "$cfg" ]; then
echo "Invalid config line: \"$line\""
RETVAL=1
continue
fi
exec_mount_hook pre-unmount "${mnt}"
res=`umount ${mnt} 2>&1`
if [ $? -ne 0 ]
then
# umount failed, ignore the failure if not mounted at all
echo $res | grep "not mounted" >/dev/null 2>&1
if [ $? -ne 0 ]; then
# Is mounted, abort.
echo "umount failed: $res"
RETVAL=1
continue
fi
fi
exec_mount_hook post-unmount "${mnt}"
done
IFS="$OLDIFS"
# tests if other beegfs mounts exists
mount -t beegfs | grep beegfs >/dev/null 2>&1
if [ $? -ne 0 ]
then
echo "- Unloading modules"
res=`rmmod $CLIENT_MOD 2>&1`
if [ $? -ne 0 ]; then
# rmmod failed, ignore it if the module is not loaded at all
echo $res | grep "does not exist in" >/dev/null 2>&1
if [ $? -ne 0 ]; then
# Is loaded, abort
echo "rmmod failed: $res"
RETVAL=1
fi
fi
fi
if [ $RETVAL -eq 0 ]; then rm -f $SUBSYS; fi
# Remember status and be verbose
;;
status)
# Return value is slightly different for the status command:
# 0 - service up and running
# 1 - service dead, but /var/run/ pid file exists
# 2 - service dead, but /var/lock/ lock file exists
# 3 - service not running (unused)
# 4 - service status unknown :-(
# 5--199 reserved (5--99 LSB, 100--149 distro, 150--199 appl.)
echo -n "Checking for service BeeGFS Client (${CONFIG}): "
lsmod | grep $CLIENT_MOD >/dev/null 2>&1
if [ $? -eq 0 ]
then
echo "is running..."
mount -t beegfs | grep beegfs_${CONFIG} >/dev/null 2>&1
if [ $? -eq 0 ]; then
mount -t beegfs | grep beegfs_${CONFIG} | cut "-d " -f1-3
echo
RETVAL=0
else
echo ">> No mounts for the configuration ${CONFIG} mounted."
echo
RETVAL=4
fi
else
echo "is stopped."
echo
RETVAL=3
fi
;;
restart)
## Stop the service and regardless of whether it was
## running or not, start it again.
$0 stop ${CONFIG}
$0 start ${CONFIG}
RETVAL=$?
# Remember status and be quiet
;;
rebuild)
# Just rebuild modules. The user needs to call "restart" to make use
# of those new modules.
build_beegfs
RETVAL=$?
if [ $RETVAL -eq 0 ]; then
rm -f $FORCE_AUTO_BUILD
fi
;;
try-restart|condrestart)
## Do a restart only if the service was active before.
## Note: try-restart is now part of LSB (as of 1.9).
## RH has a similar command named condrestart.
$0 status ${CONFIG}
if test $? = 0
then
$0 restart ${CONFIG}
RETVAL=$?
else
RETVAL=7
fi
;;
*)
echo "Usage: $0 {start|stop|status|restart|rebuild|condrestart|try-restart} [CONFIGURATION_NAME]"
exit 3
;;
esac
return $RETVAL
}

View File

@@ -0,0 +1,199 @@
# NOTE(jstimpfle, 2022-04): I changed the interface of the feature-detect.sh
# script to take some arguments explicitly from the command-line, as opposed to
# implicitly from the environment.
#
# The reason is that we hit a case where there was a string literal in
# KBUILD_CFLAGS (generated in Linux kernel Makefiles), and since this variable
# is normally used as part of shell commands contained in Makefiles this
# string literal is wrapped in a pair of single quotes,
# like this '"string literal"'.
BEEGFS_FEATURE_DETECTION := $(shell $(dir $(lastword $(MAKEFILE_LIST)))/../build/feature-detect.sh $(KBUILD_CFLAGS) $(KBUILD_CPPFLAGS))
ifneq ($(lastword $(BEEGFS_FEATURE_DETECTION)),--~~success~~--)
$(error feature detection reported an error)
else
BEEGFS_FEATURE_DETECTION := $(filter-out --~~success~~--,$(BEEGFS_FEATURE_DETECTION))
$(info feature detection gives: $(BEEGFS_FEATURE_DETECTION))
endif
# ccflags-y was introduced in 2.6.24, earlier kernels use EXTRA_CFLAGS for the same purpose
ifeq ($(origin ccflags-y),file)
ccflags-y += $(BEEGFS_FEATURE_DETECTION)
else
# the client makefile sets this already
override EXTRA_CFLAGS += $(BEEGFS_FEATURE_DETECTION)
endif
kernel-version = $(shell printf "%02d%02d" $(VERSION) $(PATCHLEVEL))
kernel-if-version-or-later = $(shell [ $(kernel-version) -ge $(1) ] && echo $(2))
obj-m += ${TARGET}.o
SOURCES := \
fault-inject/fault-inject.c \
os/iov_iter.c \
os/atomic64.c \
os/OsCompat.c \
os/OsDeps.c \
net/message/NetMessageFactory.c \
net/filesystem/FhgfsOpsCommKit.c \
net/filesystem/FhgfsOpsRemoting.c \
net/filesystem/FhgfsOpsCommKitVec.c \
common/system/System.c \
common/net/sock/Socket.c \
common/net/sock/NicAddress.c \
common/net/sock/NetworkInterfaceCard.c \
common/net/sock/NicAddressList.c \
common/net/sock/RDMASocket.c \
common/net/sock/ibv/IBVSocket.c \
common/net/sock/ibv/IBVBuffer.c \
common/net/sock/ibv/No_IBVSocket.c \
common/net/sock/StandardSocket.c \
common/net/message/control/PeerInfoMsg.c \
common/net/message/SimpleIntMsg.c \
common/net/message/NetMessage.c \
common/net/message/session/locking/FLockEntryMsg.c \
common/net/message/session/locking/FLockAppendMsg.c \
common/net/message/session/locking/LockGrantedMsgEx.c \
common/net/message/session/locking/FLockRangeMsg.c \
common/net/message/session/GetFileVersionRespMsg.c \
common/net/message/session/rw/ReadLocalFileV2Msg.c \
common/net/message/session/rw/ReadLocalFileRDMAMsg.c \
common/net/message/session/rw/WriteLocalFileMsg.c \
common/net/message/session/rw/WriteLocalFileRDMAMsg.c \
common/net/message/session/FSyncLocalFileMsg.c \
common/net/message/session/GetFileVersionMsg.c \
common/net/message/session/opening/OpenFileMsg.c \
common/net/message/session/opening/OpenFileRespMsg.c \
common/net/message/session/opening/CloseFileMsg.c \
common/net/message/session/BumpFileVersion.c \
common/net/message/SimpleInt64Msg.c \
common/net/message/SimpleUInt16Msg.c \
common/net/message/SimpleStringMsg.c \
common/net/message/SimpleIntStringMsg.c \
common/net/message/nodes/RegisterNodeMsg.c \
common/net/message/nodes/RegisterNodeRespMsg.c \
common/net/message/nodes/HeartbeatRequestMsgEx.c \
common/net/message/nodes/MapTargetsMsgEx.c \
common/net/message/nodes/GetTargetMappingsRespMsg.c \
common/net/message/nodes/HeartbeatMsgEx.c \
common/net/message/nodes/RemoveNodeMsgEx.c \
common/net/message/nodes/GetStatesAndBuddyGroupsMsg.c \
common/net/message/nodes/GetStatesAndBuddyGroupsRespMsg.c \
common/net/message/nodes/RefreshTargetStatesMsgEx.c \
common/net/message/nodes/GetNodesRespMsg.c \
common/net/message/nodes/SetMirrorBuddyGroupMsgEx.c \
common/net/message/SimpleMsg.c \
common/net/message/storage/moving/RenameMsg.c \
common/net/message/storage/StatStoragePathRespMsg.c \
common/net/message/storage/creating/HardlinkMsg.c \
common/net/message/storage/creating/MkFileMsg.c \
common/net/message/storage/creating/MkDirMsg.c \
common/net/message/storage/creating/UnlinkFileMsg.c \
common/net/message/storage/creating/MkDirRespMsg.c \
common/net/message/storage/creating/RmDirMsg.c \
common/net/message/storage/creating/MkFileRespMsg.c \
common/net/message/storage/attribs/StatRespMsg.c \
common/net/message/storage/attribs/ListXAttrRespMsg.c \
common/net/message/storage/attribs/SetAttrMsg.c \
common/net/message/storage/attribs/ListXAttrMsg.c \
common/net/message/storage/attribs/RefreshEntryInfoMsg.c \
common/net/message/storage/attribs/StatMsg.c \
common/net/message/storage/attribs/GetXAttrRespMsg.c \
common/net/message/storage/attribs/GetXAttrMsg.c \
common/net/message/storage/attribs/RemoveXAttrMsg.c \
common/net/message/storage/attribs/SetXAttrMsg.c \
common/net/message/storage/lookup/LookupIntentRespMsg.c \
common/net/message/storage/lookup/LookupIntentMsg.c \
common/net/message/storage/TruncFileMsg.c \
common/net/message/storage/listing/ListDirFromOffsetRespMsg.c \
common/net/message/storage/listing/ListDirFromOffsetMsg.c \
common/threading/Thread.c \
common/toolkit/Serialization.c \
common/toolkit/MessagingTk.c \
common/toolkit/HashTk.c \
common/toolkit/ackstore/WaitAckMap.c \
common/toolkit/ackstore/AcknowledgmentStore.c \
common/toolkit/ackstore/AckStoreMap.c \
common/toolkit/Random.c \
common/toolkit/tree/IntMap.c \
common/toolkit/tree/StrCpyMap.c \
common/toolkit/tree/PointerRBTree.c \
common/toolkit/NodesTk.c \
common/toolkit/SocketTk.c \
common/toolkit/MetadataTk.c \
common/toolkit/StringTk.c \
common/toolkit/ListTk.c \
common/Types.c \
common/nodes/Node.c \
common/nodes/TargetMapper.c \
common/nodes/MirrorBuddyGroup.c \
common/nodes/NumNodeID.c \
common/nodes/TargetStateStore.c \
common/nodes/NodeTree.c \
common/nodes/MirrorBuddyGroupMapper.c \
common/nodes/NodeConnPool.c \
common/storage/StorageErrors.c \
common/storage/StatData.c \
common/storage/striping/BuddyMirrorPattern.c \
common/storage/striping/SimplePattern.c \
common/storage/striping/StripePattern.c \
common/storage/striping/Raid10Pattern.c \
common/storage/striping/Raid0Pattern.c \
common/storage/PathInfo.c \
common/storage/RdmaInfo.c \
common/storage/Nvfs.c \
common/storage/EntryInfo.c \
common/storage/StoragePoolId.c \
common/storage/FileEvent.c \
program/Main.c \
toolkit/FhgfsChunkPageVec.c \
toolkit/StatFsCache.c \
toolkit/NoAllocBufferStore.c \
toolkit/InodeRefStore.c \
toolkit/BitStore.c \
components/DatagramListener.c \
components/InternodeSyncer.c \
components/Flusher.c \
components/worker/RWPagesWork.c \
components/AckManager.c \
nodes/NodeStoreEx.c \
filesystem/ProcFs.c \
filesystem/FhgfsOpsPages.c \
filesystem/FhgfsOpsFile.c \
filesystem/FhgfsOpsInode.c \
filesystem/FhgfsOpsFileNative.c \
filesystem/FhgfsInode.c \
filesystem/helper/IoctlHelper.c \
filesystem/FsFileInfo.c \
filesystem/ProcFsHelper.c \
filesystem/FhgfsOpsSuper.c \
filesystem/FhgfsOps_versions.c \
filesystem/FhgfsXAttrHandlers.c \
filesystem/FhgfsOpsDir.c \
filesystem/FhgfsOpsIoctl.c \
filesystem/FhgfsOpsExport.c \
filesystem/FhgfsOpsHelper.c \
app/App.c \
app/log/Logger.c \
app/config/MountConfig.c \
app/config/Config.c
${TARGET}-y := $(patsubst %.c,%.o,$(SOURCES))
ifdef BEEGFS_NO_RDMA
ccflags-y += -DBEEGFS_NO_RDMA
endif
ifneq ($(OFED_INCLUDE_PATH),)
# RHEL/CentOS 8 + MLNX 4.7 requires extra flags (bug?)
ccflags-y += $(call kernel-if-version-or-later, 0418, -DHAVE_BITS_H)
NOSTDINC_FLAGS+=-I$(OFED_INCLUDE_PATH) -I$(OFED_INCLUDE_PATH)/uapi
ifeq ($(shell [ -f $(OFED_INCLUDE_PATH)/linux/compat-2.6.h ] && echo 1),1)
ccflags-y += -include $(OFED_INCLUDE_PATH)/linux/compat-2.6.h
endif
endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,436 @@
#ifndef APP_H_
#define APP_H_
#include <app/config/MountConfig.h>
#include <common/toolkit/list/PointerListIter.h>
#include <common/toolkit/list/StrCpyListIter.h>
#include <common/toolkit/list/UInt16ListIter.h>
#include <common/net/sock/NicAddressList.h>
#include <common/threading/AtomicInt.h>
#include <common/threading/Mutex.h>
#include <common/threading/Thread.h>
#include <common/Common.h>
#include <toolkit/BitStore.h>
// program return codes
#define APPCODE_NO_ERROR 0
#define APPCODE_PROGRAM_ERROR 1
#define APPCODE_INVALID_CONFIG 2
#define APPCODE_INITIALIZATION_ERROR 3
#define APPCODE_RUNTIME_ERROR 4
// forward declarations
struct Config;
struct Logger;
struct DatagramListener;
struct InternodeSyncer;
struct AckManager;
struct Flusher;
struct Node;
struct NodeStoreEx;
struct TargetMapper;
struct MirrorBuddyGroupMapper;
struct TargetStateStore;
struct NoAllocBufferStore;
struct AcknowledgmentStore;
struct NetFilter;
struct InodeRefStore;
struct StatFsCache;
struct App;
typedef struct App App;
extern void App_init(App* this, MountConfig* mountConfig);
extern void App_uninit(App* this);
extern int App_run(App* this);
extern void App_stop(App* this);
extern bool __App_initDataObjects(App* this, MountConfig* mountConfig);
extern bool __App_initInodeOperations(App* this);
extern bool __App_initLocalNodeInfo(App* this);
extern bool __App_initComponents(App* this);
extern void __App_startComponents(App* this);
extern void __App_stopComponents(App* this);
extern void __App_joinComponents(App* this);
extern void __App_waitForComponentTermination(App* this, Thread* component);
extern void __App_logInfos(App* this);
extern bool __App_mountServerCheck(App* this);
extern bool App_findAllowedInterfaces(App* this, NicAddressList* nicList);
extern void App_findAllowedRDMAInterfaces(App* this, NicAddressList* nicList, NicAddressList* rdmaNicList);
// external getters & setters
extern const char* App_getVersionStr(void);
extern void App_updateLocalInterfaces(App* app, NicAddressList* nicList);
extern char* App_cloneFsUUID(App* this);
extern void App_updateFsUUID(App* this, const char* fsUUID);
extern void App_cloneLocalNicList(App* this, NicAddressList* nicList);
extern void App_cloneLocalRDMANicList(App* this, NicAddressList* rdmaNicList);
// inliners
static inline struct Logger* App_getLogger(App* this);
static inline struct Config* App_getConfig(App* this);
static inline struct MountConfig* App_getMountConfig(App* this);
static inline struct NetFilter* App_getNetFilter(App* this);
static inline struct NetFilter* App_getTcpOnlyFilter(App* this);
static inline NicAddressList* App_getLocalRDMANicListLocked(App* this);
/**
* Called when access to the nicList is required but doesn't
* want the overhead of a clone operation. This locks the internel nicListMutex.
* App_unlockNicList must later be invoked.
*/
static inline void App_lockNicList(App* this);
/**
* Release the lock on nicListMutex acquired by App_lockNicList.
*/
static inline void App_unlockNicList(App* this);
static inline UInt16List* App_getPreferredStorageTargets(App* this);
static inline UInt16List* App_getPreferredMetaNodes(App* this);
static inline struct Node* App_getLocalNode(App* this);
static inline struct NodeStoreEx* App_getMgmtNodes(App* this);
static inline struct NodeStoreEx* App_getMetaNodes(App* this);
static inline struct NodeStoreEx* App_getStorageNodes(App* this);
static inline struct TargetMapper* App_getTargetMapper(App* this);
static inline struct MirrorBuddyGroupMapper* App_getStorageBuddyGroupMapper(App* this);
static inline struct MirrorBuddyGroupMapper* App_getMetaBuddyGroupMapper(App* this);
static inline struct TargetStateStore* App_getTargetStateStore(App* this);
static inline struct TargetStateStore* App_getMetaStateStore(App* this);
static inline struct NoAllocBufferStore* App_getCacheBufStore(App* this);
static inline struct NoAllocBufferStore* App_getPathBufStore(App* this);
static inline struct NoAllocBufferStore* App_getMsgBufStore(App* this);
static inline struct AcknowledgmentStore* App_getAckStore(App* this);
static inline struct InodeRefStore* App_getInodeRefStore(App* this);
static inline struct StatFsCache* App_getStatFsCache(App* this);
static inline struct DatagramListener* App_getDatagramListener(App* this);
static inline struct InternodeSyncer* App_getInternodeSyncer(App* this);
static inline struct AckManager* App_getAckManager(App* this);
static inline AtomicInt* App_getLockAckAtomicCounter(App* this);
static inline bool App_getConnRetriesEnabled(App* this);
static inline void App_setConnRetriesEnabled(App* this, bool connRetriesEnabled);
static inline bool App_getNetBenchModeEnabled(App* this);
static inline void App_setNetBenchModeEnabled(App* this, bool netBenchModeEnabled);
static inline struct inode_operations* App_getFileInodeOps(App* this);
static inline struct inode_operations* App_getSymlinkInodeOps(App* this);
static inline struct inode_operations* App_getDirInodeOps(App* this);
static inline struct inode_operations* App_getSpecialInodeOps(App* this);
#ifdef BEEGFS_DEBUG
static inline size_t App_getNumRPCs(App* this);
static inline void App_incNumRPCs(App* this);
static inline size_t App_getNumRemoteReads(App* this);
static inline void App_incNumRemoteReads(App* this);
static inline size_t App_getNumRemoteWrites(App* this);
static inline void App_incNumRemoteWrites(App* this);
#endif // BEEGFS_DEBUG
struct App
{
int appResult;
MountConfig* mountConfig;
struct Config* cfg;
struct Logger* logger;
const char* fsUUID;
Mutex fsUUIDMutex;
struct NetFilter* netFilter; // empty filter means "all nets allowed"
struct NetFilter* tcpOnlyFilter; // for IPs which allow only plain TCP (no RDMA etc)
StrCpyList allowedInterfaces; // empty list means "all interfaces accepted"
StrCpyList allowedRDMAInterfaces; // empty list means "all interfaces eligible"
UInt16List preferredMetaNodes; // empty list means "no preferred nodes => use any"
UInt16List preferredStorageTargets; // empty list means "no preferred nodes => use any"
// rdmaNicList contains the addresses of specific RDMA NICs to use for outbound RDMA.
// This is only populated when the configuration specifies a list of interfaces. If this
// list is empty, any RDMA NIC on the client may be used for outbound RDMA.
// allowedRDMAInterfaces contains the interface names used to populate this list.
NicAddressList rdmaNicList;
Mutex nicListMutex;
struct Node* localNode;
struct NodeStoreEx* mgmtNodes;
struct NodeStoreEx* metaNodes;
struct NodeStoreEx* storageNodes;
struct TargetMapper* targetMapper;
struct MirrorBuddyGroupMapper* storageBuddyGroupMapper;
struct MirrorBuddyGroupMapper* metaBuddyGroupMapper;
struct TargetStateStore* targetStateStore; // map storage targets IDs to a state
struct TargetStateStore* metaStateStore; // map mds targets (i.e. nodeIDs) to a state
struct NoAllocBufferStore* cacheBufStore; // for buffered cache mode
struct NoAllocBufferStore* pathBufStore; // for dentry path lookups
struct NoAllocBufferStore* msgBufStore; // for MessagingTk request/response
struct AcknowledgmentStore* ackStore;
struct InodeRefStore* inodeRefStore;
struct StatFsCache* statfsCache;
struct DatagramListener* dgramListener;
struct InternodeSyncer* internodeSyncer;
struct AckManager* ackManager;
struct Flusher* flusher;
AtomicInt lockAckAtomicCounter; // used by remoting to generate unique lockAckIDs
volatile bool connRetriesEnabled; // changed at umount and via procfs
bool netBenchModeEnabled; // changed via procfs to disable server-side disk read/write
// Inode operations. Since the members of the structs depend on runtime config opts, we need
// one copy of each struct per App object.
struct inode_operations* fileInodeOps;
struct inode_operations* symlinkInodeOps;
struct inode_operations* dirInodeOps;
struct inode_operations* specialInodeOps;
#ifdef BEEGFS_DEBUG
Mutex debugCounterMutex; // this is the closed tree, so we don't have atomics here (but doesn't
// matter since this is debug info and not performance critical)
size_t numRPCs;
size_t numRemoteReads;
size_t numRemoteWrites;
#endif // BEEGFS_DEBUG
};
struct Logger* App_getLogger(App* this)
{
return this->logger;
}
struct Config* App_getConfig(App* this)
{
return this->cfg;
}
struct MountConfig* App_getMountConfig(App* this)
{
return this->mountConfig;
}
struct NetFilter* App_getNetFilter(App* this)
{
return this->netFilter;
}
struct NetFilter* App_getTcpOnlyFilter(App* this)
{
return this->tcpOnlyFilter;
}
UInt16List* App_getPreferredMetaNodes(App* this)
{
return &this->preferredMetaNodes;
}
UInt16List* App_getPreferredStorageTargets(App* this)
{
return &this->preferredStorageTargets;
}
void App_lockNicList(App* this)
{
Mutex_lock(&this->nicListMutex); // L O C K
}
void App_unlockNicList(App* this)
{
Mutex_unlock(&this->nicListMutex); // U N L O C K
}
NicAddressList* App_getLocalRDMANicListLocked(App* this)
{
return &this->rdmaNicList;
}
struct Node* App_getLocalNode(App* this)
{
return this->localNode;
}
struct NodeStoreEx* App_getMgmtNodes(App* this)
{
return this->mgmtNodes;
}
struct NodeStoreEx* App_getMetaNodes(App* this)
{
return this->metaNodes;
}
struct NodeStoreEx* App_getStorageNodes(App* this)
{
return this->storageNodes;
}
struct TargetMapper* App_getTargetMapper(App* this)
{
return this->targetMapper;
}
struct MirrorBuddyGroupMapper* App_getStorageBuddyGroupMapper(App* this)
{
return this->storageBuddyGroupMapper;
}
struct MirrorBuddyGroupMapper* App_getMetaBuddyGroupMapper(App* this)
{
return this->metaBuddyGroupMapper;
}
struct TargetStateStore* App_getTargetStateStore(App* this)
{
return this->targetStateStore;
}
struct TargetStateStore* App_getMetaStateStore(App* this)
{
return this->metaStateStore;
}
struct NoAllocBufferStore* App_getCacheBufStore(App* this)
{
return this->cacheBufStore;
}
struct NoAllocBufferStore* App_getPathBufStore(App* this)
{
return this->pathBufStore;
}
struct NoAllocBufferStore* App_getMsgBufStore(App* this)
{
return this->msgBufStore;
}
struct AcknowledgmentStore* App_getAckStore(App* this)
{
return this->ackStore;
}
struct InodeRefStore* App_getInodeRefStore(App* this)
{
return this->inodeRefStore;
}
struct StatFsCache* App_getStatFsCache(App* this)
{
return this->statfsCache;
}
struct DatagramListener* App_getDatagramListener(App* this)
{
return this->dgramListener;
}
struct InternodeSyncer* App_getInternodeSyncer(App* this)
{
return this->internodeSyncer;
}
struct AckManager* App_getAckManager(App* this)
{
return this->ackManager;
}
AtomicInt* App_getLockAckAtomicCounter(App* this)
{
return &this->lockAckAtomicCounter;
}
bool App_getConnRetriesEnabled(App* this)
{
return this->connRetriesEnabled;
}
void App_setConnRetriesEnabled(App* this, bool connRetriesEnabled)
{
this->connRetriesEnabled = connRetriesEnabled;
}
bool App_getNetBenchModeEnabled(App* this)
{
return this->netBenchModeEnabled;
}
void App_setNetBenchModeEnabled(App* this, bool netBenchModeEnabled)
{
this->netBenchModeEnabled = netBenchModeEnabled;
}
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;
}
#ifdef BEEGFS_DEBUG
size_t App_getNumRPCs(App* this)
{
return this->numRPCs;
}
void App_incNumRPCs(App* this)
{
Mutex_lock(&this->debugCounterMutex);
this->numRPCs++;
Mutex_unlock(&this->debugCounterMutex);
}
size_t App_getNumRemoteReads(App* this)
{
return this->numRemoteReads;
}
void App_incNumRemoteReads(App* this)
{
Mutex_lock(&this->debugCounterMutex);
this->numRemoteReads++;
Mutex_unlock(&this->debugCounterMutex);
}
size_t App_getNumRemoteWrites(App* this)
{
return this->numRemoteWrites;
}
void App_incNumRemoteWrites(App* this)
{
Mutex_lock(&this->debugCounterMutex);
this->numRemoteWrites++;
Mutex_unlock(&this->debugCounterMutex);
}
#else // BEEGFS_DEBUG
#define App_incNumRPCs(this)
#define App_incNumRemoteReads(this)
#define App_incNumRemoteWrites(this)
#endif // BEEGFS_DEBUG
#endif /*APP_H_*/

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,758 @@
#ifndef CONFIG_H_
#define CONFIG_H_
#include <common/Common.h>
#include <common/toolkit/list/StrCpyListIter.h>
#include <common/toolkit/list/UInt16ListIter.h>
#include <common/toolkit/tree/StrCpyMap.h>
#include <common/toolkit/tree/StrCpyMapIter.h>
#include <common/toolkit/StringTk.h>
#include <app/config/MountConfig.h>
struct Config;
typedef struct Config Config;
enum FileCacheType;
typedef enum FileCacheType FileCacheType;
enum InodeIDStyle;
typedef enum InodeIDStyle InodeIDStyle;
enum RDMAKeyType;
typedef enum RDMAKeyType RDMAKeyType;
enum CheckCapabilities;
typedef enum CheckCapabilities CheckCapabilities;
enum EventLogMask
{
EventLogMask_NONE = 0,
EventLogMask_FLUSH = 1,
EventLogMask_TRUNC = 2,
EventLogMask_SETATTR = 4,
EventLogMask_CLOSE = 8,
EventLogMask_LINK_OP = 16,
EventLogMask_OPEN_READ = 32,
EventLogMask_OPEN_WRITE = 64,
EventLogMask_OPEN_READ_WRITE = 128
};
extern __must_check bool Config_init(Config* this, MountConfig* mountConfig);
extern Config* Config_construct(MountConfig* mountConfig);
extern void Config_uninit(Config* this);
extern void Config_destruct(Config* this);
extern bool _Config_initConfig(Config* this, MountConfig* mountConfig);
extern StrCpyMapIter _Config_eraseFromConfigMap(Config* this, StrCpyMapIter* iter);
extern void _Config_loadDefaults(Config* this);
extern bool _Config_applyConfigMap(Config* this);
extern void _Config_configMapRedefine(Config* this, char* keyStr, const char* valueStr);
extern void __Config_addLineToConfigMap(Config* this, char* line);
extern void __Config_loadFromMountConfig(Config* this, MountConfig* mountConfig);
extern bool __Config_loadFromFile(struct Config* this, const char* filename);
extern bool Config_loadStringListFile(const char* filename,
StrCpyList* outList);
extern bool Config_loadUInt16ListFile(struct Config* this, const char* filename,
UInt16List* outList);
extern bool __Config_initImplicitVals(Config* this);
extern void __Config_initConnNumCommRetries(Config* this);
extern void __Config_initTuneFileCacheTypeNum(Config* this);
void __Config_initSysInodeIDStyleNum(Config* this);
bool __Config_initConnAuthHash(Config* this, char* connAuthFile, uint64_t* outConnAuthHash);
void __Config_initConnRDMAKeyTypeNum(Config* this);
// conversion
const char* Config_fileCacheTypeNumToStr(FileCacheType cacheType);
const char* Config_inodeIDStyleNumToStr(InodeIDStyle inodeIDStyle);
const char* Config_eventLogMaskToStr(enum EventLogMask mask);
const char* Config_rdmaKeyTypeNumToStr(RDMAKeyType keyType);
const char* Config_checkCapabilitiesTypeToStr(CheckCapabilities checkCapabilities);
// getters & setters
static inline char* Config_getCfgFile(Config* this);
static inline int Config_getLogLevel(Config* this);
static inline bool Config_getLogClientID(Config* this);
static inline bool Config_getConnUseRDMA(Config* this);
static inline bool Config_getConnTCPFallbackEnabled(Config* this);
static inline int Config_getConnClientPort(Config* this);
static inline int Config_getConnMgmtdPort(Config* this);
static inline int Config_getConnMgmtdGrpcPort(Config* this);
static inline void Config_setConnMgmtdGrpcPort(Config* this, int port);
static inline unsigned Config_getConnMaxInternodeNum(Config* this);
static inline char* Config_getConnInterfacesFile(Config* this);
static inline char* Config_getConnInterfacesList(Config* this);
static inline char* Config_getConnRDMAInterfacesFile(Config* this);
static inline unsigned Config_getConnFallbackExpirationSecs(Config* this);
static inline unsigned Config_getConnNumCommRetries(Config* this);
static inline unsigned Config_getConnCommRetrySecs(Config* this);
static inline bool Config_getConnUnmountRetries(Config* this);
static inline int Config_getConnTCPRcvBufSize(Config* this);
static inline int Config_getConnUDPRcvBufSize(Config* this);
static inline unsigned Config_getConnRDMABufSize(Config* this);
static inline unsigned Config_getConnRDMAFragmentSize(Config* this);
static inline unsigned Config_getConnRDMABufNum(Config* this);
static inline unsigned Config_getConnRDMAMetaBufSize(Config* this);
static inline unsigned Config_getConnRDMAMetaBufNum(Config* this);
static inline unsigned Config_getConnRDMAMetaFragmentSize(Config* this);
static inline char* Config_getConnRDMAKeyType(Config* this);
static inline RDMAKeyType Config_getConnRDMAKeyTypeNum(Config* this);
static inline int Config_getConnRDMATypeOfService(Config* this);
static inline unsigned Config_getRemapConnectionFailureStatus(Config* this);
static inline void Config_setRemapConnectionFailureStatus(Config* this, unsigned status);
static inline char* Config_getConnNetFilterFile(Config* this);
static inline unsigned Config_getConnMaxConcurrentAttempts(Config* this);
static inline char* Config_getConnAuthFile(Config* this);
static inline bool Config_getConnDisableAuthentication(Config* this);
static inline uint64_t Config_getConnAuthHash(Config* this);
static inline char* Config_getConnTcpOnlyFilterFile(Config* this);
static inline char* Config_getTunePreferredMetaFile(Config* this);
static inline char* Config_getTunePreferredStorageFile(Config* this);
static inline char* Config_getTuneFileCacheType(Config* this);
static inline FileCacheType Config_getTuneFileCacheTypeNum(Config* this);
static inline int Config_getTuneFileCacheBufSize(Config* this);
static inline int Config_getTuneFileCacheBufNum(Config* this);
static inline int Config_getTunePathBufSize(Config* this);
static inline int Config_getTunePathBufNum(Config* this);
static inline int Config_getTuneMsgBufSize(Config* this);
static inline int Config_getTuneMsgBufNum(Config* this);
static inline unsigned Config_getTunePageCacheValidityMS(Config* this);
static inline unsigned Config_getTuneDirSubentryCacheValidityMS(Config* this);
static inline unsigned Config_getTuneFileSubentryCacheValidityMS(Config* this);
static inline unsigned Config_getTuneENOENTCacheValidityMS(Config* this);
static inline bool Config_getTuneRemoteFSync(Config* this);
static inline bool Config_getTuneUseGlobalFileLocks(Config* this);
static inline bool Config_getTuneRefreshOnGetAttr(Config* this);
static inline void Config_setTuneRefreshOnGetAttr(Config* this);
static inline unsigned Config_getTuneInodeBlockBits(Config* this);
static inline unsigned Config_getTuneInodeBlockSize(Config* this);
static inline bool Config_getTuneEarlyCloseResponse(Config* this);
static inline bool Config_getTuneUseGlobalAppendLocks(Config* this);
static inline bool Config_getTuneUseBufferedAppend(Config* this);
static inline unsigned Config_getTuneStatFsCacheSecs(Config* this);
static inline bool Config_getTuneCoherentBuffers(Config* this);
static inline char* Config_getSysMgmtdHost(Config* this);
static inline char* Config_getSysInodeIDStyle(Config* this);
static inline InodeIDStyle Config_getSysInodeIDStyleNum(Config* this);
static inline bool Config_getSysCacheInvalidationVersion(Config* this);
static inline bool Config_getSysCreateHardlinksAsSymlinks(Config* this);
static inline unsigned Config_getSysMountSanityCheckMS(Config* this);
static inline bool Config_getSysSyncOnClose(Config* this);
static inline bool Config_getSysSessionCheckOnClose(Config* this);
static inline bool Config_getSysSessionChecksEnabled(Config* this);
static inline unsigned Config_getSysUpdateTargetStatesSecs(Config* this);
static inline unsigned Config_getSysTargetOfflineTimeoutSecs(Config* this);
static inline bool Config_getSysXAttrsEnabled(Config* this);
static inline CheckCapabilities Config_getSysXAttrsCheckCapabilities (Config* this);
static inline bool Config_getSysACLsEnabled(Config* this);
static inline bool Config_getSysXAttrsImplicitlyEnabled(Config* this);
static inline bool Config_getSysBypassFileAccessCheckOnMeta(Config* this);
static inline bool Config_getQuotaEnabled(Config* this);
static inline char* Config_getConnMessagingTimeouts(Config* this);
static inline char* Config_getConnRDMATimeouts(Config* this);
static inline int Config_getConnRDMATimeoutConnect(Config* this);
static inline int Config_getConnRDMATimeoutCompletion(Config* this);
static inline int Config_getConnRDMATimeoutFlowSend(Config* this);
static inline int Config_getConnRDMATimeoutFlowRecv(Config* this);
static inline int Config_getConnRDMATimeoutPoll(Config* this);
enum FileCacheType
{ FILECACHETYPE_None = 0, FILECACHETYPE_Buffered = 1, FILECACHETYPE_Paged = 2,
FILECACHETYPE_Native = 3};
#define INODEIDSTYLE_HASH32HSIEH_STR "hash32"
#define INODEIDSTYLE_HASH64HSIEH_STR "hash64"
#define INODEIDSTYLE_HASH32MD4_STR "md4hash32"
#define INODEIDSTYLE_HASH64MD4_STR "md4hash64"
#define INODEIDSTYLE_DEFAULT INODEIDSTYLE_HASH64MD4_STR
enum InodeIDStyle
{
INODEIDSTYLE_Hash32Hsieh = 0, // hsieh32
INODEIDSTYLE_Hash32MD4, // half-md4
INODEIDSTYLE_Hash64HSieh, // hsieh32
INODEIDSTYLE_Hash64MD4 // half-md4
};
#define INODEIDSTYLE_Default INODEIDSTYLE_Hash64MD4
#define RDMAKEYTYPE_UNSAFE_GLOBAL_STR "global"
#define RDMAKEYTYPE_UNSAFE_DMA_STR "dma"
#define RDMAKEYTYPE_REGISTER_STR "register"
enum RDMAKeyType
{
RDMAKEYTYPE_UnsafeGlobal = 0,
RDMAKEYTYPE_UnsafeDMA,
RDMAKEYTYPE_Register
};
#define CHECKCAPABILITIES_ALWAYS_STR "always"
#define CHECKCAPABILITIES_CACHE_STR "cache"
#define CHECKCAPABILITIES_NEVER_STR "never"
enum CheckCapabilities
{
CHECKCAPABILITIES_Always = 0,
CHECKCAPABILITIES_Cache,
CHECKCAPABILITIES_Never
};
struct Config
{
// configurables
char* cfgFile;
int logLevel;
bool logClientID;
int connPortShift; // shifts all UDP and TCP ports
int connClientPort;
int connMgmtdPort;
int connMgmtdGrpcPort; // pulled from mgmtd and not meant to be configured by the user
bool connUseRDMA;
bool connTCPFallbackEnabled;
unsigned connMaxInternodeNum;
char* connInterfacesFile;
char* connInterfacesList;
char* connRDMAInterfacesFile;
unsigned connFallbackExpirationSecs;
unsigned connNumCommRetries; // auto-computed from connCommRetrySecs
unsigned connCommRetrySecs;
bool connUnmountRetries;
int connTCPRcvBufSize;
int connUDPRcvBufSize;
int connRDMABufSize;
int connRDMAFragmentSize;
int connRDMABufNum;
int connRDMAMetaBufSize;
int connRDMAMetaFragmentSize;
int connRDMAMetaBufNum;
int connRDMATypeOfService;
char* connRDMAKeyType;
RDMAKeyType connRDMAKeyTypeNum;
char* connNetFilterFile; // allowed IP addresses (all IPs allowed, if empty)
unsigned connMaxConcurrentAttempts;
char* connAuthFile;
bool connDisableAuthentication;
uint64_t connAuthHash; // implicitly set based on hash of connAuthFile contents
char* connTcpOnlyFilterFile; // allow only plain TCP (no RDMA etc) to these IPs
char* connMessagingTimeouts;
int connMsgLongTimeout;
int connMsgMediumTimeout;
int connMsgShortTimeout; // connection (response) timeouts in ms
// note: be careful here, because servers not
// responding for >30secs under high load is nothing
// unusual, so never use connMsgShortTimeout for
// IO-related operations.
char* connRDMATimeouts;
int connRDMATimeoutConnect;
int connRDMATimeoutCompletion;
int connRDMATimeoutFlowSend;
int connRDMATimeoutFlowRecv;
int connRDMATimeoutPoll;
char* tunePreferredMetaFile;
char* tunePreferredStorageFile;
char* tuneFileCacheType;
FileCacheType tuneFileCacheTypeNum; // auto-generated based on tuneFileCacheType
int tuneFileCacheBufSize;
int tuneFileCacheBufNum; // 0 means automatic setting
unsigned tunePageCacheValidityMS;
unsigned tuneDirSubentryCacheValidityMS;
unsigned tuneFileSubentryCacheValidityMS;
unsigned tuneENOENTCacheValidityMS;
int tunePathBufSize;
int tunePathBufNum;
int tuneMsgBufSize;
int tuneMsgBufNum; // 0 means automatic setting
bool tuneRemoteFSync;
bool tuneUseGlobalFileLocks; // false means local flock/fcntl locks
bool tuneRefreshOnGetAttr; // false means don't refresh on getattr
unsigned tuneInodeBlockBits; // bitshift for optimal io size seen by stat() (2^n)
unsigned tuneInodeBlockSize; // auto-generated based on tuneInodeBlockBits
bool tuneEarlyCloseResponse; // don't wait for chunk files close result
bool tuneUseGlobalAppendLocks; // false means local append locks
bool tuneUseBufferedAppend; // false disables buffering of append writes
unsigned tuneStatFsCacheSecs; // 0 disables caching of free space info from servers
bool tuneCoherentBuffers; // try to keep buffer cache and page cache coherent
char* sysMgmtdHost;
char* sysInodeIDStyle;
InodeIDStyle sysInodeIDStyleNum; // auto-generated based on sysInodeIDStyle
bool sysCacheInvalidationVersion;
bool sysCreateHardlinksAsSymlinks;
unsigned sysMountSanityCheckMS;
bool sysSyncOnClose;
bool sysSessionCheckOnClose;
bool sysSessionChecksEnabled;
unsigned sysUpdateTargetStatesSecs;
unsigned sysTargetOfflineTimeoutSecs;
bool sysXAttrsEnabled;
CheckCapabilities sysXAttrsCheckCapabilities;
bool sysACLsEnabled;
bool sysXAttrsImplicitlyEnabled; // True when XAttrs have not been enabled in the config file
// but have been enabled by __Config_initImplicitVals
// because ACLs are enabled in the config and XAs are needed
// to store the ACLs.
bool sysBypassFileAccessCheckOnMeta; // bypass file access check on meta server
bool quotaEnabled;
enum EventLogMask eventLogMask;
/* workaround for rename of closed files on nfs */
bool sysRenameEbusyAsXdev;
// internals
StrCpyMap configMap;
// testing
unsigned remapConnectionFailureStatus;
};
char* Config_getCfgFile(Config* this)
{
return this->cfgFile;
}
int Config_getLogLevel(Config* this)
{
return this->logLevel;
}
bool Config_getLogClientID(Config* this)
{
return this->logClientID;
}
int Config_getConnClientPort(Config* this)
{
return this->connClientPort ? (this->connClientPort + this->connPortShift) : 0;
}
int Config_getConnMgmtdPort(Config* this)
{
return this->connMgmtdPort ? (this->connMgmtdPort + this->connPortShift) : 0;
}
int Config_getConnMgmtdGrpcPort(Config* this)
{
// not adding port shift here because connMgmtdGrpcPort is pulled from mgmtd and already shifted
return this->connMgmtdGrpcPort ? this->connMgmtdGrpcPort : 0;
}
void Config_setConnMgmtdGrpcPort(Config* this, int port)
{
this->connMgmtdGrpcPort = port;
}
bool Config_getConnUseRDMA(Config* this)
{
return this->connUseRDMA;
}
bool Config_getConnTCPFallbackEnabled(Config* this)
{
return this->connTCPFallbackEnabled;
}
unsigned Config_getConnMaxInternodeNum(Config* this)
{
return this->connMaxInternodeNum;
}
char* Config_getConnInterfacesFile(Config* this)
{
return this->connInterfacesFile;
}
char* Config_getConnInterfacesList(Config* this)
{
return this->connInterfacesList;
}
char* Config_getConnRDMAInterfacesFile(Config* this)
{
return this->connRDMAInterfacesFile;
}
unsigned Config_getConnFallbackExpirationSecs(Config* this)
{
return this->connFallbackExpirationSecs;
}
unsigned Config_getConnNumCommRetries(Config* this)
{
return this->connNumCommRetries;
}
unsigned Config_getConnCommRetrySecs(Config* this)
{
return this->connCommRetrySecs;
}
bool Config_getConnUnmountRetries(Config* this)
{
return this->connUnmountRetries;
}
int Config_getConnTCPRcvBufSize(Config* this)
{
return this->connTCPRcvBufSize;
}
int Config_getConnUDPRcvBufSize(Config* this)
{
return this->connUDPRcvBufSize;
}
unsigned Config_getConnRDMABufSize(Config* this)
{
return (unsigned) this->connRDMABufSize;
}
unsigned Config_getConnRDMAFragmentSize(Config* this)
{
return (unsigned) this->connRDMAFragmentSize;
}
unsigned Config_getConnRDMABufNum(Config* this)
{
return (unsigned) this->connRDMABufNum;
}
unsigned Config_getConnRDMAMetaBufSize(Config* this)
{
return (unsigned) this->connRDMAMetaBufSize;
}
unsigned Config_getConnRDMAMetaFragmentSize(Config* this)
{
return (unsigned) this->connRDMAMetaFragmentSize;
}
unsigned Config_getConnRDMAMetaBufNum(Config* this)
{
return (unsigned) this->connRDMAMetaBufNum;
}
int Config_getConnRDMATypeOfService(Config* this)
{
return this->connRDMATypeOfService;
}
char* Config_getConnRDMAKeyType(Config* this)
{
return this->connRDMAKeyType;
}
RDMAKeyType Config_getConnRDMAKeyTypeNum(Config* this)
{
return this->connRDMAKeyTypeNum;
}
unsigned Config_getRemapConnectionFailureStatus(Config* this)
{
return this->remapConnectionFailureStatus;
}
void Config_setRemapConnectionFailureStatus(Config* this, unsigned status)
{
this->remapConnectionFailureStatus = status;
}
char* Config_getConnNetFilterFile(Config* this)
{
return this->connNetFilterFile;
}
unsigned Config_getConnMaxConcurrentAttempts(Config* this)
{
return this->connMaxConcurrentAttempts;
}
char* Config_getConnAuthFile(Config* this)
{
return this->connAuthFile;
}
bool Config_getConnDisableAuthentication(Config* this)
{
return this->connDisableAuthentication;
}
uint64_t Config_getConnAuthHash(Config* this)
{
return this->connAuthHash;
}
char* Config_getConnTcpOnlyFilterFile(Config* this)
{
return this->connTcpOnlyFilterFile;
}
char* Config_getTunePreferredMetaFile(Config* this)
{
return this->tunePreferredMetaFile;
}
char* Config_getTunePreferredStorageFile(Config* this)
{
return this->tunePreferredStorageFile;
}
char* Config_getTuneFileCacheType(Config* this)
{
return this->tuneFileCacheType;
}
FileCacheType Config_getTuneFileCacheTypeNum(Config* this)
{
return this->tuneFileCacheTypeNum;
}
int Config_getTuneFileCacheBufSize(Config* this)
{
return this->tuneFileCacheBufSize;
}
int Config_getTuneFileCacheBufNum(Config* this)
{
return this->tuneFileCacheBufNum;
}
int Config_getTunePathBufSize(Config* this)
{
return this->tunePathBufSize;
}
int Config_getTunePathBufNum(Config* this)
{
return this->tunePathBufNum;
}
int Config_getTuneMsgBufSize(Config* this)
{
return this->tuneMsgBufSize;
}
int Config_getTuneMsgBufNum(Config* this)
{
return this->tuneMsgBufNum;
}
unsigned Config_getTunePageCacheValidityMS(Config* this)
{
return this->tunePageCacheValidityMS;
}
unsigned Config_getTuneDirSubentryCacheValidityMS(Config* this)
{
return this->tuneDirSubentryCacheValidityMS;
}
unsigned Config_getTuneFileSubentryCacheValidityMS(Config* this)
{
return this->tuneFileSubentryCacheValidityMS;
}
unsigned Config_getTuneENOENTCacheValidityMS(Config* this)
{
return this->tuneENOENTCacheValidityMS;
}
bool Config_getTuneRemoteFSync(Config* this)
{
return this->tuneRemoteFSync;
}
bool Config_getTuneUseGlobalFileLocks(Config* this)
{
return this->tuneUseGlobalFileLocks;
}
bool Config_getTuneRefreshOnGetAttr(Config* this)
{
return this->tuneRefreshOnGetAttr;
}
bool Config_getTuneCoherentBuffers(Config* this)
{
return this->tuneCoherentBuffers;
}
/**
* Special function to automatically enable TuneRefreshOnGetAttr, e.g. for NFS exports.
*
* Note: We do not use any locks here assuming the right value will propate to all cores rather
* soon.
*/
void Config_setTuneRefreshOnGetAttr(Config* this)
{
this->tuneRefreshOnGetAttr = true;
// do a memory barrier, so that other CPUs get the new value as soon as possible
smp_wmb();
}
unsigned Config_getTuneInodeBlockBits(Config* this)
{
return this->tuneInodeBlockBits;
}
unsigned Config_getTuneInodeBlockSize(Config* this)
{
return this->tuneInodeBlockSize;
}
bool Config_getTuneEarlyCloseResponse(Config* this)
{
return this->tuneEarlyCloseResponse;
}
bool Config_getTuneUseGlobalAppendLocks(Config* this)
{
return this->tuneUseGlobalAppendLocks;
}
bool Config_getTuneUseBufferedAppend(Config* this)
{
return this->tuneUseBufferedAppend;
}
unsigned Config_getTuneStatFsCacheSecs(Config* this)
{
return this->tuneStatFsCacheSecs;
}
char* Config_getSysMgmtdHost(Config* this)
{
return this->sysMgmtdHost;
}
char* Config_getSysInodeIDStyle(Config* this)
{
return this->sysInodeIDStyle;
}
InodeIDStyle Config_getSysInodeIDStyleNum(Config* this)
{
return this->sysInodeIDStyleNum;
}
bool Config_getSysCacheInvalidationVersion(Config* this)
{
return this->sysCacheInvalidationVersion;
}
bool Config_getSysCreateHardlinksAsSymlinks(Config* this)
{
return this->sysCreateHardlinksAsSymlinks;
}
unsigned Config_getSysMountSanityCheckMS(Config* this)
{
return this->sysMountSanityCheckMS;
}
bool Config_getSysSyncOnClose(Config* this)
{
return this->sysSyncOnClose;
}
bool Config_getSysSessionCheckOnClose(Config* this)
{
return this->sysSessionCheckOnClose;
}
bool Config_getSysSessionChecksEnabled(Config* this)
{
return this->sysSessionChecksEnabled;
}
unsigned Config_getSysUpdateTargetStatesSecs(Config* this)
{
return this->sysUpdateTargetStatesSecs;
}
unsigned Config_getSysTargetOfflineTimeoutSecs(Config* this)
{
return this->sysTargetOfflineTimeoutSecs;
}
bool Config_getSysXAttrsEnabled(Config* this)
{
return this->sysXAttrsEnabled;
}
CheckCapabilities Config_getSysXAttrsCheckCapabilities(Config* this)
{
return this->sysXAttrsCheckCapabilities;
}
bool Config_getSysACLsEnabled(Config* this)
{
return this->sysACLsEnabled;
}
bool Config_getSysXAttrsImplicitlyEnabled(Config* this)
{
return this->sysXAttrsImplicitlyEnabled;
}
bool Config_getSysBypassFileAccessCheckOnMeta(Config* this)
{
return this->sysBypassFileAccessCheckOnMeta;
}
bool Config_getQuotaEnabled(Config* this)
{
return this->quotaEnabled;
}
char* Config_getConnMessagingTimeouts(Config* this)
{
return this->connMessagingTimeouts;
}
char* Config_getConnRDMATimeouts(Config* this)
{
return this->connRDMATimeouts;
}
int Config_getConnRDMATimeoutConnect(Config* this)
{
return this->connRDMATimeoutConnect;
}
int Config_getConnRDMATimeoutCompletion(Config* this)
{
return this->connRDMATimeoutCompletion;
}
int Config_getConnRDMATimeoutFlowSend(Config* this)
{
return this->connRDMATimeoutFlowSend;
}
int Config_getConnRDMATimeoutFlowRecv(Config* this)
{
return this->connRDMATimeoutFlowRecv;
}
int Config_getConnRDMATimeoutPoll(Config* this)
{
return this->connRDMATimeoutPoll;
}
#endif /*CONFIG_H_*/

View File

@@ -0,0 +1,238 @@
#include <app/config/MountConfig.h>
#include <common/toolkit/list/StrCpyList.h>
#include <common/toolkit/list/StrCpyListIter.h>
#include <common/Common.h>
#include <linux/parser.h>
enum {
/* Mount options that take string arguments */
Opt_cfgFile,
Opt_logStdFile,
Opt_sysMgmtdHost,
Opt_tunePreferredMetaFile,
Opt_tunePreferredStorageFile,
Opt_connInterfacesList,
Opt_connAuthFile,
Opt_connDisableAuthentication,
/* Mount options that take integer arguments */
Opt_logLevel,
Opt_connPortShift,
Opt_connMgmtdPort,
Opt_sysMountSanityCheckMS,
/* Mount options that take no arguments */
Opt_grpid,
Opt_err
};
static match_table_t fhgfs_mount_option_tokens =
{
/* Mount options that take string arguments */
{ Opt_cfgFile, "cfgFile=%s" },
{ Opt_logStdFile, "logStdFile=%s" },
{ Opt_sysMgmtdHost, "sysMgmtdHost=%s" },
{ Opt_tunePreferredMetaFile, "tunePreferredMetaFile=%s" },
{ Opt_tunePreferredStorageFile, "tunePreferredStorageFile=%s" },
{ Opt_connInterfacesList, "connInterfacesList=%s" },
{ Opt_connAuthFile, "connAuthFile=%s" },
{ Opt_connDisableAuthentication, "connDisableAuthentication=%s" },
/* Mount options that take integer arguments */
{ Opt_logLevel, "logLevel=%d" },
{ Opt_connPortShift, "connPortShift=%d" },
{ Opt_connMgmtdPort, "connMgmtdPort=%u" },
{ Opt_sysMountSanityCheckMS, "sysMountSanityCheckMS=%u" },
{ Opt_grpid, "grpid" },
{ Opt_err, NULL }
};
bool MountConfig_parseFromRawOptions(MountConfig* this, char* mountOptions)
{
char* currentOption;
if(!mountOptions)
{
printk_fhgfs_debug(KERN_INFO, "Mount options = <none>\n");
return true;
}
printk_fhgfs_debug(KERN_INFO, "Mount options = '%s'\n", mountOptions);
while( (currentOption = strsep(&mountOptions, ",") ) != NULL)
{
substring_t args[MAX_OPT_ARGS];
int tokenID;
if(!*currentOption)
continue; // skip empty string
tokenID = match_token(currentOption, fhgfs_mount_option_tokens, args);
switch(tokenID)
{
/* Mount options that take STRING arguments */
case Opt_cfgFile:
{
SAFE_KFREE(this->cfgFile);
this->cfgFile = match_strdup(args);// (string kalloc'ed => needs kfree later)
} break;
case Opt_logStdFile:
{
SAFE_KFREE(this->logStdFile);
this->logStdFile = match_strdup(args); // (string kalloc'ed => needs kfree later)
} break;
case Opt_sysMgmtdHost:
{
SAFE_KFREE(this->sysMgmtdHost);
this->sysMgmtdHost = match_strdup(args); // (string kalloc'ed => needs kfree later)
} break;
case Opt_tunePreferredMetaFile:
{
SAFE_KFREE(this->tunePreferredMetaFile);
this->tunePreferredMetaFile = match_strdup(args); // (string kalloc'ed => needs kfree later)
} break;
case Opt_tunePreferredStorageFile:
{
SAFE_KFREE(this->tunePreferredStorageFile);
this->tunePreferredStorageFile = match_strdup(args); // (string kalloc'ed => needs kfree later)
} break;
case Opt_connInterfacesList:
{
SAFE_KFREE(this->connInterfacesList);
this->connInterfacesList = match_strdup(args);
} break;
case Opt_connAuthFile:
{
SAFE_KFREE(this->connAuthFile);
this->connAuthFile = match_strdup(args);
} break;
case Opt_connDisableAuthentication:
{
SAFE_KFREE(this->connDisableAuthentication);
this->connDisableAuthentication = match_strdup(args);
} break;
/* Mount options that take INTEGER arguments */
case Opt_logLevel:
{
if(match_int(args, &this->logLevel) )
goto err_exit_invalid_option;
this->logLevelDefined = true;
} break;
case Opt_connPortShift:
{
if(match_int(args, &this->connPortShift) )
goto err_exit_invalid_option;
this->connPortShiftDefined = true;
} break;
case Opt_connMgmtdPort:
{
if(match_int(args, &this->connMgmtdPort) )
goto err_exit_invalid_option;
this->connMgmtdPortDefined = true;
} break;
case Opt_sysMountSanityCheckMS:
{
if(match_int(args, &this->sysMountSanityCheckMS) )
goto err_exit_invalid_option;
this->sysMountSanityCheckMSDefined = true;
} break;
case Opt_grpid:
this->grpid = true;
break;
default:
goto err_exit_unknown_option;
}
}
return true;
err_exit_unknown_option:
printk_fhgfs(KERN_WARNING, "Unknown mount option: '%s'\n", currentOption);
return false;
err_exit_invalid_option:
printk_fhgfs(KERN_WARNING, "Invalid mount option: '%s'\n", currentOption);
return false;
}
void MountConfig_showOptions(MountConfig* this, struct seq_file* sf)
{
if (this->cfgFile)
seq_printf(sf, ",cfgFile=%s", this->cfgFile);
if (this->logStdFile)
seq_printf(sf, ",logStdFile=%s", this->logStdFile);
if (this->sysMgmtdHost)
seq_printf(sf, ",sysMgmtdHost=%s", this->sysMgmtdHost);
if (this->tunePreferredMetaFile)
seq_printf(sf, ",tunePreferredMetaFile=%s", this->tunePreferredMetaFile);
if (this->tunePreferredStorageFile)
seq_printf(sf, ",tunePreferredStorageFile=%s", this->tunePreferredStorageFile);
if (this->connInterfacesList)
seq_printf(sf, ",connInterfacesList=%s", this->connInterfacesList);
if (this->connAuthFile)
seq_printf(sf, ",connAuthFile=%s", this->connInterfacesList);
if (this->connDisableAuthentication)
seq_printf(sf, ",connDisableAuthentication=%s", this->connInterfacesList);
if (this->logLevelDefined)
seq_printf(sf, ",logLevel=%d", this->logLevel);
if (this->connPortShiftDefined)
seq_printf(sf, ",connPortShift=%d", this->connPortShift);
if (this->connMgmtdPortDefined)
seq_printf(sf, ",connMgmtdPort=%u", this->connMgmtdPort);
if (this->sysMountSanityCheckMSDefined)
seq_printf(sf, ",sysMountSanityCheckMS=%u", this->sysMountSanityCheckMS);
if (this->grpid)
seq_printf(sf, ",grpid");
}

View File

@@ -0,0 +1,80 @@
#ifndef OPEN_MOUNTCONFIG_H_
#define OPEN_MOUNTCONFIG_H_
#include <common/Common.h>
#include <linux/seq_file.h>
struct MountConfig;
typedef struct MountConfig MountConfig;
static inline void MountConfig_init(MountConfig* this);
static inline MountConfig* MountConfig_construct(void);
static inline void MountConfig_uninit(MountConfig* this);
static inline void MountConfig_destruct(MountConfig* this);
extern bool MountConfig_parseFromRawOptions(MountConfig* this, char* mountOptions);
extern void MountConfig_showOptions(MountConfig* this, struct seq_file* sf);
struct MountConfig
{
char* cfgFile;
char* logStdFile;
char* sysMgmtdHost;
char* tunePreferredMetaFile;
char* tunePreferredStorageFile;
bool logLevelDefined; // true if the value has been specified
bool connPortShiftDefined; // true if the value has been specified
bool connMgmtdPortDefined; // true if the value has been specified
bool sysMountSanityCheckMSDefined; // true if the value has been specified
int logLevel;
unsigned connPortShift;
unsigned connMgmtdPort;
unsigned sysMountSanityCheckMS;
char* connInterfacesList;
char* connAuthFile;
char* connDisableAuthentication;
bool grpid;
};
void MountConfig_init(MountConfig* this)
{
memset(this, 0, sizeof(*this) );
}
struct MountConfig* MountConfig_construct(void)
{
struct MountConfig* this = (MountConfig*)os_kmalloc(sizeof(*this) );
MountConfig_init(this);
return this;
}
void MountConfig_uninit(MountConfig* this)
{
SAFE_KFREE(this->cfgFile);
SAFE_KFREE(this->logStdFile);
SAFE_KFREE(this->sysMgmtdHost);
SAFE_KFREE(this->tunePreferredMetaFile);
SAFE_KFREE(this->tunePreferredStorageFile);
SAFE_KFREE(this->connInterfacesList);
SAFE_KFREE(this->connAuthFile);
SAFE_KFREE(this->connDisableAuthentication);
}
void MountConfig_destruct(MountConfig* this)
{
MountConfig_uninit(this);
kfree(this);
}
#endif /*OPEN_MOUNTCONFIG_H_*/

View File

@@ -0,0 +1,331 @@
#include <common/threading/Thread.h>
#include <common/toolkit/MessagingTk.h>
#include <common/nodes/Node.h>
#include <filesystem/FhgfsOpsSuper.h>
#include <filesystem/FhgfsInode.h>
#include <toolkit/NoAllocBufferStore.h>
#include "Logger.h"
#define LOG_TOPIC_GENERAL_STR "general"
#define LOG_TOPIC_CONN_STR "conn"
#define LOG_TOPIC_COMMKIT_STR "commkit"
#define LOG_TOPIC_UNKNOWN_STR "<unknown>" /* for unknown/invalid log topics */
void Logger_init(Logger* this, App* app, Config* cfg)
{
int i;
this->app = app;
for(i=0; i < LogTopic_LAST; i++)
this->logLevels[i] = Config_getLogLevel(cfg);
this->logFormattedBuf = (char*)os_kmalloc(LOGGER_LOGBUF_SIZE);
this->logContextBuf = (char*)os_kmalloc(LOGGER_LOGBUF_SIZE);
this->clientID = NULL;
Mutex_init(&this->outputMutex);
// Note: The follwing guys exist to avoid deadlocks that would occur when log messages are
// created (by the same thread) while we're already trying to send a log message to the
// helper daemon (e.g. the messages of the NodeConnPool). Such messages will be discarded.
this->currentOutputPID = LOGGER_PID_NOCURRENTOUTPUT;
Mutex_init(&this->multiLockMutex);
}
Logger* Logger_construct(App* app, Config* cfg)
{
Logger* this = (Logger*)os_kmalloc(sizeof(Logger) );
Logger_init(this, app, cfg);
return this;
}
void Logger_uninit(Logger* this)
{
SAFE_KFREE(this->clientID);
SAFE_KFREE(this->logContextBuf);
SAFE_KFREE(this->logFormattedBuf);
Mutex_uninit(&this->multiLockMutex);
Mutex_uninit(&this->outputMutex);
}
void Logger_destruct(Logger* this)
{
Logger_uninit(this);
kfree(this);
}
/**
* Just print a log message with formatting similar to printk().
*
* @param level LogLevel_... value
* @param context the context from which this msg was printed (e.g. the calling function).
* @param msg the log message with formatting, e.g. "%s".
*/
void Logger_logFormatted(Logger* this, LogLevel level, const char* context, const char* msgFormat,
...)
{
// note: cannot be inlined because of variable arg list
va_list ap;
if(level > this->logLevels[LogTopic_GENERAL])
return;
va_start(ap, msgFormat);
__Logger_logTopFormattedGranted(this, LogTopic_GENERAL, level, context, msgFormat, ap);
va_end(ap);
}
void Logger_logTopFormatted(Logger* this, LogTopic logTopic, LogLevel level, const char* context,
const char* msgFormat, ...)
{
// note: cannot be inlined because of variable arg list
va_list ap;
if(level > this->logLevels[logTopic])
return;
va_start(ap, msgFormat);
__Logger_logTopFormattedGranted(this, logTopic, level, context, msgFormat, ap);
va_end(ap);
}
/**
* Log with EntryID
*
* Note: This takes an EntryInfo read-lock. Must be used only if there is no risk of deadlock.
*/
void Logger_logTopFormattedWithEntryID(struct inode* inode, LogTopic logTopic, LogLevel level,
const char* logContext, const char* msgFormat, ...)
{
char* newMsg;
App* app = FhgfsOps_getApp(inode->i_sb);
Logger* log = App_getLogger(app);
FhgfsInode* fhgfsInode = BEEGFS_INODE(inode);
const EntryInfo* entryInfo = FhgfsInode_getEntryInfo(fhgfsInode);
va_list ap;
FhgfsInode_entryInfoReadLock(fhgfsInode); // L O C K entryInfo
va_start(ap, msgFormat);
newMsg = os_kmalloc(LOGGER_LOGBUF_SIZE);
if (newMsg)
snprintf(newMsg, LOGGER_LOGBUF_SIZE, "entryID: %s %s ", EntryInfo_getEntryID(entryInfo),
msgFormat);
else // malloc failed. Likely an out memory situation, we still try to print msgFormat
newMsg = (char*)msgFormat;
Logger_logTopFormattedVA(log, logTopic, level, logContext, newMsg, ap);
va_end(ap);
FhgfsInode_entryInfoReadUnlock(fhgfsInode); // U N L O C K entryInfo
if(newMsg != msgFormat)
kfree(newMsg);
}
/**
* Just print a log message. Similar to Logger_logFormatted(), but take a va_list already
*/
void Logger_logFormattedVA(Logger* this, LogLevel level, const char* context, const char* msgFormat,
va_list ap)
{
if(level > this->logLevels[LogTopic_GENERAL])
return;
__Logger_logTopFormattedGranted(this, LogTopic_GENERAL, level, context, msgFormat, ap);
}
/**
* Just print a log message. Similar to Logger_logTopFormatted(), but take a va_list already
*/
void Logger_logTopFormattedVA(Logger* this, LogTopic logTopic, LogLevel level, const char* context,
const char* msgFormat, va_list ap)
{
if(level > this->logLevels[logTopic])
return;
__Logger_logTopFormattedGranted(this, logTopic, level, context, msgFormat, ap);
}
void Logger_logErrFormatted(Logger* this, const char* context, const char* msgFormat, ...)
{
// note: cannot be inlined because of variable arg list
va_list ap;
va_start(ap, msgFormat);
__Logger_logTopFormattedGranted(this, LogTopic_GENERAL, Log_ERR, context, msgFormat, ap);
va_end(ap);
}
void Logger_logTopErrFormatted(Logger* this, LogTopic logTopic, const char* context,
const char* msgFormat, ...)
{
// note: cannot be inlined because of variable arg list
va_list ap;
va_start(ap, msgFormat);
__Logger_logTopFormattedGranted(this, logTopic, Log_ERR, context, msgFormat, ap);
va_end(ap);
}
/**
* Prints a message to the standard log.
*
* @param level log level (Log_... value)
* @param msg the message
*/
void __Logger_logTopFormattedGranted(Logger* this, LogTopic logTopic, LogLevel level,
const char* context, const char* msgFormat, va_list args)
{
if(__Logger_checkThreadMultiLock(this) )
{
// this thread is already trying to log a message. trying to lock outputMutex would deadlock.
// => discard this message
return;
}
Mutex_lock(&this->outputMutex);
__Logger_setCurrentOutputPID(this, current->pid); // grab currentOutputPID
// evaluate msgFormat
vsnprintf(this->logFormattedBuf, LOGGER_LOGBUF_SIZE, msgFormat, args);
// extend context
if(this->clientID)
snprintf(this->logContextBuf, LOGGER_LOGBUF_SIZE, "%s: %s", this->clientID, context);
else
snprintf(this->logContextBuf, LOGGER_LOGBUF_SIZE, "%s", context);
printk_fhgfs(KERN_INFO, "%s: %s\n", this->logContextBuf, this->logFormattedBuf);
__Logger_setCurrentOutputPID(this, LOGGER_PID_NOCURRENTOUTPUT); // release currentOutputPID
Mutex_unlock(&this->outputMutex);
}
/**
* Note: Call this before locking the outputMutex (because it exists to avoid dead-locking).
*
* @return true if the currentOutputPID is set to the current thread and logging cannot continue;
*/
bool __Logger_checkThreadMultiLock(Logger* this)
{
bool retVal = false;
Mutex_lock(&this->multiLockMutex);
if(this->currentOutputPID == current->pid)
{ // we alread own the outputPID (=> we already own the outputMutex)
retVal = true;
}
Mutex_unlock(&this->multiLockMutex);
return retVal;
}
/**
* Note: Call this only after the thread owns the outputMutex to avoid "stealing".
*/
void __Logger_setCurrentOutputPID(Logger* this, pid_t pid)
{
Mutex_lock(&this->multiLockMutex);
this->currentOutputPID = pid;
Mutex_unlock(&this->multiLockMutex);
}
/**
* Returns a pointer to the static string representation of a log topic (or "<unknown>" for unknown/
* invalid log topic numbers.
*/
const char* Logger_getLogTopicStr(LogTopic logTopic)
{
switch(logTopic)
{
case LogTopic_GENERAL:
return LOG_TOPIC_GENERAL_STR;
case LogTopic_CONN:
return LOG_TOPIC_CONN_STR;
case LogTopic_COMMKIT:
return LOG_TOPIC_COMMKIT_STR;
default:
return LOG_TOPIC_UNKNOWN_STR;
}
}
/**
* Returns the log topic number from a string (not case-sensitive).
*
* @return false if string didn't match any known log topic.
*/
bool Logger_getLogTopicFromStr(const char* logTopicStr, LogTopic* outLogTopic)
{
int i;
for(i=0; i < LogTopic_LAST; i++)
{
const char* currentLogTopicStr = Logger_getLogTopicStr( (LogTopic)i);
if(!strcasecmp(logTopicStr, currentLogTopicStr))
{
*outLogTopic = i;
return true;
}
}
// (note: we carefully set outLogTopic to "general" to not risk leaving it undefined)
*outLogTopic = LogTopic_GENERAL;
return false;
}
/**
* Shortcut to retrieve the level of LogTopic_GENERAL in old code.
* New code should use _getLogTopicLevel() instead.
*/
LogLevel Logger_getLogLevel(Logger* this)
{
return this->logLevels[LogTopic_GENERAL];
}
LogLevel Logger_getLogTopicLevel(Logger* this, LogTopic logTopic)
{
return this->logLevels[logTopic];
}

View File

@@ -0,0 +1,244 @@
#ifndef LOGGER_H_
#define LOGGER_H_
#include <app/config/Config.h>
#include <app/App.h>
#include <common/Common.h>
#include <common/toolkit/StringTk.h>
#include <common/toolkit/Time.h>
#include <common/threading/Mutex.h>
#include <common/Common.h>
#include <common/Common.h>
#define LOGGER_LOGBUF_SIZE 1000 /* max log message length */
#define LOGGER_PID_NOCURRENTOUTPUT 0 /* pid value if outputMutex not locked */
#ifdef LOG_DEBUG_MESSAGES
#define LOG_DEBUG(logger, level, contextStr, msgStr) \
do { Logger_log(logger, level, contextStr, msgStr); } while(0)
#define LOG_DEBUG_TOP(logger, logTopic, level, contextStr, msgStr) \
do { Logger_logTop(logger, logTopic, level, contextStr, msgStr); } while(0)
#define LOG_DEBUG_FORMATTED(logger, level, contextStr, msgStr, ...) \
do { Logger_logFormatted(logger, level, contextStr, msgStr, ## __VA_ARGS__); } while(0)
#define LOG_DEBUG_TOP_FORMATTED(logger, logTopic, level, contextStr, msgStr, ...) \
do { Logger_logTopFormatted(logger, logTopic, level, contextStr, msgStr, ## __VA_ARGS__); } \
while(0)
#else
#define LOG_DEBUG(logger, level, contextStr, msgStr)
#define LOG_DEBUG_TOP(logger, logTopic, level, contextStr, msgStr)
#define LOG_DEBUG_FORMATTED(logger, level, contextStr, msgStr, ...)
#define LOG_DEBUG_TOP_FORMATTED(logger, logTopic, level, contextStr, msgStr, ...)
#endif // LOG_DEBUG_MESSAGES
#define Logger_logFormattedWithEntryID(inode, level, logContext, msgFormat, ...) \
Logger_logTopFormattedWithEntryID(inode, LogTopic_GENERAL, level, logContext, msgFormat, \
##__VA_ARGS__)
// forward declarations...
struct Logger;
typedef struct Logger Logger;
struct Node;
enum LogLevel;
typedef enum LogLevel LogLevel;
enum LogTopic;
typedef enum LogTopic LogTopic;
extern void Logger_init(Logger* this, App* app, Config* cfg);
extern Logger* Logger_construct(App* app, Config* cfg);
extern void Logger_uninit(Logger* this);
extern void Logger_destruct(Logger* this);
__attribute__((format(printf, 4, 5)))
extern void Logger_logFormatted(Logger* this, LogLevel level, const char* context,
const char* msgFormat, ...);
__attribute__((format(printf, 5, 6)))
extern void Logger_logTopFormattedWithEntryID(struct inode* inode, LogTopic logTopic,
LogLevel level, const char* logContext, const char* msgFormat, ...);
__attribute__((format(printf, 5, 6)))
extern void Logger_logTopFormatted(Logger* this, LogTopic logTopic, LogLevel level,
const char* context, const char* msgFormat, ...);
extern void Logger_logFormattedVA(Logger* this, LogLevel level, const char* context,
const char* msgFormat, va_list ap);
extern void Logger_logTopFormattedVA(Logger* this, LogTopic logTopic, LogLevel level,
const char* context, const char* msgFormat, va_list ap);
__attribute__((format(printf, 3, 4)))
extern void Logger_logErrFormatted(Logger* this, const char* context, const char* msgFormat, ...);
__attribute__((format(printf, 4, 5)))
extern void Logger_logTopErrFormatted(Logger* this, LogTopic logTopic, const char* context,
const char* msgFormat, ...);
extern LogLevel Logger_getLogLevel(Logger* this);
extern LogLevel Logger_getLogTopicLevel(Logger* this, LogTopic logTopic);
extern void __Logger_logTopFormattedGranted(Logger* this, LogTopic logTopic, LogLevel level,
const char* context, const char* msgFormat, va_list args);
extern bool __Logger_checkThreadMultiLock(Logger* this);
extern void __Logger_setCurrentOutputPID(Logger* this, pid_t pid);
// static
extern const char* Logger_getLogTopicStr(LogTopic logTopic);
extern bool Logger_getLogTopicFromStr(const char* logTopicStr, LogTopic* logTopic);
// getters & setters
static inline void Logger_setClientID(Logger* this, const char* clientID);
static inline void Logger_setAllLogLevels(Logger* this, LogLevel logLevel);
static inline void Logger_setLogTopicLevel(Logger* this, LogTopic logTopic, LogLevel logLevel);
// inliners
static inline void Logger_log(Logger* this, LogLevel level, const char* context, const char* msg);
static inline void Logger_logTop(Logger* this, LogTopic logTopic, LogLevel level,
const char* context, const char* msg);
static inline void Logger_logErr(Logger* this, const char* context, const char* msg);
static inline void Logger_logTopErr(Logger* this, LogTopic logTopic, const char* context,
const char* msg);
enum LogLevel
{
LOG_NOTHING=-1,
Log_ERR=0, /* system error */
Log_CRITICAL=1, /* something the users should definitely know about */
Log_WARNING=2, /* things that indicate or are related to a problem */
Log_NOTICE=3, /* things that could help finding problems */
Log_DEBUG=4, /* things that are only useful during debugging, often logged with LOG_DEBUG() */
Log_SPAM=5 /* things that are typically too detailed even during normal debugging,
very often with LOG_DEBUG() */
};
/**
* Note: When you add a new log topic, you must also update these places:
* 1) Logger_getLogTopicStr()
* 2) ProcFsHelper_{read/write}_logLevels()
*/
enum LogTopic
{
LogTopic_GENERAL=0, /* everything that is not assigned to a more specific log topic */
LogTopic_CONN, /* connects and disconnects */
LogTopic_COMMKIT, /* CommKitVec */
LogTopic_LAST /* not valid, just exists to define the LogLevelsArray size */
};
typedef signed char LogTopicLevels[LogTopic_LAST]; /* array for per-topic log levels, see LogTopic/
LogLevel. Note: Type is actually type LogLevel, but we use char here because we also allow
"-1" to disable a level. */
/**
* This is the general logger class.
*/
struct Logger
{
// configurables
LogTopicLevels logLevels; // per-topic log levels
// internals
App* app;
Mutex outputMutex;
Mutex multiLockMutex; // to avoid multiple locking of the outputMutex by the same thread
pid_t currentOutputPID; // pid of outputMutex holder (see LOGGER_PID_NOCURRENTOUTPUT)
char* logFormattedBuf; // for logging functions with variable argument list
char* logContextBuf; // for extended context logging
char* clientID; // only set if clientID logging is enabled
};
/**
* Note: Copies the clientID.
*/
void Logger_setClientID(Logger* this, const char* clientID)
{
SAFE_KFREE(this->clientID); // free old clientID
this->clientID = StringTk_strDup(clientID);
}
/**
* Note: This is intended to be used during app destruction to disable logging by setting the levels
* to "-1".
*
* @param logLevel LogLevel_... or "-1" to disable.
*/
void Logger_setAllLogLevels(Logger* this, LogLevel logLevel)
{
int i;
for(i=0; i < LogTopic_LAST; i++)
this->logLevels[i] = logLevel;
}
/**
* @param logLevel LogLevel_... or "-1" to disable.
*/
void Logger_setLogTopicLevel(Logger* this, LogTopic logTopic, LogLevel logLevel)
{
this->logLevels[logTopic] = logLevel;
}
/**
* Log msg for LogTopic_GENERAL.
*
* @param level LogLevel_... value
* @param context the context from which this msg was printed (e.g. the calling function).
* @param msg the log message
*/
void Logger_log(Logger* this, LogLevel level, const char* context, const char* msg)
{
Logger_logFormatted(this, level, context, "%s", msg);
}
/**
* Log msg for a certain log topic.
*
* @param level LogLevel_... value
* @param context the context from which this msg was printed (e.g. the calling function).
* @param msg the log message
*/
void Logger_logTop(Logger* this, LogTopic logTopic, LogLevel level, const char* context,
const char* msg)
{
Logger_logTopFormatted(this, logTopic, level, context, "%s", msg);
}
/**
* Log error msg for LogTopic_GENERAL.
*/
void Logger_logErr(Logger* this, const char* context, const char* msg)
{
Logger_logErrFormatted(this, context, "%s", msg);
}
/**
* Log error msg for a certain log topic.
*/
void Logger_logTopErr(Logger* this, LogTopic logTopic, const char* context, const char* msg)
{
Logger_logTopErrFormatted(this, logTopic, context, "%s", msg);
}
#endif /*LOGGER_H_*/

View File

@@ -0,0 +1,490 @@
#ifndef COMMON_H_
#define COMMON_H_
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/sched.h> /* for TASK_COMM_LEN */
#include <linux/string.h>
#include <linux/time.h>
#include <linux/types.h>
#include <linux/version.h>
#include <linux/vmalloc.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#ifdef KERNEL_HAS_LINUX_FILELOCK_H
#include <linux/filelock.h>
#endif
#ifdef KERNEL_HAS_LINUX_STDARG_H
#include <linux/stdarg.h>
#else
#include <stdarg.h>
#endif
#include <linux/types.h>
#include <linux/stddef.h>
#include <linux/cred.h>
#include <asm/div64.h>
#ifdef KERNEL_HAS_SCHED_SIG_H
#include <linux/sched/signal.h>
#endif
#include <common/FhgfsTypes.h>
#include <os/OsDeps.h>
/**
* NOTE: These timeouts can now be overridden by the connMessagingTimeouts
* option in the configuration file. If that option is unset or set to <=0, we
* still default to these constants.
*/
#define CONN_LONG_TIMEOUT 600000
#define CONN_MEDIUM_TIMEOUT 90000
#define CONN_SHORT_TIMEOUT 30000
#ifndef MIN
#define MIN(a, b) \
( ( (a) < (b) ) ? (a) : (b) )
#endif
#ifndef MAX
#define MAX(a, b) \
( ( (a) < (b) ) ? (b) : (a) )
#endif
#define SAFE_VFREE(p) \
do{ if(p) {vfree(p); (p)=NULL;} } while(0)
#define SAFE_VFREE_NOSET(p) \
do{ if(p) vfree(p); } while(0)
#define SAFE_KFREE(p) \
do{ if(p) {kfree(p); (p)=NULL;} } while(0)
#define SAFE_KFREE_NOSET(p) \
do{ if(p) kfree(p); } while(0)
#define SAFE_DESTRUCT(p, destructor) \
do{if(p) {destructor(p); (p)=NULL;} } while(0)
#define SAFE_DESTRUCT_NOSET(p, destructor) \
do{if(p) destructor(p); } while(0)
// typically used for optional out-args
#define SAFE_ASSIGN(destPointer, sourceValue) \
do{ if(destPointer) {*(destPointer) = (sourceValue);} } while(0)
// module name
#ifndef BEEGFS_MODULE_NAME_STR
#define BEEGFS_MODULE_NAME_STR "beegfs"
#endif
#define BEEGFS_THREAD_NAME_PREFIX_STR BEEGFS_MODULE_NAME_STR "_"
// a printk-version that adds the module name and comm name
#define printk_fhgfs(levelStr, fmtStr, ...) \
printk(levelStr BEEGFS_MODULE_NAME_STR ": " "%s(%u): " fmtStr, current->comm, \
(unsigned)current->pid, ## __VA_ARGS__)
// for interrupt handling routines (does not print "current")
#define printk_fhgfs_ir(levelStr, fmtStr, ...) \
printk(levelStr BEEGFS_MODULE_NAME_STR ": " fmtStr, ## __VA_ARGS__)
// dumps stack in case of a buggy condition
#define BEEGFS_BUG_ON(condition, msgStr) \
do { \
if(unlikely(condition) ) { \
printk_fhgfs(KERN_ERR, "%s:%d: BUG: %s (dumping stack...)\n", \
__func__, __LINE__, msgStr); \
dump_stack(); \
} \
} while(0)
#ifdef LOG_DEBUG_MESSAGES
#define printk_fhgfs_debug(levelStr, fmtStr, ...) \
printk(levelStr BEEGFS_MODULE_NAME_STR ": " "%s(%u): " fmtStr, current->comm, \
(unsigned)current->pid, ## __VA_ARGS__)
#define printk_fhgfs_ir_debug(levelStr, fmtStr, ...) \
printk_fhgfs_ir(levelStr, fmtStr, ## __VA_ARGS__)
#define BEEGFS_BUG_ON_DEBUG(condition, msgStr) BEEGFS_BUG_ON(condition, msgStr)
#else // !LOG_DEBUG_MESSAGES
#define printk_fhgfs_debug(levelStr, fmtStr, ...) \
do { /* nothing */ } while(0)
#define printk_fhgfs_ir_debug(levelStr, fmtStr, ...) \
do { /* nothing */ } while(0)
#define BEEGFS_BUG_ON_DEBUG(condition, msgStr) \
do { /* nothing */ } while(0)
#endif // LOG_DEBUG_MESSAGES
#ifdef BEEGFS_OPENTK_LOG_CONN_ERRORS
#define printk_fhgfs_connerr(levelStr, fmtStr, ...) \
printk_fhgfs(levelStr, fmtStr, ## __VA_ARGS__)
#else
#define printk_fhgfs_connerr(levelStr, fmtStr, ...) /* logging of conn errors disabled */
#endif // BEEGFS_OPENTK_LOG_CONN_ERRORS
// this macro mutes warnings about unused variables
#define IGNORE_UNUSED_VARIABLE(a) do{ if( ((long)a)==1) {} } while(0)
// this macro mutes warnings about unsused variables that are only used in debug build
#ifdef BEEGFS_DEBUG
#define IGNORE_UNUSED_DEBUG_VARIABLE(a) do{ /* do nothing */ } while(0)
#else
#define IGNORE_UNUSED_DEBUG_VARIABLE(a) do{ if( ((long)a)==1) {} } while(0)
#endif
////////////////////////////////////////////////////////
/* set_fs() / get_fs() macro hackery.
*
* set_fs() and get_fs() have disappeared with Linux kernel 5.10.
* For older kernels, we employ some macros to make their use less of a hassle.
*/
////////////////////////////////////////////////////////
#define BEEGFS_CONCAT_(x, y) x ## y
#define BEEGFS_CONCAT(x, y) BEEGFS_CONCAT_(x, y)
#define BEEGFS_UNIQUE_NAME(prefix) BEEGFS_CONCAT(prefix, __LINE__)
// Lifted from Linux 5.10
#if __has_attribute(__fallthrough__)
#define BEEGFS_FALLTHROUGH __attribute__((__fallthrough__))
#else
#define BEEGFS_FALLTHROUGH do {} while (0) /* FALLTHROUGH */
#endif
/* Preprocessor hack to add statements that are executed on scope cleanup.
* A for-loop that runs exactly 1 time is misused to execute the cleanup
* statement. An assertion ensures that we didn't break from the inner loop,
* to ensure the cleanup statement is executed. */
#define BEEGFS_FOR_SCOPE_(begin_stmt, end_stmt, name) \
for (int name = 0; !name; ({BUG_ON(!name);})) \
for (begin_stmt; !name++; end_stmt)
#define BEEGFS_FOR_SCOPE(begin_stmt, end_stmt) \
BEEGFS_FOR_SCOPE_(begin_stmt, end_stmt, BEEGFS_UNIQUE_NAME(scope))
#ifdef KERNEL_HAS_GET_FS
static inline mm_segment_t BEEGFS_BEGIN_PROCESS_CONTEXT(void)
{
mm_segment_t out = get_fs();
set_fs(KERNEL_DS);
return out;
}
static inline void BEEGFS_END_PROCESS_CONTEXT(mm_segment_t *backup)
{
set_fs(*backup);
}
#define WITH_PROCESS_CONTEXT \
BEEGFS_FOR_SCOPE( \
mm_segment_t segment = BEEGFS_BEGIN_PROCESS_CONTEXT(), \
BEEGFS_END_PROCESS_CONTEXT(&segment))
#else
#define WITH_PROCESS_CONTEXT
#endif
////////////////////////////////////////////////////////
// in 4.13 wait_queue_t got renamed to wait_queue_entry_t
#if defined(KERNEL_HAS_WAIT_QUEUE_ENTRY_T)
typedef wait_queue_entry_t wait_queue_t;
#endif
#if defined(KERNEL_HAS_64BIT_TIMESTAMPS)
static inline struct timespec64 current_fs_time(struct super_block *sb)
{
struct timespec64 now;
#if defined(KERNEL_HAS_KTIME_GET_COARSE_REAL_TS64)
ktime_get_coarse_real_ts64(&now);
return now;
#elif defined(KERNEL_HAS_KTIME_GET_REAL_TS64)
ktime_get_real_ts64(&now);
return timespec64_trunc(now, sb->s_time_gran);
#else
now = current_kernel_time64();
return timespec64_trunc(now, sb->s_time_gran);
#endif
}
#elif !defined(KERNEL_HAS_CURRENT_FS_TIME)
static inline struct timespec current_fs_time(struct super_block *sb)
{
struct timespec now = current_kernel_time();
return timespec_trunc(now, sb->s_time_gran);
}
#endif
/* Defined by <linux/include/linux/uidgid.h> and already included by one of the headers, so
* no KernelFeatureDetection.mk detection required.
* Note: Not in OsCompat.h, as OsCompat depends on Common.h. */
#ifndef _LINUX_UIDGID_H
typedef unsigned kuid_t;
typedef unsigned kgid_t;
#define from_kuid(a, b) (b)
#define from_kgid(a, b) (b)
#define make_kuid(a, b) (b)
#define make_kgid(a, b) (b)
#endif
#ifndef swap
#define swap(a, b) do { typeof(a) __tmp = (a); (a) = (b); (b) = __tmp; } while (0)
#endif
#undef BEEGFS_RDMA
#ifndef BEEGFS_NO_RDMA
#if defined(CONFIG_INFINIBAND) || defined(CONFIG_INFINIBAND_MODULE)
#define BEEGFS_RDMA 1
#endif
#endif
static inline unsigned FhgfsCommon_getCurrentUserID(void);
static inline unsigned FhgfsCommon_getCurrentGroupID(void);
unsigned FhgfsCommon_getCurrentUserID(void)
{
return from_kuid(&init_user_ns, current_fsuid());
}
unsigned FhgfsCommon_getCurrentGroupID(void)
{
return from_kgid(&init_user_ns, current_fsgid());
}
// Helper function for getting file pointer
static inline struct file * FhgfsCommon_getFileLock(struct file_lock *fileLock)
{
#if defined(KERNEL_HAS_FILE_LOCK_CORE)
return fileLock->c.flc_file;
#else
return fileLock->fl_file;
#endif
}
// Helper function to get PID from file lock
static inline pid_t FhgfsCommon_getFileLockPID(struct file_lock *fileLock)
{
#if defined(KERNEL_HAS_FILE_LOCK_CORE)
return fileLock->c.flc_pid;
#else
return fileLock->fl_pid;
#endif
}
// Helper function to get lock type
static inline unsigned char FhgfsCommon_getFileLockType(struct file_lock *flock)
{
#if defined(KERNEL_HAS_FILE_LOCK_CORE)
return flock->c.flc_type;
#else
return flock->fl_type;
#endif
}
// Helper function to get lock flags
static inline unsigned int FhgfsCommon_getFileLockFlags(struct file_lock *fileLock)
{
#if defined(KERNEL_HAS_FILE_LOCK_CORE)
return fileLock->c.flc_flags;
#else
return fileLock->fl_flags;
#endif
}
/*
* Debug definitions:
* - LOG_DEBUG_MESSAGES: Enables logging of some extra debug messages that will not be
* available otherwise.
* - DEBUG_REFCOUNT: Enables debugging of ObjectReferencer::refCount. Error messages will
* be logged if refCount is less than zero.
*/
/**
* BEEGFS_KFREE_LIST() - destroys and kfree()s all element of a list, leaving an empty list
*
* expands to ``BEEGFS_KFREE_LIST_DTOR(List, ElemType, Member, (void))``, ie no destructor is
* called.
*/
#define BEEGFS_KFREE_LIST(List, ElemType, Member) \
BEEGFS_KFREE_LIST_DTOR(List, ElemType, Member, (void))
/**
* BEEGFS_KFREE_LIST_DTOR() - destroys and kfree()s all element of a list, leaving an empty list
* @List the &struct list_head to free
* @ElemType type of elements contained in the list
* @Member name of the &struct list_head in @ElemType that links to the next element of the list
* @Dtor for each element of the list, ``Dtor(entry)`` is evaluated before the entry is freed
*/
#define BEEGFS_KFREE_LIST_DTOR(List, ElemType, Member, Dtor) \
do { \
ElemType* entry; \
ElemType* n; \
list_for_each_entry_safe(entry, n, List, Member) \
{ \
Dtor(entry); \
kfree(entry); \
} \
INIT_LIST_HEAD(List); \
} while (0)
/**
* Generic key comparison function for integer types and pointers, to be used by the
* RBTREE_FUNCTIONS as KeyCmp.
*/
#define BEEGFS_RB_KEYCMP_LT_INTEGRAL(lhs, rhs) \
( lhs < rhs ? -1 : (lhs == rhs ? 0 : 1) )
/**
* BEEGFS_KFREE_RBTREE() - destroys and kfree()s all elements an rbtree
*
* expands to ``BEEGFS_KFREE_RBTREE_DTOR(TreeRoot, ElemType, Member, (void))``, ie no destructor is
* called.
*/
#define BEEGFS_KFREE_RBTREE(TreeRoot, ElemType, Member) \
BEEGFS_KFREE_RBTREE_DTOR(TreeRoot, ElemType, Member, (void))
/**
* BEEGFS_KFREE_RBTREE_DTOR() - destroys and kfree()s all elements an rbtree, leaving an empty tree
* @TreeRoot &struct rb_root to free
* @ElemType type of elements contained in the tree
* @Member name of the &struct rb_node in @ElemType that links to further entries in the tree
* @Dtor for each element of the tree, ``Dtor(elem)`` is evaluated before the entry is freed
*/
#define BEEGFS_KFREE_RBTREE_DTOR(TreeRoot, ElemType, Member, Dtor) \
do { \
ElemType* pos; \
ElemType* n; \
rbtree_postorder_for_each_entry_safe(pos, n, TreeRoot, Member) \
{ \
Dtor(pos); \
kfree(pos); \
} \
*(TreeRoot) = RB_ROOT; \
} while (0)
/**
* BEEGFS_RBTREE_FUNCTIONS() - defines a default set of rbtree functions
* @Access access modifier of generated functions
* @NS namespace prefix for all defined functions
* @RootTy type of the struct that contains the tree we are building functions for
* @RootNode name of the &struct rb_root of our tree in @RootTy
* @KeyTy type of the trees sort key
* @ElemTy type of the tree element. must contain a field of type @KeyTy
* @ElemKey name of the key member in @ElemTy (must be of type @KeyTy)
* @ElemNode node of the &struct rb_node of our tree in @ElemTy
* @KeyCmp function or macro used to compare to @KeyTy values for tree ordering
*
* This macro declares a number of functions with names prefixed by @NS:
*
* * ``Access ElemTy* NS##_find(const RootTy*, KeyTy key)`` finds the @ElemTy with key ``key`` and
* returns it. If none exists, %NULL is returned.
* * ``Access bool NS##_insert(RootTy*, ElemTy* data)`` inserts the element ``data`` into the tree
* if no element with the same key exists and return %true. If an element with the same key does
* exist, returns %false.
* * ``Access ElemTy* NS##_insertOrReplace(RootTy*, ElemTy* data)`` inserts ``data`` into the tree
* if no element with the same key exists or replaced the existing item with the same key. If no
* item existed %NULL is returned, otherwise the pointer to the previous element is returned.
* This is analogous to how std::map::operator[] works in C++.
* * ``access void NS##_erase(RootTy*, ElemTy* data)`` removes ``data`` from the tree. ``data`` is
* not freed or otherwise processed, this function only removes the item and rebalances the tree
* if necessary.
*/
#define BEEGFS_RBTREE_FUNCTIONS(Access, NS, RootTy, RootNode, KeyTy, ElemTy, ElemKey, ElemNode, \
KeyCmp) \
__attribute__((unused)) \
Access ElemTy* NS##_find(const RootTy* root, KeyTy key) \
{ \
struct rb_node* node = root->RootNode.rb_node; \
while (node) \
{ \
ElemTy* data = rb_entry(node, ElemTy, ElemNode); \
int cmp = KeyCmp(key, data->ElemKey); \
\
if (cmp < 0) \
node = node->rb_left; \
else if (cmp > 0) \
node = node->rb_right; \
else \
return data; \
} \
return NULL; \
} \
__attribute__((unused)) \
Access bool NS##_insert(RootTy* root, ElemTy* data) \
{ \
struct rb_node** new = &root->RootNode.rb_node; \
struct rb_node* parent = NULL; \
while (*new) \
{ \
ElemTy* cur = container_of(*new, ElemTy, ElemNode); \
int cmp = KeyCmp(data->ElemKey, cur->ElemKey); \
\
parent = *new; \
if (cmp < 0) \
new = &(*new)->rb_left; \
else if (cmp > 0) \
new = &(*new)->rb_right; \
else \
return false; \
} \
rb_link_node(&data->ElemNode, parent, new); \
rb_insert_color(&data->ElemNode, &root->RootNode); \
return true; \
} \
__attribute__((unused)) \
Access ElemTy* NS##_insertOrReplace(RootTy* root, ElemTy* data) \
{ \
ElemTy* existing; \
if (NS##_insert(root, data)) \
return NULL; \
\
existing = NS##_find(root, data->ElemKey); \
rb_replace_node(&existing->ElemNode, &data->ElemNode, &root->RootNode); \
return existing; \
} \
__attribute__((unused)) \
Access void NS##_erase(RootTy* root, ElemTy* data) \
{ \
rb_erase(&data->ElemNode, &root->RootNode); \
}
#define BEEGFS_RBTREE_FOR_EACH_ENTRY(Pos, Root, Node) \
for (Pos = rb_entry_safe(rb_first(Root), typeof(*Pos), Node); \
Pos; \
Pos = rb_entry_safe(rb_next(&Pos->Node), typeof(*Pos), Node))
/* version number of both the network protocol and the on-disk data structures that are versioned.
* must be kept in sync with userspace. */
#define BEEGFS_DATA_VERSION ((uint32_t)0)
#endif /*COMMON_H_*/

View File

@@ -0,0 +1,35 @@
#ifndef OPEN_FHGFSTYPES_H_
#define OPEN_FHGFSTYPES_H_
#include <linux/in.h>
#include <linux/time.h>
#include <common/toolkit/Time.h>
struct fhgfs_sockaddr_in
{
struct in_addr addr;
__be16 port;
};
typedef struct fhgfs_sockaddr_in fhgfs_sockaddr_in;
struct fhgfs_stat
{
umode_t mode;
unsigned int nlink;
uid_t uid;
gid_t gid;
loff_t size;
uint64_t blocks;
Time atime;
Time mtime;
Time ctime; // attrib change time (not creation time)
unsigned int metaVersion;
};
typedef struct fhgfs_stat fhgfs_stat;
#endif /* OPEN_FHGFSTYPES_H_ */

View File

@@ -0,0 +1,30 @@
#include "Types.h"
SERDES_DEFINE_SERIALIZERS_SIMPLE(, TargetMapping, struct TargetMapping,
(targetID, , Serialization, UShort),
(nodeID, &, NumNodeID, ))
SERDES_DEFINE_LIST_SERIALIZERS(, TargetMappingList, struct TargetMapping,
TargetMapping, (void), _list, false)
SERDES_DEFINE_SERIALIZERS_SIMPLE(, TargetPoolMapping, struct TargetPoolMapping,
(targetID, , Serialization, UShort),
(poolID, &, StoragePoolId, ))
SERDES_DEFINE_LIST_SERIALIZERS(, TargetPoolMappingList, struct TargetPoolMapping,
TargetPoolMapping, (void), _list, false)
SERDES_DEFINE_SERIALIZERS_SIMPLE(, BuddyGroupMapping, struct BuddyGroupMapping,
(groupID, , Serialization, UShort),
(primaryTargetID, , Serialization, UShort),
(secondaryTargetID, , Serialization, UShort))
SERDES_DEFINE_LIST_SERIALIZERS(, BuddyGroupMappingList, struct BuddyGroupMapping,
BuddyGroupMapping, (void), _list, false)
SERDES_DEFINE_SERIALIZERS_SIMPLE(, TargetStateMapping, struct TargetStateMapping,
(targetID, , Serialization, UShort),
(reachabilityState, , TargetReachabilityState, ),
(consistencyState, , TargetConsistencyState, ))
SERDES_DEFINE_LIST_SERIALIZERS(, TargetStateMappingList, struct TargetStateMapping,
TargetStateMapping, (void), _list, false)

View File

@@ -0,0 +1,105 @@
#ifndef BEEGFS_TYPES_H_
#define BEEGFS_TYPES_H_
#include <common/storage/StoragePoolId.h>
#include <common/toolkit/Serialization.h>
struct TargetMapping
{
uint16_t targetID;
NumNodeID nodeID;
/* private: */
union {
struct rb_node _node; /* for use by TargetMapper */
struct list_head _list; /* for use by de/serialized lists */
};
};
SERDES_DECLARE_SERIALIZERS(TargetMapping, struct TargetMapping)
SERDES_DECLARE_LIST_SERIALIZERS(TargetMappingList, struct TargetMapping)
/* make sure to keep this in sync with TargetState in common lib */
enum TargetReachabilityState
{
TargetReachabilityState_ONLINE,
TargetReachabilityState_POFFLINE, // probably offline
TargetReachabilityState_OFFLINE
};
typedef enum TargetReachabilityState TargetReachabilityState;
SERDES_DEFINE_ENUM_SERIALIZERS(TargetReachabilityState, enum TargetReachabilityState,
uint8_t, UInt8)
enum TargetConsistencyState
{
TargetConsistencyState_GOOD,
TargetConsistencyState_NEEDS_RESYNC,
TargetConsistencyState_BAD
};
typedef enum TargetConsistencyState TargetConsistencyState;
SERDES_DEFINE_ENUM_SERIALIZERS(TargetConsistencyState, enum TargetConsistencyState, uint8_t, UInt8)
struct CombinedTargetState
{
TargetReachabilityState reachabilityState;
TargetConsistencyState consistencyState;
};
typedef struct CombinedTargetState CombinedTargetState;
struct TargetStateInfo
{
uint16_t targetID;
struct CombinedTargetState state;
/* private */
struct rb_node _node;
};
typedef struct TargetStateInfo TargetStateInfo;
struct TargetPoolMapping
{
uint16_t targetID;
StoragePoolId poolID;
/* private: */
struct list_head _list; /* for de/serialized lists */
};
SERDES_DECLARE_SERIALIZERS(TargetPoolMapping, struct TargetPoolMapping)
SERDES_DECLARE_LIST_SERIALIZERS(TargetPoolMappingList, struct TargetPoolMapping)
struct BuddyGroupMapping
{
uint16_t groupID;
uint16_t primaryTargetID;
uint16_t secondaryTargetID;
/* private: */
struct list_head _list; /* for de/serialized lists */
};
SERDES_DECLARE_SERIALIZERS(BuddyGroupMapping, struct BuddyGroupMapping)
SERDES_DECLARE_LIST_SERIALIZERS(BuddyGroupMappingList, struct BuddyGroupMapping)
struct TargetStateMapping
{
uint16_t targetID;
TargetReachabilityState reachabilityState;
TargetConsistencyState consistencyState;
/* private: */
struct list_head _list; /* for de/serialized lists */
};
SERDES_DECLARE_SERIALIZERS(TargetStateMapping, struct TargetStateMapping)
SERDES_DECLARE_LIST_SERIALIZERS(TargetStateMappingList, struct TargetStateMapping)
#endif

View File

@@ -0,0 +1,149 @@
#include "NetMessage.h"
/**
* Processes this message.
*
* Note: Some messages might be received over a datagram socket, so the response
* must be atomic (=> only a single sendto()-call)
*
* @param fromAddr must be NULL for stream sockets
* @return false on error
*/
bool NetMessage_processIncoming(NetMessage* this, struct App* app,
fhgfs_sockaddr_in* fromAddr, struct Socket* sock, char* respBuf, size_t bufLen)
{
// Note: Has to be implemented appropriately by derived classes.
// Empty implementation provided here for invalid messages and other messages
// that don't require this way of processing (e.g. some response messages).
return false;
}
/**
* Returns all feature flags that are supported by this message. Defaults to "none", so this
* method needs to be overridden by derived messages that actually support header feature
* flags.
*
* @return combination of all supported feature flags
*/
unsigned NetMessage_getSupportedHeaderFeatureFlagsMask(NetMessage* this)
{
return 0;
}
/**
* Reads the (common) header part of a message from a buffer.
*
* Note: Message type will be set to NETMSGTYPE_Invalid if deserialization fails.
*/
void __NetMessage_deserializeHeader(DeserializeCtx* ctx, NetMessageHeader* outHeader)
{
size_t totalLength = ctx->length;
uint64_t prefix = 0;
// check min buffer length
if(unlikely(ctx->length < NETMSG_HEADER_LENGTH) )
{
outHeader->msgType = NETMSGTYPE_Invalid;
return;
}
// message length
Serialization_deserializeUInt(ctx, &outHeader->msgLength);
// verify contained msg length
if(unlikely(outHeader->msgLength != totalLength) )
{
outHeader->msgType = NETMSGTYPE_Invalid;
return;
}
// feature flags
Serialization_deserializeUShort(ctx, &outHeader->msgFeatureFlags);
Serialization_deserializeUInt8(ctx, &outHeader->msgCompatFeatureFlags);
Serialization_deserializeUInt8(ctx, &outHeader->msgFlags);
// check message prefix
Serialization_deserializeUInt64(ctx, &prefix);
if (prefix != NETMSG_PREFIX)
{
outHeader->msgType = NETMSGTYPE_Invalid;
return;
}
if (outHeader->msgFlags & ~(MSGHDRFLAG_BUDDYMIRROR_SECOND | MSGHDRFLAG_IS_SELECTIVE_ACK |
MSGHDRFLAG_HAS_SEQUENCE_NO))
{
outHeader->msgType = NETMSGTYPE_Invalid;
return;
}
// message type
Serialization_deserializeUShort(ctx, &outHeader->msgType);
// targetID
Serialization_deserializeUShort(ctx, &outHeader->msgTargetID);
// userID
Serialization_deserializeUInt(ctx, &outHeader->msgUserID);
Serialization_deserializeUInt64(ctx, &outHeader->msgSequence);
Serialization_deserializeUInt64(ctx, &outHeader->msgSequenceDone);
}
/**
* Writes the (common) header part of a message to a buffer.
*
* Note the min required size for the buf parameter! Message-specific data can be stored
* from &buf[NETMSG_HEADER_LENGTH] on.
* The msg->msgPrefix field is ignored and will always be stored correctly in the buffer.
*
* @param buf min size is NETMSG_HEADER_LENGTH
* @return false on error (e.g. bufLen too small), true otherwise
*/
void __NetMessage_serializeHeader(NetMessage* this, SerializeCtx* ctx, bool zeroLengthField)
{
// message length
Serialization_serializeUInt(ctx, zeroLengthField ? 0 : NetMessage_getMsgLength(this) );
// feature flags
Serialization_serializeUShort(ctx, this->msgHeader.msgFeatureFlags);
Serialization_serializeChar(ctx, this->msgHeader.msgCompatFeatureFlags);
Serialization_serializeChar(ctx, this->msgHeader.msgFlags);
// message prefix
Serialization_serializeUInt64(ctx, NETMSG_PREFIX);
// message type
Serialization_serializeUShort(ctx, this->msgHeader.msgType);
// targetID
Serialization_serializeUShort(ctx, this->msgHeader.msgTargetID);
// userID
Serialization_serializeUInt(ctx, this->msgHeader.msgUserID);
Serialization_serializeUInt64(ctx, this->msgHeader.msgSequence);
Serialization_serializeUInt64(ctx, this->msgHeader.msgSequenceDone);
}
/**
* Dummy function for deserialize pointers
*/
bool _NetMessage_deserializeDummy(NetMessage* this, DeserializeCtx* ctx)
{
printk_fhgfs(KERN_INFO, "Bug: Deserialize function called, although it should not\n");
dump_stack();
return true;
}
/**
* Dummy function for serialize pointers
*/
void _NetMessage_serializeDummy(NetMessage* this, SerializeCtx* ctx)
{
printk_fhgfs(KERN_INFO, "Bug: Serialize function called, although it should not\n");
dump_stack();
}

View File

@@ -0,0 +1,259 @@
#ifndef NETMESSAGE_H_
#define NETMESSAGE_H_
#include <common/net/sock/NetworkInterfaceCard.h>
#include <common/net/sock/Socket.h>
#include <common/toolkit/Serialization.h>
#include <common/Common.h>
#include "NetMessageTypes.h"
/**
* Note: This "class" is not meant to be instantiated directly (consider it to be abstract).
* It contains some "virtual" methods, as you can see in the struct NetMessage. Only the virtual
* Method processIncoming(..) has a default implementation.
* Derived classes have a destructor with a NetMessage-Pointer (instead of the real type)
* because of the generic virtual destructor signature.
* Derived classes normally have two constructors: One has no arguments and is used for
* deserialization. The other one is the standard constructor.
*/
// common message constants
// ========================
#define NETMSG_PREFIX ((0x42474653ULL << 32) + BEEGFS_DATA_VERSION)
#define NETMSG_MIN_LENGTH NETMSG_HEADER_LENGTH
#define NETMSG_HEADER_LENGTH 40 /* length of the header (see struct NetMessageHeader) */
#define NETMSG_MAX_MSG_SIZE 65536 // 64kB
#define NETMSG_MAX_PAYLOAD_SIZE ((unsigned)(NETMSG_MAX_MSG_SIZE - NETMSG_HEADER_LENGTH))
#define NETMSG_DEFAULT_USERID (~0) // non-zero to avoid mixing up with root userID
// forward declaration
struct App;
struct NetMessageHeader;
typedef struct NetMessageHeader NetMessageHeader;
struct NetMessage;
typedef struct NetMessage NetMessage;
struct NetMessageOps;
static inline void NETMESSAGE_FREE(NetMessage* this);
static inline void NetMessage_init(NetMessage* this, unsigned short msgType,
const struct NetMessageOps* ops);
extern void __NetMessage_deserializeHeader(DeserializeCtx* ctx, struct NetMessageHeader* outHeader);
extern void __NetMessage_serializeHeader(NetMessage* this, SerializeCtx* ctx, bool zeroLengthField);
extern void _NetMessage_serializeDummy(NetMessage* this, SerializeCtx* ctx);
extern bool _NetMessage_deserializeDummy(NetMessage* this, DeserializeCtx* ctx);
static inline unsigned NetMessage_extractMsgLengthFromBuf(const char* recvBuf);
static inline bool NetMessage_serialize(NetMessage* this, char* buf, size_t bufLen);
static inline bool NetMessage_checkHeaderFeatureFlagsCompat(NetMessage* this);
// virtual functions
extern bool NetMessage_processIncoming(NetMessage* this, struct App* app,
fhgfs_sockaddr_in* fromAddr, struct Socket* sock, char* respBuf, size_t bufLen);
extern unsigned NetMessage_getSupportedHeaderFeatureFlagsMask(NetMessage* this);
// getters & setters
static inline unsigned short NetMessage_getMsgType(NetMessage* this);
static inline unsigned NetMessage_getMsgHeaderFeatureFlags(NetMessage* this);
static inline bool NetMessage_isMsgHeaderFeatureFlagSet(NetMessage* this, unsigned flag);
static inline void NetMessage_addMsgHeaderFeatureFlag(NetMessage* this, unsigned flag);
static inline unsigned NetMessage_getMsgLength(NetMessage* this);
static inline void NetMessage_setMsgHeaderUserID(NetMessage* this, unsigned userID);
static inline void NetMessage_setMsgHeaderTargetID(NetMessage* this, uint16_t userID);
static inline void _NetMessage_setMsgType(NetMessage* this, unsigned short msgType);
#define MSGHDRFLAG_BUDDYMIRROR_SECOND (0x01)
#define MSGHDRFLAG_IS_SELECTIVE_ACK (0x02)
#define MSGHDRFLAG_HAS_SEQUENCE_NO (0x04)
struct NetMessageHeader
{
unsigned msgLength; // in bytes
uint16_t msgFeatureFlags; // feature flags for derived messages (depend on msgType)
uint8_t msgCompatFeatureFlags; /* for derived messages, similar to msgFeatureFlags, but
"compat" because there is no check whether receiver
understands these flags, so they might be ignored. */
uint8_t msgFlags;
// char* msgPrefix; // NETMSG_PREFIX_STR (8 bytes)
unsigned short msgType; // the type of payload, defined as NETMSGTYPE_x
uint16_t msgTargetID; // targetID (not groupID) for per-target workers on storage server
unsigned msgUserID; // system user ID for per-user msg queues, stats etc.
uint64_t msgSequence; // for retries, 0 if not present
uint64_t msgSequenceDone; // a sequence number that has been fully processed, or 0
};
struct NetMessageOps
{
void (*serializePayload) (NetMessage* this, SerializeCtx* ctx);
bool (*deserializePayload) (NetMessage* this, DeserializeCtx* ctx);
bool (*processIncoming) (NetMessage* this, struct App* app, fhgfs_sockaddr_in* fromAddr,
struct Socket* sock, char* respBuf, size_t bufLen);
unsigned (*getSupportedHeaderFeatureFlagsMask) (NetMessage* this);
void (*release)(NetMessage* this);
// not strictly operations, but these are common to all messages and do not warrant their own
// functions
bool supportsSequenceNumbers;
};
struct NetMessage
{
struct NetMessageHeader msgHeader;
const struct NetMessageOps* ops;
};
void NetMessage_init(NetMessage* this, unsigned short msgType, const struct NetMessageOps* ops)
{
memset(this, 0, sizeof(*this) ); // clear function pointers etc.
// this->msgLength = 0; // zero'ed by memset
// this->msgFeatureFlags = 0; // zero'ed by memset
this->msgHeader.msgType = msgType;
// needs to be set to actual ID by some async flushers etc
this->msgHeader.msgUserID = FhgfsCommon_getCurrentUserID();
// this->msgTargetID = 0; // zero'ed by memset
this->ops = ops;
}
#define NETMESSAGE_CONSTRUCT(TYPE) \
({ \
TYPE* msg = os_kmalloc(sizeof(TYPE)); \
TYPE##_init(msg); \
(NetMessage*)msg; \
})
static inline void NETMESSAGE_FREE(NetMessage* msg)
{
if (msg->ops->release)
msg->ops->release(msg);
kfree(msg);
}
/**
* recvBuf must be at least NETMSG_MIN_LENGTH long
*/
unsigned NetMessage_extractMsgLengthFromBuf(const char* recvBuf)
{
unsigned msgLength;
DeserializeCtx ctx = { recvBuf, sizeof(msgLength) };
Serialization_deserializeUInt(&ctx, &msgLength);
return msgLength;
}
bool NetMessage_serialize(NetMessage* this, char* buf, size_t bufLen)
{
SerializeCtx ctx = {
.data = buf,
};
if(unlikely(bufLen < NetMessage_getMsgLength(this) ) )
return false;
__NetMessage_serializeHeader(this, &ctx, false);
this->ops->serializePayload(this, &ctx);
return true;
}
/**
* Check if the msg sender has set an incompatible feature flag.
*
* @return false if an incompatible feature flag was set
*/
bool NetMessage_checkHeaderFeatureFlagsCompat(NetMessage* this)
{
unsigned unsupportedFlags = ~(this->ops->getSupportedHeaderFeatureFlagsMask(this) );
if(unlikely(this->msgHeader.msgFeatureFlags & unsupportedFlags) )
return false; // an unsupported flag was set
return true;
}
unsigned short NetMessage_getMsgType(NetMessage* this)
{
return this->msgHeader.msgType;
}
unsigned NetMessage_getMsgHeaderFeatureFlags(NetMessage* this)
{
return this->msgHeader.msgFeatureFlags;
}
/**
* Test flag. (For convenience and readability.)
*
* @return true if given flag is set.
*/
bool NetMessage_isMsgHeaderFeatureFlagSet(NetMessage* this, unsigned flag)
{
return (this->msgHeader.msgFeatureFlags & flag) != 0;
}
/**
* Add another flag without clearing the previously set flags.
*
* Note: The receiver will reject this message if it doesn't know the given feature flag.
*/
void NetMessage_addMsgHeaderFeatureFlag(NetMessage* this, unsigned flag)
{
this->msgHeader.msgFeatureFlags |= flag;
}
unsigned NetMessage_getMsgLength(NetMessage* this)
{
if(!this->msgHeader.msgLength)
{
SerializeCtx ctx = { NULL, 0 };
__NetMessage_serializeHeader(this, &ctx, true);
this->ops->serializePayload(this, &ctx);
this->msgHeader.msgLength = ctx.length;
}
return this->msgHeader.msgLength;
}
void NetMessage_setMsgHeaderUserID(NetMessage* this, unsigned userID)
{
this->msgHeader.msgUserID = userID;
}
/**
* @param targetID this has to be an actual targetID (not a groupID).
*/
void NetMessage_setMsgHeaderTargetID(NetMessage* this, uint16_t targetID)
{
this->msgHeader.msgTargetID = targetID;
}
void _NetMessage_setMsgType(NetMessage* this, unsigned short msgType)
{
this->msgHeader.msgType = msgType;
}
#endif /*NETMESSAGE_H_*/

View File

@@ -0,0 +1,273 @@
#ifndef NETMESSAGETYPES_H_
#define NETMESSAGETYPES_H_
/* This file MUST be kept in sync with the corresponding fhgfs_common file!
See fhgfs_common/source/common/net/message/NetMessageTypes.h */
// invalid messages
#define NETMSGTYPE_Invalid 0
// nodes messages
#define NETMSGTYPE_RemoveNode 1013
#define NETMSGTYPE_RemoveNodeResp 1014
#define NETMSGTYPE_GetNodes 1017
#define NETMSGTYPE_GetNodesResp 1018
#define NETMSGTYPE_HeartbeatRequest 1019
#define NETMSGTYPE_Heartbeat 1020
#define NETMSGTYPE_GetNodeCapacityPools 1021
#define NETMSGTYPE_GetNodeCapacityPoolsResp 1022
#define NETMSGTYPE_MapTargets 1023
#define NETMSGTYPE_MapTargetsResp 1024
#define NETMSGTYPE_GetTargetMappings 1025
#define NETMSGTYPE_GetTargetMappingsResp 1026
#define NETMSGTYPE_UnmapTarget 1027
#define NETMSGTYPE_UnmapTargetResp 1028
#define NETMSGTYPE_GenericDebug 1029
#define NETMSGTYPE_GenericDebugResp 1030
#define NETMSGTYPE_GetClientStats 1031
#define NETMSGTYPE_GetClientStatsResp 1032
#define NETMSGTYPE_RefreshCapacityPools 1035
#define NETMSGTYPE_StorageBenchControlMsg 1037
#define NETMSGTYPE_StorageBenchControlMsgResp 1038
#define NETMSGTYPE_RegisterNode 1039
#define NETMSGTYPE_RegisterNodeResp 1040
#define NETMSGTYPE_RegisterTarget 1041
#define NETMSGTYPE_RegisterTargetResp 1042
#define NETMSGTYPE_SetMirrorBuddyGroup 1045
#define NETMSGTYPE_SetMirrorBuddyGroupResp 1046
#define NETMSGTYPE_GetMirrorBuddyGroups 1047
#define NETMSGTYPE_GetMirrorBuddyGroupsResp 1048
#define NETMSGTYPE_GetTargetStates 1049
#define NETMSGTYPE_GetTargetStatesResp 1050
#define NETMSGTYPE_RefreshTargetStates 1051
#define NETMSGTYPE_GetStatesAndBuddyGroups 1053
#define NETMSGTYPE_GetStatesAndBuddyGroupsResp 1054
#define NETMSGTYPE_SetTargetConsistencyStates 1055
#define NETMSGTYPE_SetTargetConsistencyStatesResp 1056
#define NETMSGTYPE_ChangeTargetConsistencyStates 1057
#define NETMSGTYPE_ChangeTargetConsistencyStatesResp 1058
#define NETMSGTYPE_PublishCapacities 1059
#define NETMSGTYPE_RemoveBuddyGroup 1060
#define NETMSGTYPE_RemoveBuddyGroupResp 1061
#define NETMSGTYPE_GetTargetConsistencyStates 1062
#define NETMSGTYPE_GetTargetConsistencyStatesResp 1063
// storage messages
#define NETMSGTYPE_MkDir 2001
#define NETMSGTYPE_MkDirResp 2002
#define NETMSGTYPE_RmDir 2003
#define NETMSGTYPE_RmDirResp 2004
#define NETMSGTYPE_MkFile 2005
#define NETMSGTYPE_MkFileResp 2006
#define NETMSGTYPE_UnlinkFile 2007
#define NETMSGTYPE_UnlinkFileResp 2008
#define NETMSGTYPE_UnlinkLocalFile 2011
#define NETMSGTYPE_UnlinkLocalFileResp 2012
#define NETMSGTYPE_Stat 2015
#define NETMSGTYPE_StatResp 2016
#define NETMSGTYPE_GetChunkFileAttribs 2017
#define NETMSGTYPE_GetChunkFileAttribsResp 2018
#define NETMSGTYPE_TruncFile 2019
#define NETMSGTYPE_TruncFileResp 2020
#define NETMSGTYPE_TruncLocalFile 2021
#define NETMSGTYPE_TruncLocalFileResp 2022
#define NETMSGTYPE_Rename 2023
#define NETMSGTYPE_RenameResp 2024
#define NETMSGTYPE_SetAttr 2025
#define NETMSGTYPE_SetAttrResp 2026
#define NETMSGTYPE_ListDirFromOffset 2029
#define NETMSGTYPE_ListDirFromOffsetResp 2030
#define NETMSGTYPE_StatStoragePath 2031
#define NETMSGTYPE_StatStoragePathResp 2032
#define NETMSGTYPE_SetLocalAttr 2033
#define NETMSGTYPE_SetLocalAttrResp 2034
#define NETMSGTYPE_FindOwner 2035
#define NETMSGTYPE_FindOwnerResp 2036
#define NETMSGTYPE_MkLocalDir 2037
#define NETMSGTYPE_MkLocalDirResp 2038
#define NETMSGTYPE_RmLocalDir 2039
#define NETMSGTYPE_RmLocalDirResp 2040
#define NETMSGTYPE_MovingFileInsert 2041
#define NETMSGTYPE_MovingFileInsertResp 2042
#define NETMSGTYPE_MovingDirInsert 2043
#define NETMSGTYPE_MovingDirInsertResp 2044
#define NETMSGTYPE_GetEntryInfo 2045
#define NETMSGTYPE_GetEntryInfoResp 2046
#define NETMSGTYPE_SetDirPattern 2047
#define NETMSGTYPE_SetDirPatternResp 2048
#define NETMSGTYPE_GetHighResStats 2051
#define NETMSGTYPE_GetHighResStatsResp 2052
#define NETMSGTYPE_MkFileWithPattern 2053
#define NETMSGTYPE_MkFileWithPatternResp 2054
#define NETMSGTYPE_RefreshEntryInfo 2055
#define NETMSGTYPE_RefreshEntryInfoResp 2056
#define NETMSGTYPE_RmDirEntry 2057
#define NETMSGTYPE_RmDirEntryResp 2058
#define NETMSGTYPE_LookupIntent 2059
#define NETMSGTYPE_LookupIntentResp 2060
#define NETMSGTYPE_FindLinkOwner 2063
#define NETMSGTYPE_FindLinkOwnerResp 2064
#define NETMSGTYPE_MirrorMetadata 2067
#define NETMSGTYPE_MirrorMetadataResp 2068
#define NETMSGTYPE_SetMetadataMirroring 2069
#define NETMSGTYPE_SetMetadataMirroringResp 2070
#define NETMSGTYPE_Hardlink 2071
#define NETMSGTYPE_HardlinkResp 2072
#define NETMSGTYPE_SetQuota 2075
#define NETMSGTYPE_SetQuotaResp 2076
#define NETMSGTYPE_SetExceededQuota 2077
#define NETMSGTYPE_SetExceededQuotaResp 2078
#define NETMSGTYPE_RequestExceededQuota 2079
#define NETMSGTYPE_RequestExceededQuotaResp 2080
#define NETMSGTYPE_UpdateDirParent 2081
#define NETMSGTYPE_UpdateDirParentResp 2082
#define NETMSGTYPE_ResyncLocalFile 2083
#define NETMSGTYPE_ResyncLocalFileResp 2084
#define NETMSGTYPE_StartStorageTargetResync 2085
#define NETMSGTYPE_StartStorageTargetResyncResp 2086
#define NETMSGTYPE_StorageResyncStarted 2087
#define NETMSGTYPE_StorageResyncStartedResp 2088
#define NETMSGTYPE_ListChunkDirIncremental 2089
#define NETMSGTYPE_ListChunkDirIncrementalResp 2090
#define NETMSGTYPE_RmChunkPaths 2091
#define NETMSGTYPE_RmChunkPathsResp 2092
#define NETMSGTYPE_GetStorageResyncStats 2093
#define NETMSGTYPE_GetStorageResyncStatsResp 2094
#define NETMSGTYPE_SetLastBuddyCommOverride 2095
#define NETMSGTYPE_SetLastBuddyCommOverrideResp 2096
#define NETMSGTYPE_GetQuotaInfo 2097
#define NETMSGTYPE_GetQuotaInfoResp 2098
#define NETMSGTYPE_SetStorageTargetInfo 2099
#define NETMSGTYPE_SetStorageTargetInfoResp 2100
#define NETMSGTYPE_ListXAttr 2101
#define NETMSGTYPE_ListXAttrResp 2102
#define NETMSGTYPE_GetXAttr 2103
#define NETMSGTYPE_GetXAttrResp 2104
#define NETMSGTYPE_RemoveXAttr 2105
#define NETMSGTYPE_RemoveXAttrResp 2106
#define NETMSGTYPE_SetXAttr 2107
#define NETMSGTYPE_SetXAttrResp 2108
#define NETMSGTYPE_GetDefaultQuota 2109
#define NETMSGTYPE_GetDefaultQuotaResp 2110
#define NETMSGTYPE_SetDefaultQuota 2111
#define NETMSGTYPE_SetDefaultQuotaResp 2112
#define NETMSGTYPE_ResyncSessionStore 2113
#define NETMSGTYPE_ResyncSessionStoreResp 2114
#define NETMSGTYPE_ResyncRawInodes 2115
#define NETMSGTYPE_ResyncRawInodesResp 2116
#define NETMSGTYPE_GetMetaResyncStats 2117
#define NETMSGTYPE_GetMetaResyncStatsResp 2118
#define NETMSGTYPE_MoveFileInode 2119
#define NETMSGTYPE_MoveFileInodeResp 2120
#define NETMSGTYPE_UnlinkLocalFileInode 2121
#define NETMSGTYPE_UnlinkLocalFileInodeResp 2122
#define NETMSGTYPE_SetFilePattern 2123
#define NETMSGTYPE_SetFilePatternResp 2124
#define NETMSGTYPE_CpChunkPaths 2125
#define NETMSGTYPE_CpChunkPathsResp 2126
#define NETMSGTYPE_ChunkBalance 2127
#define NETMSGTYPE_ChunkBalanceResp 2128
#define NETMSGTYPE_StripePatternUpdate 2129
#define NETMSGTYPE_StripePatternUpdateResp 2130
#define NETMSGTYPE_SetFileState 2131
#define NETMSGTYPE_SetFileStateResp 2132
// session messages
#define NETMSGTYPE_OpenFile 3001
#define NETMSGTYPE_OpenFileResp 3002
#define NETMSGTYPE_CloseFile 3003
#define NETMSGTYPE_CloseFileResp 3004
#define NETMSGTYPE_OpenLocalFile 3005
#define NETMSGTYPE_OpenLocalFileResp 3006
#define NETMSGTYPE_CloseChunkFile 3007
#define NETMSGTYPE_CloseChunkFileResp 3008
#define NETMSGTYPE_WriteLocalFile 3009
#define NETMSGTYPE_WriteLocalFileResp 3010
#define NETMSGTYPE_FSyncLocalFile 3013
#define NETMSGTYPE_FSyncLocalFileResp 3014
#define NETMSGTYPE_ReadLocalFileV2 3019
#define NETMSGTYPE_RefreshSession 3021
#define NETMSGTYPE_RefreshSessionResp 3022
#define NETMSGTYPE_LockGranted 3023
#define NETMSGTYPE_FLockEntry 3025
#define NETMSGTYPE_FLockEntryResp 3026
#define NETMSGTYPE_FLockRange 3027
#define NETMSGTYPE_FLockRangeResp 3028
#define NETMSGTYPE_FLockAppend 3029
#define NETMSGTYPE_FLockAppendResp 3030
#define NETMSGTYPE_AckNotify 3031
#define NETMSGTYPE_AckNotifyResp 3032
#define NETMSGTYPE_BumpFileVersion 3033
#define NETMSGTYPE_BumpFileVersionResp 3034
#define NETMSGTYPE_GetFileVersion 3035
#define NETMSGTYPE_GetFileVersionResp 3036
#ifdef BEEGFS_NVFS
#define NETMSGTYPE_WriteLocalFileRDMA 3037
#define NETMSGTYPE_WriteLocalFileRDMAResp 3038
#define NETMSGTYPE_ReadLocalFileRDMA 3039
#define NETMSGTYPE_ReadLocalFileRDMAResp 3040
#endif
// control messages
#define NETMSGTYPE_SetChannelDirect 4001
#define NETMSGTYPE_Ack 4003
#define NETMSGTYPE_Dummy 4005
#define NETMSGTYPE_AuthenticateChannel 4007
#define NETMSGTYPE_GenericResponse 4009
#define NETMSGTYPE_PeerInfo 4011
// mon messages
#define NETMSGTYPE_GetNodesFromRootMetaNode 6001
#define NETMSGTYPE_SendNodesList 6002
#define NETMSGTYPE_RequestMetaData 6003
#define NETMSGTYPE_RequestStorageData 6004
#define NETMSGTYPE_RequestMetaDataResp 6005
#define NETMSGTYPE_RequestStorageDataResp 6006
// fsck messages
#define NETMSGTYPE_RetrieveDirEntries 7001
#define NETMSGTYPE_RetrieveDirEntriesResp 7002
#define NETMSGTYPE_RetrieveInodes 7003
#define NETMSGTYPE_RetrieveInodesResp 7004
#define NETMSGTYPE_RetrieveChunks 7005
#define NETMSGTYPE_RetrieveChunksResp 7006
#define NETMSGTYPE_RetrieveFsIDs 7007
#define NETMSGTYPE_RetrieveFsIDsResp 7008
#define NETMSGTYPE_DeleteDirEntries 7009
#define NETMSGTYPE_DeleteDirEntriesResp 7010
#define NETMSGTYPE_CreateDefDirInodes 7011
#define NETMSGTYPE_CreateDefDirInodesResp 7012
#define NETMSGTYPE_FixInodeOwnersInDentry 7013
#define NETMSGTYPE_FixInodeOwnersInDentryResp 7014
#define NETMSGTYPE_FixInodeOwners 7015
#define NETMSGTYPE_FixInodeOwnersResp 7016
#define NETMSGTYPE_LinkToLostAndFound 7017
#define NETMSGTYPE_LinkToLostAndFoundResp 7018
#define NETMSGTYPE_DeleteChunks 7019
#define NETMSGTYPE_DeleteChunksResp 7020
#define NETMSGTYPE_CreateEmptyContDirs 7021
#define NETMSGTYPE_CreateEmptyContDirsResp 7022
#define NETMSGTYPE_UpdateFileAttribs 7023
#define NETMSGTYPE_UpdateFileAttribsResp 7024
#define NETMSGTYPE_UpdateDirAttribs 7025
#define NETMSGTYPE_UpdateDirAttribsResp 7026
#define NETMSGTYPE_RemoveInodes 7027
#define NETMSGTYPE_RemoveInodesResp 7028
#define NETMSGTYPE_RecreateFsIDs 7031
#define NETMSGTYPE_RecreateFsIDsResp 7032
#define NETMSGTYPE_RecreateDentries 7033
#define NETMSGTYPE_RecreateDentriesResp 7034
#define NETMSGTYPE_FsckModificationEvent 7035
#define NETMSGTYPE_FsckSetEventLogging 7036
#define NETMSGTYPE_FsckSetEventLoggingResp 7037
#define NETMSGTYPE_FetchFsckChunkList 7038
#define NETMSGTYPE_FetchFsckChunkListResp 7039
#define NETMSGTYPE_AdjustChunkPermissions 7040
#define NETMSGTYPE_AdjustChunkPermissionsResp 7041
#define NETMSGTYPE_MoveChunkFile 7042
#define NETMSGTYPE_MoveChunkFileResp 7043
#define NETMSGTYPE_CheckAndRepairDupInode 7044
#define NETMSGTYPE_CheckAndRepairDupInodeResp 7045
#endif /*NETMESSAGETYPES_H_*/

View File

@@ -0,0 +1,22 @@
#include "SimpleInt64Msg.h"
const struct NetMessageOps SimpleInt64Msg_Ops = {
.serializePayload = SimpleInt64Msg_serializePayload,
.deserializePayload = SimpleInt64Msg_deserializePayload,
.processIncoming = NetMessage_processIncoming,
.getSupportedHeaderFeatureFlagsMask = NetMessage_getSupportedHeaderFeatureFlagsMask,
};
void SimpleInt64Msg_serializePayload(NetMessage* this, SerializeCtx* ctx)
{
SimpleInt64Msg* thisCast = (SimpleInt64Msg*)this;
Serialization_serializeInt64(ctx, thisCast->value);
}
bool SimpleInt64Msg_deserializePayload(NetMessage* this, DeserializeCtx* ctx)
{
SimpleInt64Msg* thisCast = (SimpleInt64Msg*)this;
return Serialization_deserializeInt64(ctx, &thisCast->value);
}

View File

@@ -0,0 +1,46 @@
#ifndef SIMPLEINT64MSG_H_
#define SIMPLEINT64MSG_H_
#include "NetMessage.h"
struct SimpleInt64Msg;
typedef struct SimpleInt64Msg SimpleInt64Msg;
static inline void SimpleInt64Msg_init(SimpleInt64Msg* this, unsigned short msgType);
static inline void SimpleInt64Msg_initFromValue(SimpleInt64Msg* this, unsigned short msgType,
int64_t value);
// virtual functions
extern void SimpleInt64Msg_serializePayload(NetMessage* this, SerializeCtx* ctx);
extern bool SimpleInt64Msg_deserializePayload(NetMessage* this, DeserializeCtx* ctx);
// getters & setters
static inline int64_t SimpleInt64Msg_getValue(SimpleInt64Msg* this);
struct SimpleInt64Msg
{
NetMessage netMessage;
int64_t value;
};
extern const struct NetMessageOps SimpleInt64Msg_Ops;
void SimpleInt64Msg_init(SimpleInt64Msg* this, unsigned short msgType)
{
NetMessage_init(&this->netMessage, msgType, &SimpleInt64Msg_Ops);
}
void SimpleInt64Msg_initFromValue(SimpleInt64Msg* this, unsigned short msgType, int64_t value)
{
SimpleInt64Msg_init(this, msgType);
this->value = value;
}
int64_t SimpleInt64Msg_getValue(SimpleInt64Msg* this)
{
return this->value;
}
#endif /*SIMPLEINT64MSG_H_*/

View File

@@ -0,0 +1,22 @@
#include "SimpleIntMsg.h"
const struct NetMessageOps SimpleIntMsg_Ops = {
.serializePayload = SimpleIntMsg_serializePayload,
.deserializePayload = SimpleIntMsg_deserializePayload,
.processIncoming = NetMessage_processIncoming,
.getSupportedHeaderFeatureFlagsMask = NetMessage_getSupportedHeaderFeatureFlagsMask,
};
void SimpleIntMsg_serializePayload(NetMessage* this, SerializeCtx* ctx)
{
SimpleIntMsg* thisCast = (SimpleIntMsg*)this;
Serialization_serializeInt(ctx, thisCast->value);
}
bool SimpleIntMsg_deserializePayload(NetMessage* this, DeserializeCtx* ctx)
{
SimpleIntMsg* thisCast = (SimpleIntMsg*)this;
return Serialization_deserializeInt(ctx, &thisCast->value);
}

View File

@@ -0,0 +1,48 @@
#ifndef SIMPLEINTMSG_H_
#define SIMPLEINTMSG_H_
#include "NetMessage.h"
struct SimpleIntMsg;
typedef struct SimpleIntMsg SimpleIntMsg;
static inline void SimpleIntMsg_init(SimpleIntMsg* this, unsigned short msgType);
static inline void SimpleIntMsg_initFromValue(SimpleIntMsg* this, unsigned short msgType,
int value);
// virtual functions
extern void SimpleIntMsg_serializePayload(NetMessage* this, SerializeCtx* ctx);
extern bool SimpleIntMsg_deserializePayload(NetMessage* this, DeserializeCtx* ctx);
// getters & setters
static inline int SimpleIntMsg_getValue(SimpleIntMsg* this);
struct SimpleIntMsg
{
NetMessage netMessage;
int value;
};
extern const struct NetMessageOps SimpleIntMsg_Ops;
void SimpleIntMsg_init(SimpleIntMsg* this, unsigned short msgType)
{
NetMessage_init(&this->netMessage, msgType, &SimpleIntMsg_Ops);
}
void SimpleIntMsg_initFromValue(SimpleIntMsg* this, unsigned short msgType, int value)
{
SimpleIntMsg_init(this, msgType);
this->value = value;
}
int SimpleIntMsg_getValue(SimpleIntMsg* this)
{
return this->value;
}
#endif /*SIMPLEINTMSG_H_*/

View File

@@ -0,0 +1,31 @@
#include "SimpleIntStringMsg.h"
const struct NetMessageOps SimpleIntStringMsg_Ops = {
.serializePayload = SimpleIntStringMsg_serializePayload,
.deserializePayload = SimpleIntStringMsg_deserializePayload,
.processIncoming = NetMessage_processIncoming,
.getSupportedHeaderFeatureFlagsMask = NetMessage_getSupportedHeaderFeatureFlagsMask,
};
void SimpleIntStringMsg_serializePayload(NetMessage* this, SerializeCtx* ctx)
{
SimpleIntStringMsg* thisCast = (SimpleIntStringMsg*)this;
Serialization_serializeInt(ctx, thisCast->intValue);
Serialization_serializeStr(ctx, thisCast->strValueLen, thisCast->strValue);
}
bool SimpleIntStringMsg_deserializePayload(NetMessage* this, DeserializeCtx* ctx)
{
SimpleIntStringMsg* thisCast = (SimpleIntStringMsg*)this;
// intValue
if(!Serialization_deserializeInt(ctx, &thisCast->intValue) )
return false;
// strValue
if(!Serialization_deserializeStr(ctx, &thisCast->strValueLen, &thisCast->strValue) )
return false;
return true;
}

View File

@@ -0,0 +1,69 @@
#ifndef SIMPLEINTSTRINGMSG_H_
#define SIMPLEINTSTRINGMSG_H_
#include "NetMessage.h"
struct SimpleIntStringMsg;
typedef struct SimpleIntStringMsg SimpleIntStringMsg;
static inline void SimpleIntStringMsg_init(SimpleIntStringMsg* this, unsigned short msgType);
static inline void SimpleIntStringMsg_initFromValue(SimpleIntStringMsg* this, unsigned short msgType,
int intValue, const char* strValue);
// virtual functions
extern void SimpleIntStringMsg_serializePayload(NetMessage* this, SerializeCtx* ctx);
extern bool SimpleIntStringMsg_deserializePayload(NetMessage* this, DeserializeCtx* ctx);
// getters & setters
static inline int SimpleIntStringMsg_getIntValue(SimpleIntStringMsg* this);
static inline const char* SimpleIntStringMsg_getStrValue(SimpleIntStringMsg* this);
/**
* Simple message containing an integer value and a string (e.g. int error code and human-readable
* explantion with more details as string).
*/
struct SimpleIntStringMsg
{
NetMessage netMessage;
int intValue;
const char* strValue;
unsigned strValueLen;
};
extern const struct NetMessageOps SimpleIntStringMsg_Ops;
void SimpleIntStringMsg_init(SimpleIntStringMsg* this, unsigned short msgType)
{
NetMessage_init(&this->netMessage, msgType, &SimpleIntStringMsg_Ops);
}
/**
* @param strValue just a reference, so don't free or modify it while this msg is used.
*/
void SimpleIntStringMsg_initFromValue(SimpleIntStringMsg* this, unsigned short msgType,
int intValue, const char* strValue)
{
SimpleIntStringMsg_init(this, msgType);
this->intValue = intValue;
this->strValue = strValue;
this->strValueLen = strlen(strValue);
}
int SimpleIntStringMsg_getIntValue(SimpleIntStringMsg* this)
{
return this->intValue;
}
const char* SimpleIntStringMsg_getStrValue(SimpleIntStringMsg* this)
{
return this->strValue;
}
#endif /* SIMPLEINTSTRINGMSG_H_ */

View File

@@ -0,0 +1,19 @@
#include "SimpleMsg.h"
const struct NetMessageOps SimpleMsg_Ops = {
.serializePayload = SimpleMsg_serializePayload,
.deserializePayload = SimpleMsg_deserializePayload,
.processIncoming = NetMessage_processIncoming,
.getSupportedHeaderFeatureFlagsMask = NetMessage_getSupportedHeaderFeatureFlagsMask,
};
void SimpleMsg_serializePayload(NetMessage* this, SerializeCtx* ctx)
{
// nothing to be done here for simple messages
}
bool SimpleMsg_deserializePayload(NetMessage* this, DeserializeCtx* ctx)
{
// nothing to be done here for simple messages
return true;
}

View File

@@ -0,0 +1,33 @@
#ifndef SIMPLEMSG_H_
#define SIMPLEMSG_H_
#include "NetMessage.h"
/**
* Note: Simple messages are defined by the header (resp. the msgType) only and
* require no additional data
*/
struct SimpleMsg;
typedef struct SimpleMsg SimpleMsg;
static inline void SimpleMsg_init(SimpleMsg* this, unsigned short msgType);
// virtual functions
extern void SimpleMsg_serializePayload(NetMessage* this, SerializeCtx* ctx);
extern bool SimpleMsg_deserializePayload(NetMessage* this, DeserializeCtx* ctx);
struct SimpleMsg
{
NetMessage netMessage;
};
extern const struct NetMessageOps SimpleMsg_Ops;
void SimpleMsg_init(SimpleMsg* this, unsigned short msgType)
{
NetMessage_init(&this->netMessage, msgType, &SimpleMsg_Ops);
}
#endif /*SIMPLEMSG_H_*/

View File

@@ -0,0 +1,22 @@
#include "SimpleStringMsg.h"
const struct NetMessageOps SimpleStringMsg_Ops = {
.serializePayload = SimpleStringMsg_serializePayload,
.deserializePayload = SimpleStringMsg_deserializePayload,
.processIncoming = NetMessage_processIncoming,
.getSupportedHeaderFeatureFlagsMask = NetMessage_getSupportedHeaderFeatureFlagsMask,
};
void SimpleStringMsg_serializePayload(NetMessage* this, SerializeCtx* ctx)
{
SimpleStringMsg* thisCast = (SimpleStringMsg*)this;
Serialization_serializeStr(ctx, thisCast->valueLen, thisCast->value);
}
bool SimpleStringMsg_deserializePayload(NetMessage* this, DeserializeCtx* ctx)
{
SimpleStringMsg* thisCast = (SimpleStringMsg*)this;
return Serialization_deserializeStr(ctx, &thisCast->valueLen, &thisCast->value);
}

View File

@@ -0,0 +1,48 @@
#ifndef SIMPLESTRINGMSG_H_
#define SIMPLESTRINGMSG_H_
#include "NetMessage.h"
struct SimpleStringMsg;
typedef struct SimpleStringMsg SimpleStringMsg;
static inline void SimpleStringMsg_init(SimpleStringMsg* this, unsigned short msgType);
static inline void SimpleStringMsg_initFromValue(SimpleStringMsg* this, unsigned short msgType,
const char* value);
// virtual functions
extern void SimpleStringMsg_serializePayload(NetMessage* this, SerializeCtx* ctx);
extern bool SimpleStringMsg_deserializePayload(NetMessage* this, DeserializeCtx* ctx);
// getters & setters
static inline const char* SimpleStringMsg_getValue(SimpleStringMsg* this);
struct SimpleStringMsg
{
NetMessage netMessage;
const char* value;
unsigned valueLen;
};
extern const struct NetMessageOps SimpleStringMsg_Ops;
void SimpleStringMsg_init(SimpleStringMsg* this, unsigned short msgType)
{
NetMessage_init(&this->netMessage, msgType, &SimpleStringMsg_Ops);
}
void SimpleStringMsg_initFromValue(SimpleStringMsg* this, unsigned short msgType, const char* value)
{
SimpleStringMsg_init(this, msgType);
this->value = value;
this->valueLen = strlen(value);
}
const char* SimpleStringMsg_getValue(SimpleStringMsg* this)
{
return this->value;
}
#endif /* SIMPLESTRINGMSG_H_ */

View File

@@ -0,0 +1,22 @@
#include "SimpleUInt16Msg.h"
const struct NetMessageOps SimpleUInt16Msg_Ops = {
.serializePayload = SimpleUInt16Msg_serializePayload,
.deserializePayload = SimpleUInt16Msg_deserializePayload,
.processIncoming = NetMessage_processIncoming,
.getSupportedHeaderFeatureFlagsMask = NetMessage_getSupportedHeaderFeatureFlagsMask,
};
void SimpleUInt16Msg_serializePayload(NetMessage* this, SerializeCtx* ctx)
{
SimpleUInt16Msg* thisCast = (SimpleUInt16Msg*)this;
Serialization_serializeUShort(ctx, thisCast->value);
}
bool SimpleUInt16Msg_deserializePayload(NetMessage* this, DeserializeCtx* ctx)
{
SimpleUInt16Msg* thisCast = (SimpleUInt16Msg*)this;
return Serialization_deserializeUShort(ctx, &thisCast->value);
}

View File

@@ -0,0 +1,48 @@
#ifndef SIMPLEUINT16MSG_H_
#define SIMPLEUINT16MSG_H_
#include "NetMessage.h"
struct SimpleUInt16Msg;
typedef struct SimpleUInt16Msg SimpleUInt16Msg;
static inline void SimpleUInt16Msg_init(SimpleUInt16Msg* this, unsigned short msgType);
static inline void SimpleUInt16Msg_initFromValue(SimpleUInt16Msg* this, unsigned short msgType,
uint16_t value);
// virtual functions
extern void SimpleUInt16Msg_serializePayload(NetMessage* this, SerializeCtx* ctx);
extern bool SimpleUInt16Msg_deserializePayload(NetMessage* this, DeserializeCtx* ctx);
// getters & setters
static inline uint16_t SimpleUInt16Msg_getValue(SimpleUInt16Msg* this);
struct SimpleUInt16Msg
{
NetMessage netMessage;
uint16_t value;
};
extern const struct NetMessageOps SimpleUInt16Msg_Ops;
void SimpleUInt16Msg_init(SimpleUInt16Msg* this, unsigned short msgType)
{
NetMessage_init(&this->netMessage, msgType, &SimpleUInt16Msg_Ops);
}
void SimpleUInt16Msg_initFromValue(SimpleUInt16Msg* this, unsigned short msgType, uint16_t value)
{
SimpleUInt16Msg_init(this, msgType);
this->value = value;
}
uint16_t SimpleUInt16Msg_getValue(SimpleUInt16Msg* this)
{
return this->value;
}
#endif /* SIMPLEUINT16MSG_H_ */

View File

@@ -0,0 +1,40 @@
#ifndef ACKMSGEX_H_
#define ACKMSGEX_H_
#include "../SimpleStringMsg.h"
struct AckMsgEx;
typedef struct AckMsgEx AckMsgEx;
static inline void AckMsgEx_init(AckMsgEx* this);
static inline void AckMsgEx_initFromValue(AckMsgEx* this,
const char* value);
// getters & setters
static inline const char* AckMsgEx_getValue(AckMsgEx* this);
struct AckMsgEx
{
SimpleStringMsg simpleStringMsg;
};
void AckMsgEx_init(AckMsgEx* this)
{
SimpleStringMsg_init( (SimpleStringMsg*)this, NETMSGTYPE_Ack);
}
void AckMsgEx_initFromValue(AckMsgEx* this, const char* value)
{
SimpleStringMsg_initFromValue( (SimpleStringMsg*)this, NETMSGTYPE_Ack, value);
}
const char* AckMsgEx_getValue(AckMsgEx* this)
{
return SimpleStringMsg_getValue( (SimpleStringMsg*)this);
}
#endif /* ACKMSGEX_H_ */

View File

@@ -0,0 +1,32 @@
#ifndef AUTHENTICATECHANNELMSG_H_
#define AUTHENTICATECHANNELMSG_H_
#include <common/net/message/SimpleInt64Msg.h>
struct AuthenticateChannelMsg;
typedef struct AuthenticateChannelMsg AuthenticateChannelMsg;
static inline void AuthenticateChannelMsg_init(AuthenticateChannelMsg* this);
static inline void AuthenticateChannelMsg_initFromValue(AuthenticateChannelMsg* this,
uint64_t authHash);
struct AuthenticateChannelMsg
{
SimpleInt64Msg simpleInt64Msg;
};
void AuthenticateChannelMsg_init(AuthenticateChannelMsg* this)
{
SimpleInt64Msg_init( (SimpleInt64Msg*)this, NETMSGTYPE_AuthenticateChannel);
}
void AuthenticateChannelMsg_initFromValue(AuthenticateChannelMsg* this, uint64_t authHash)
{
SimpleInt64Msg_initFromValue( (SimpleInt64Msg*)this, NETMSGTYPE_AuthenticateChannel, authHash);
}
#endif /* AUTHENTICATECHANNELMSG_H_ */

View File

@@ -0,0 +1,65 @@
#ifndef GENERICRESPONSEMSG_H_
#define GENERICRESPONSEMSG_H_
#include <common/net/message/SimpleIntStringMsg.h>
/**
* Note: Remember to keep this in sync with userspace common lib.
*/
enum GenericRespMsgCode
{
GenericRespMsgCode_TRYAGAIN = 0, /* requestor shall try again in a few seconds */
GenericRespMsgCode_INDIRECTCOMMERR = 1, /* indirect communication error and requestor should
try again (e.g. msg forwarding to other server failed) */
GenericRespMsgCode_NEWSEQNOBASE = 2, /* client has restarted its seq# sequence. server provides
the new starting seq#. */
};
typedef enum GenericRespMsgCode GenericRespMsgCode;
struct GenericResponseMsg;
typedef struct GenericResponseMsg GenericResponseMsg;
static inline void GenericResponseMsg_init(GenericResponseMsg* this);
// getters & setters
static inline GenericRespMsgCode GenericResponseMsg_getControlCode(GenericResponseMsg* this);
static inline const char* GenericResponseMsg_getLogStr(GenericResponseMsg* this);
/**
* A generic response that can be sent as a reply to any message. This special control message will
* be handled internally by the requestors MessageTk::requestResponse...() method.
*
* This is intended to submit internal information (like asking for a communication retry) to the
* requestors MessageTk through the control code. So the MessageTk caller on the requestor side
* will never actually see this GenericResponseMsg.
*
* The message string is intended to provide additional human-readable information like why this
* control code was submitted instead of the actually expected response msg.
*/
struct GenericResponseMsg
{
SimpleIntStringMsg simpleIntStringMsg;
};
void GenericResponseMsg_init(GenericResponseMsg* this)
{
SimpleIntStringMsg_init( (SimpleIntStringMsg*)this, NETMSGTYPE_GenericResponse);
}
GenericRespMsgCode GenericResponseMsg_getControlCode(GenericResponseMsg* this)
{
return (GenericRespMsgCode)SimpleIntStringMsg_getIntValue( (SimpleIntStringMsg*)this);
}
const char* GenericResponseMsg_getLogStr(GenericResponseMsg* this)
{
return SimpleIntStringMsg_getStrValue( (SimpleIntStringMsg*)this);
}
#endif /* GENERICRESPONSEMSG_H_ */

View File

@@ -0,0 +1,29 @@
#include "PeerInfoMsg.h"
static void PeerInfoMsg_serializePayload(NetMessage* this, SerializeCtx* ctx)
{
PeerInfoMsg* thisCast = (PeerInfoMsg*)this;
Serialization_serializeUInt(ctx, thisCast->type);
NumNodeID_serialize(ctx, &thisCast->id);
}
static bool PeerInfoMsg_deserializePayload(NetMessage* this, DeserializeCtx* ctx)
{
PeerInfoMsg* thisCast = (PeerInfoMsg*)this;
unsigned type = 0;
bool result =
Serialization_deserializeUInt(ctx, &type)
&& NumNodeID_deserialize(ctx, &thisCast->id);
thisCast->type = type;
return result;
}
const struct NetMessageOps PeerInfoMsg_Ops = {
.serializePayload = PeerInfoMsg_serializePayload,
.deserializePayload = PeerInfoMsg_deserializePayload,
.processIncoming = NetMessage_processIncoming,
.getSupportedHeaderFeatureFlagsMask = NetMessage_getSupportedHeaderFeatureFlagsMask,
};

View File

@@ -0,0 +1,28 @@
#ifndef COMMON_NET_MESSAGE_CONTROL_PEERINFOMSG_H
#define COMMON_NET_MESSAGE_CONTROL_PEERINFOMSG_H
#include <common/net/message/NetMessage.h>
#include <common/nodes/Node.h>
struct PeerInfoMsg;
typedef struct PeerInfoMsg PeerInfoMsg;
struct PeerInfoMsg
{
NetMessage netMessage;
NodeType type;
NumNodeID id;
};
extern const struct NetMessageOps PeerInfoMsg_Ops;
static inline void PeerInfoMsg_init(PeerInfoMsg* this, NodeType type, NumNodeID id)
{
NetMessage_init(&this->netMessage, NETMSGTYPE_PeerInfo, &PeerInfoMsg_Ops);
this->type = type;
this->id = id;
}
#endif

View File

@@ -0,0 +1,29 @@
#ifndef SETCHANNELDIRECTMSG_H_
#define SETCHANNELDIRECTMSG_H_
#include <common/net/message/SimpleIntMsg.h>
struct SetChannelDirectMsg;
typedef struct SetChannelDirectMsg SetChannelDirectMsg;
static inline void SetChannelDirectMsg_init(SetChannelDirectMsg* this);
static inline void SetChannelDirectMsg_initFromValue(SetChannelDirectMsg* this, int value);
struct SetChannelDirectMsg
{
SimpleIntMsg simpleIntMsg;
};
void SetChannelDirectMsg_init(SetChannelDirectMsg* this)
{
SimpleIntMsg_init( (SimpleIntMsg*)this, NETMSGTYPE_SetChannelDirect);
}
void SetChannelDirectMsg_initFromValue(SetChannelDirectMsg* this, int value)
{
SimpleIntMsg_initFromValue( (SimpleIntMsg*)this, NETMSGTYPE_SetChannelDirect, value);
}
#endif /*SETCHANNELDIRECTMSG_H_*/

View File

@@ -0,0 +1,29 @@
#include <app/App.h>
#include <common/toolkit/SocketTk.h>
#include "GetHostByNameMsg.h"
const struct NetMessageOps GetHostByNameMsg_Ops = {
.serializePayload = GetHostByNameMsg_serializePayload,
.deserializePayload = GetHostByNameMsg_deserializePayload,
.processIncoming = NetMessage_processIncoming,
.getSupportedHeaderFeatureFlagsMask = NetMessage_getSupportedHeaderFeatureFlagsMask,
};
void GetHostByNameMsg_serializePayload(NetMessage* this, SerializeCtx* ctx)
{
GetHostByNameMsg* thisCast = (GetHostByNameMsg*)this;
// hostname
Serialization_serializeStr(ctx, thisCast->hostnameLen, thisCast->hostname);
}
bool GetHostByNameMsg_deserializePayload(NetMessage* this, DeserializeCtx* ctx)
{
GetHostByNameMsg* thisCast = (GetHostByNameMsg*)this;
// hostname
if(!Serialization_deserializeStr(ctx, &thisCast->hostnameLen, &thisCast->hostname) )
return false;
return true;
}

View File

@@ -0,0 +1,45 @@
#ifndef GETHOSTBYNAMEMSG_H_
#define GETHOSTBYNAMEMSG_H_
#include <common/net/message/NetMessage.h>
struct GetHostByNameMsg;
typedef struct GetHostByNameMsg GetHostByNameMsg;
static inline void GetHostByNameMsg_init(GetHostByNameMsg* this);
static inline void GetHostByNameMsg_initFromHostname(GetHostByNameMsg* this,
const char* hostname);
// virtual functions
extern void GetHostByNameMsg_serializePayload(NetMessage* this, SerializeCtx* ctx);
extern bool GetHostByNameMsg_deserializePayload(NetMessage* this, DeserializeCtx* ctx);
struct GetHostByNameMsg
{
NetMessage netMessage;
unsigned hostnameLen;
const char* hostname;
};
extern const struct NetMessageOps GetHostByNameMsg_Ops;
void GetHostByNameMsg_init(GetHostByNameMsg* this)
{
NetMessage_init(&this->netMessage, NETMSGTYPE_GetHostByName, &GetHostByNameMsg_Ops);
}
/**
* @param hostname just a reference, so do not free it as long as you use this object!
*/
void GetHostByNameMsg_initFromHostname(GetHostByNameMsg* this,
const char* hostname)
{
GetHostByNameMsg_init(this);
this->hostname = hostname;
this->hostnameLen = strlen(hostname);
}
#endif /*GETHOSTBYNAMEMSG_H_*/

View File

@@ -0,0 +1,21 @@
#include <app/App.h>
#include <common/toolkit/SocketTk.h>
#include "GetHostByNameRespMsg.h"
const struct NetMessageOps GetHostByNameRespMsg_Ops = {
.serializePayload = _NetMessage_serializeDummy,
.deserializePayload = GetHostByNameRespMsg_deserializePayload,
.processIncoming = NetMessage_processIncoming,
.getSupportedHeaderFeatureFlagsMask = NetMessage_getSupportedHeaderFeatureFlagsMask,
};
bool GetHostByNameRespMsg_deserializePayload(NetMessage* this, DeserializeCtx* ctx)
{
GetHostByNameRespMsg* thisCast = (GetHostByNameRespMsg*)this;
// hostAddr
if(!Serialization_deserializeStr(ctx, &thisCast->hostAddrLen, &thisCast->hostAddr) )
return false;
return true;
}

View File

@@ -0,0 +1,39 @@
#ifndef GETHOSTBYNAMERESPMSG_H_
#define GETHOSTBYNAMERESPMSG_H_
#include <common/net/message/NetMessage.h>
struct GetHostByNameRespMsg;
typedef struct GetHostByNameRespMsg GetHostByNameRespMsg;
static inline void GetHostByNameRespMsg_init(GetHostByNameRespMsg* this);
// virtual functions
extern bool GetHostByNameRespMsg_deserializePayload(NetMessage* this, DeserializeCtx* ctx);
// getters & setters
static inline const char* GetHostByNameRespMsg_getHostAddr(GetHostByNameRespMsg* this);
struct GetHostByNameRespMsg
{
NetMessage netMessage;
unsigned hostAddrLen;
const char* hostAddr;
};
extern const struct NetMessageOps GetHostByNameRespMsg_Ops;
void GetHostByNameRespMsg_init(GetHostByNameRespMsg* this)
{
NetMessage_init(&this->netMessage, NETMSGTYPE_GetHostByNameResp, &GetHostByNameRespMsg_Ops);
}
const char* GetHostByNameRespMsg_getHostAddr(GetHostByNameRespMsg* this)
{
return this->hostAddr;
}
#endif /*GETHOSTBYNAMERESPMSG_H_*/

View File

@@ -0,0 +1,61 @@
#include <app/App.h>
#include <common/nodes/Node.h>
#include <common/toolkit/SocketTk.h>
#include <common/toolkit/ListTk.h>
#include <nodes/NodeStoreEx.h>
#include "LogMsg.h"
const struct NetMessageOps LogMsg_Ops = {
.serializePayload = LogMsg_serializePayload,
.deserializePayload = LogMsg_deserializePayload,
.processIncoming = NetMessage_processIncoming,
.getSupportedHeaderFeatureFlagsMask = NetMessage_getSupportedHeaderFeatureFlagsMask,
};
void LogMsg_serializePayload(NetMessage* this, SerializeCtx* ctx)
{
LogMsg* thisCast = (LogMsg*)this;
// level
Serialization_serializeInt(ctx, thisCast->level);
// threadID
Serialization_serializeInt(ctx, thisCast->threadID);
// threadName
Serialization_serializeStr(ctx, thisCast->threadNameLen, thisCast->threadName);
// context
Serialization_serializeStr(ctx, thisCast->contextLen, thisCast->context);
// logMsg
Serialization_serializeStr(ctx, thisCast->logMsgLen, thisCast->logMsg);
}
bool LogMsg_deserializePayload(NetMessage* this, DeserializeCtx* ctx)
{
LogMsg* thisCast = (LogMsg*)this;
// level
if(!Serialization_deserializeInt(ctx, &thisCast->level) )
return false;
// threadID
if(!Serialization_deserializeInt(ctx, &thisCast->threadID) )
return false;
// threadName
if(!Serialization_deserializeStr(ctx, &thisCast->threadNameLen, &thisCast->threadName) )
return false;
// context
if(!Serialization_deserializeStr(ctx, &thisCast->contextLen, &thisCast->context) )
return false;
// logMsg
if(!Serialization_deserializeStr(ctx, &thisCast->logMsgLen, &thisCast->logMsg) )
return false;
return true;
}

View File

@@ -0,0 +1,62 @@
#ifndef LOGMSG_H_
#define LOGMSG_H_
#include <common/net/message/NetMessage.h>
struct LogMsg;
typedef struct LogMsg LogMsg;
static inline void LogMsg_init(LogMsg* this);
static inline void LogMsg_initFromEntry(LogMsg* this, int level,
int threadID, const char* threadName, const char* context, const char* logMsg);
// virtual functions
extern void LogMsg_serializePayload(NetMessage* this, SerializeCtx* ctx);
extern bool LogMsg_deserializePayload(NetMessage* this, DeserializeCtx* ctx);
struct LogMsg
{
NetMessage netMessage;
int level;
int threadID;
unsigned threadNameLen;
const char* threadName;
unsigned contextLen;
const char* context;
unsigned logMsgLen;
const char* logMsg;
};
extern const struct NetMessageOps LogMsg_Ops;
void LogMsg_init(LogMsg* this)
{
NetMessage_init(&this->netMessage, NETMSGTYPE_Log, &LogMsg_Ops);
}
/**
* @param context just a reference, so do not free it as long as you use this object!
* @param logMsg just a reference, so do not free it as long as you use this object!
*/
void LogMsg_initFromEntry(LogMsg* this, int level, int threadID, const char* threadName,
const char* context, const char* logMsg)
{
LogMsg_init(this);
this->level = level;
this->threadID = threadID;
this->threadName = threadName;
this->threadNameLen = strlen(threadName);
this->context = context;
this->contextLen = strlen(context);
this->logMsg = logMsg;
this->logMsgLen = strlen(logMsg);
}
#endif /*LOGMSG_H_*/

View File

@@ -0,0 +1,32 @@
#ifndef LOGRESPMSG_H_
#define LOGRESPMSG_H_
#include <common/net/message/SimpleIntMsg.h>
struct LogRespMsg;
typedef struct LogRespMsg LogRespMsg;
static inline void LogRespMsg_init(LogRespMsg* this);
// getters & setters
static inline int LogRespMsg_getValue(LogRespMsg* this);
struct LogRespMsg
{
SimpleIntMsg simpleIntMsg;
};
void LogRespMsg_init(LogRespMsg* this)
{
SimpleIntMsg_init( (SimpleIntMsg*)this, NETMSGTYPE_LogResp);
}
int LogRespMsg_getValue(LogRespMsg* this)
{
return SimpleIntMsg_getValue( (SimpleIntMsg*)this);
}
#endif /*LOGRESPMSG_H_*/

View File

@@ -0,0 +1,21 @@
#ifndef GETMIRRORBUDDYGROUPSMSG_H
#define GETMIRRORBUDDYGROUPSMSG_H
#include <common/net/message/SimpleIntMsg.h>
struct GetMirrorBuddyGroupsMsg;
typedef struct GetMirrorBuddyGroupsMsg GetMirrorBuddyGroupsMsg;
static inline void GetMirrorBuddyGroupsMsg_init(GetMirrorBuddyGroupsMsg* this, NodeType nodeType);
struct GetMirrorBuddyGroupsMsg
{
SimpleIntMsg simpleIntMsg;
};
void GetMirrorBuddyGroupsMsg_init(GetMirrorBuddyGroupsMsg* this, NodeType nodeType)
{
SimpleIntMsg_initFromValue( (SimpleIntMsg*)this, NETMSGTYPE_GetMirrorBuddyGroups, nodeType);
}
#endif /* GETMIRRORBUDDYGROUPSMSG_H */

View File

@@ -0,0 +1,32 @@
#ifndef GETNODESMSG_H_
#define GETNODESMSG_H_
#include <common/net/message/SimpleIntMsg.h>
struct GetNodesMsg;
typedef struct GetNodesMsg GetNodesMsg;
static inline void GetNodesMsg_init(GetNodesMsg* this);
static inline void GetNodesMsg_initFromValue(GetNodesMsg* this, int nodeType);
struct GetNodesMsg
{
SimpleIntMsg simpleIntMsg;
};
void GetNodesMsg_init(GetNodesMsg* this)
{
SimpleIntMsg_init( (SimpleIntMsg*)this, NETMSGTYPE_GetNodes);
}
/**
* @param nodeType NODETYPE_...
*/
void GetNodesMsg_initFromValue(GetNodesMsg* this, int nodeType)
{
SimpleIntMsg_initFromValue( (SimpleIntMsg*)this, NETMSGTYPE_GetNodes, nodeType);
}
#endif /* GETNODESMSG_H_ */

View File

@@ -0,0 +1,30 @@
#include "GetNodesRespMsg.h"
const struct NetMessageOps GetNodesRespMsg_Ops = {
.serializePayload = _NetMessage_serializeDummy,
.deserializePayload = GetNodesRespMsg_deserializePayload,
.processIncoming = NetMessage_processIncoming,
.getSupportedHeaderFeatureFlagsMask = NetMessage_getSupportedHeaderFeatureFlagsMask,
};
bool GetNodesRespMsg_deserializePayload(NetMessage* this, DeserializeCtx* ctx)
{
GetNodesRespMsg* thisCast = (GetNodesRespMsg*)this;
// nodeList
if(!Serialization_deserializeNodeListPreprocess(ctx, &thisCast->rawNodeList) )
return false;
// rootNumID
if(!NumNodeID_deserialize(ctx, &thisCast->rootNumID) )
return false;
// rootIsBuddyMirrored
if(!Serialization_deserializeBool(ctx, &thisCast->rootIsBuddyMirrored) )
return false;
return true;
}

View File

@@ -0,0 +1,62 @@
#ifndef GETNODESRESPMSG_H_
#define GETNODESRESPMSG_H_
#include <common/net/message/NetMessage.h>
#include <common/nodes/NodeList.h>
/*
* note: serialization not implemented
*/
struct GetNodesRespMsg;
typedef struct GetNodesRespMsg GetNodesRespMsg;
static inline void GetNodesRespMsg_init(GetNodesRespMsg* this);
// virtual functions
extern bool GetNodesRespMsg_deserializePayload(NetMessage* this, DeserializeCtx* ctx);
// inliners
static inline void GetNodesRespMsg_parseNodeList(App* app, GetNodesRespMsg* this,
NodeList* outNodeList);
// getters & setters
static inline NumNodeID GetNodesRespMsg_getRootNumID(GetNodesRespMsg* this);
static inline bool GetNodesRespMsg_getRootIsBuddyMirrored(GetNodesRespMsg* this);
struct GetNodesRespMsg
{
NetMessage netMessage;
NumNodeID rootNumID;
bool rootIsBuddyMirrored;
// for deserialization
RawList rawNodeList;
};
extern const struct NetMessageOps GetNodesRespMsg_Ops;
void GetNodesRespMsg_init(GetNodesRespMsg* this)
{
NetMessage_init(&this->netMessage, NETMSGTYPE_GetNodesResp, &GetNodesRespMsg_Ops);
this->rootNumID = (NumNodeID){0};
}
void GetNodesRespMsg_parseNodeList(App* app, GetNodesRespMsg* this, NodeList* outNodeList)
{
Serialization_deserializeNodeList(app, &this->rawNodeList, outNodeList);
}
NumNodeID GetNodesRespMsg_getRootNumID(GetNodesRespMsg* this)
{
return this->rootNumID;
}
bool GetNodesRespMsg_getRootIsBuddyMirrored(GetNodesRespMsg* this)
{
return this->rootIsBuddyMirrored;
}
#endif /* GETNODESRESPMSG_H_ */

View File

@@ -0,0 +1,27 @@
#include "GetStatesAndBuddyGroupsMsg.h"
static void GetStatesAndBuddyGroupsMsg_serializePayload(NetMessage* this, SerializeCtx* ctx)
{
GetStatesAndBuddyGroupsMsg* thisCast = (GetStatesAndBuddyGroupsMsg*)this;
Serialization_serializeInt(ctx, thisCast->nodeType);
NumNodeID_serialize(ctx, &thisCast->requestedByClientID);
}
static bool GetStatesAndBuddyGroupsMsg_deserializePayload(NetMessage* this, DeserializeCtx* ctx)
{
GetStatesAndBuddyGroupsMsg* thisCast = (GetStatesAndBuddyGroupsMsg*)this;
bool result =
Serialization_deserializeInt(ctx, (int32_t*)&thisCast->nodeType)
&& NumNodeID_deserialize(ctx, &thisCast->requestedByClientID);
return result;
}
const struct NetMessageOps GetStatesAndBuddyGroupsMsg_Ops = {
.serializePayload = GetStatesAndBuddyGroupsMsg_serializePayload,
.deserializePayload = GetStatesAndBuddyGroupsMsg_deserializePayload,
.processIncoming = NetMessage_processIncoming,
.getSupportedHeaderFeatureFlagsMask = NetMessage_getSupportedHeaderFeatureFlagsMask,
};

View File

@@ -0,0 +1,34 @@
#ifndef GETSTATESANDBUDDYGROUPSMSG_H_
#define GETSTATESANDBUDDYGROUPSMSG_H_
#include <common/net/message/NetMessage.h>
#include "common/nodes/NumNodeID.h"
#include <common/nodes/Node.h>
struct GetStatesAndBuddyGroupsMsg;
typedef struct GetStatesAndBuddyGroupsMsg GetStatesAndBuddyGroupsMsg;
static inline void GetStatesAndBuddyGroupsMsg_init(GetStatesAndBuddyGroupsMsg* this,
NodeType nodeType, NumNodeID requestedByClientID);
struct GetStatesAndBuddyGroupsMsg
{
NetMessage netMessage;
NodeType nodeType;
NumNodeID requestedByClientID;
};
extern const struct NetMessageOps GetStatesAndBuddyGroupsMsg_Ops;
void GetStatesAndBuddyGroupsMsg_init(GetStatesAndBuddyGroupsMsg* this, NodeType nodeType, NumNodeID requestedByClientID)
{
NetMessage_init(&this->netMessage, NETMSGTYPE_GetStatesAndBuddyGroups, &GetStatesAndBuddyGroupsMsg_Ops);
this->nodeType = nodeType;
this->requestedByClientID = requestedByClientID;
}
#endif /* GETSTATESANDBUDDYGROUPSMSG_H_ */

View File

@@ -0,0 +1,33 @@
#include "GetStatesAndBuddyGroupsRespMsg.h"
static void GetStatesAndBuddyGroupsRespMsg_release(NetMessage* msg)
{
GetStatesAndBuddyGroupsRespMsg* this = container_of(msg, struct GetStatesAndBuddyGroupsRespMsg,
netMessage);
BEEGFS_KFREE_LIST(&this->groups, struct BuddyGroupMapping, _list);
BEEGFS_KFREE_LIST(&this->states, struct TargetStateMapping, _list);
}
const struct NetMessageOps GetStatesAndBuddyGroupsRespMsg_Ops = {
.serializePayload = _NetMessage_serializeDummy,
.deserializePayload = GetStatesAndBuddyGroupsRespMsg_deserializePayload,
.processIncoming = NetMessage_processIncoming,
.getSupportedHeaderFeatureFlagsMask = NetMessage_getSupportedHeaderFeatureFlagsMask,
.release = GetStatesAndBuddyGroupsRespMsg_release,
};
bool GetStatesAndBuddyGroupsRespMsg_deserializePayload(NetMessage* this, DeserializeCtx* ctx)
{
GetStatesAndBuddyGroupsRespMsg* thisCast = (GetStatesAndBuddyGroupsRespMsg*)this;
if (!BuddyGroupMappingList_deserialize(ctx, &thisCast->groups))
return false;
if (!TargetStateMappingList_deserialize(ctx, &thisCast->states))
return false;
return true;
}

View File

@@ -0,0 +1,43 @@
#ifndef GETSTATESANDBUDDYGROUPSRESPMSG_H_
#define GETSTATESANDBUDDYGROUPSRESPMSG_H_
#include <common/net/message/NetMessage.h>
#include <common/Common.h>
#include <common/Types.h>
struct GetStatesAndBuddyGroupsRespMsg;
typedef struct GetStatesAndBuddyGroupsRespMsg GetStatesAndBuddyGroupsRespMsg;
static inline void GetStatesAndBuddyGroupsRespMsg_init(GetStatesAndBuddyGroupsRespMsg* this);
// virtual functions
extern bool GetStatesAndBuddyGroupsRespMsg_deserializePayload(NetMessage* this,
DeserializeCtx* ctx);
/**
* This message carries two maps:
* 1) buddyGroupID -> primaryTarget, secondaryTarget
* 2) targetID -> targetReachabilityState, targetConsistencyState
*
* Note: This message can only be received/deserialized (send/serialization not implemented).
*/
struct GetStatesAndBuddyGroupsRespMsg
{
NetMessage netMessage;
struct list_head groups; /* struct BuddyGroupMapping */
struct list_head states; /* struct TargetStateMapping */
};
extern const struct NetMessageOps GetStatesAndBuddyGroupsRespMsg_Ops;
void GetStatesAndBuddyGroupsRespMsg_init(GetStatesAndBuddyGroupsRespMsg* this)
{
NetMessage_init(&this->netMessage, NETMSGTYPE_GetStatesAndBuddyGroupsResp,
&GetStatesAndBuddyGroupsRespMsg_Ops);
INIT_LIST_HEAD(&this->groups);
INIT_LIST_HEAD(&this->states);
}
#endif /* GETSTATESANDBUDDYGROUPSRESPMSG_H_ */

View File

@@ -0,0 +1,24 @@
#ifndef GETTARGETMAPPINGSMSG_H_
#define GETTARGETMAPPINGSMSG_H_
#include "../SimpleMsg.h"
struct GetTargetMappingsMsg;
typedef struct GetTargetMappingsMsg GetTargetMappingsMsg;
static inline void GetTargetMappingsMsg_init(GetTargetMappingsMsg* this);
struct GetTargetMappingsMsg
{
SimpleMsg simpleMsg;
};
void GetTargetMappingsMsg_init(GetTargetMappingsMsg* this)
{
SimpleMsg_init( (SimpleMsg*)this, NETMSGTYPE_GetTargetMappings);
}
#endif /* GETTARGETMAPPINGSMSG_H_ */

View File

@@ -0,0 +1,28 @@
#include "GetTargetMappingsRespMsg.h"
#include <common/nodes/TargetMapper.h>
static void GetTargetMappingsRespMsg_release(NetMessage* this)
{
GetTargetMappingsRespMsg* thisCast = (GetTargetMappingsRespMsg*)this;
BEEGFS_KFREE_LIST(&thisCast->mappings, struct TargetMapping, _list);
}
bool GetTargetMappingsRespMsg_deserializePayload(NetMessage* this, DeserializeCtx* ctx)
{
GetTargetMappingsRespMsg* thisCast = (GetTargetMappingsRespMsg*)this;
if (!TargetMappingList_deserialize(ctx, &thisCast->mappings))
return false;
return true;
}
const struct NetMessageOps GetTargetMappingsRespMsg_Ops = {
.serializePayload = _NetMessage_serializeDummy,
.deserializePayload = GetTargetMappingsRespMsg_deserializePayload,
.processIncoming = NetMessage_processIncoming,
.getSupportedHeaderFeatureFlagsMask = NetMessage_getSupportedHeaderFeatureFlagsMask,
.release = GetTargetMappingsRespMsg_release,
};

View File

@@ -0,0 +1,38 @@
#ifndef GETTARGETMAPPINGSRESPMSG_H_
#define GETTARGETMAPPINGSRESPMSG_H_
#include <common/net/message/NetMessage.h>
#include <common/Common.h>
/**
* Note: This message can only be received/deserialized (send/serialization not implemented)
*/
struct GetTargetMappingsRespMsg;
typedef struct GetTargetMappingsRespMsg GetTargetMappingsRespMsg;
static inline void GetTargetMappingsRespMsg_init(GetTargetMappingsRespMsg* this);
// virtual functions
extern bool GetTargetMappingsRespMsg_deserializePayload(NetMessage* this, DeserializeCtx* ctx);
struct GetTargetMappingsRespMsg
{
NetMessage netMessage;
struct list_head mappings; /* TargetMapping */
};
extern const struct NetMessageOps GetTargetMappingsRespMsg_Ops;
void GetTargetMappingsRespMsg_init(GetTargetMappingsRespMsg* this)
{
NetMessage_init(&this->netMessage, NETMSGTYPE_GetTargetMappingsResp,
&GetTargetMappingsRespMsg_Ops);
INIT_LIST_HEAD(&this->mappings);
}
#endif /* GETTARGETMAPPINGSRESPMSG_H_ */

View File

@@ -0,0 +1,257 @@
#include <app/App.h>
#include <common/nodes/Node.h>
#include <common/toolkit/SocketTk.h>
#include <common/net/msghelpers/MsgHelperAck.h>
#include <common/toolkit/ListTk.h>
#include <nodes/NodeStoreEx.h>
#include <app/config/Config.h>
#include "HeartbeatMsgEx.h"
const struct NetMessageOps HeartbeatMsgEx_Ops = {
.serializePayload = HeartbeatMsgEx_serializePayload,
.deserializePayload = HeartbeatMsgEx_deserializePayload,
.processIncoming = __HeartbeatMsgEx_processIncoming,
.getSupportedHeaderFeatureFlagsMask = NetMessage_getSupportedHeaderFeatureFlagsMask,
};
void HeartbeatMsgEx_serializePayload(NetMessage* this, SerializeCtx* ctx)
{
HeartbeatMsgEx* thisCast = (HeartbeatMsgEx*)this;
// instanceVersion
Serialization_serializeUInt64(ctx, thisCast->instanceVersion);
// nicListVersion
Serialization_serializeUInt64(ctx, thisCast->nicListVersion);
// nodeType
Serialization_serializeInt(ctx, thisCast->nodeType);
// nodeID
Serialization_serializeStr(ctx, thisCast->nodeIDLen, thisCast->nodeID);
// ackID
Serialization_serializeStrAlign4(ctx, thisCast->ackIDLen, thisCast->ackID);
// nodeNumID
NumNodeID_serialize(ctx, &thisCast->nodeNumID);
// rootNumID
NumNodeID_serialize(ctx, &thisCast->rootNumID);
// rootIsBuddyMirrored
Serialization_serializeBool(ctx, thisCast->rootIsBuddyMirrored);
// portUDP
Serialization_serializeUShort(ctx, thisCast->portUDP);
// portTCP
Serialization_serializeUShort(ctx, thisCast->portTCP);
// nicList
Serialization_serializeNicList(ctx, thisCast->nicList);
// machineUUID
Serialization_serializeStr(ctx, thisCast->machineUUIDLen, thisCast->machineUUID);
}
bool HeartbeatMsgEx_deserializePayload(NetMessage* this, DeserializeCtx* ctx)
{
HeartbeatMsgEx* thisCast = (HeartbeatMsgEx*)this;
// instanceVersion
if(!Serialization_deserializeUInt64(ctx, &thisCast->instanceVersion) )
return false;
// nicListVersion
if(!Serialization_deserializeUInt64(ctx, &thisCast->nicListVersion) )
return false;
// nodeType
if(!Serialization_deserializeInt(ctx, &thisCast->nodeType) )
return false;
// nodeID
if(!Serialization_deserializeStr(ctx, &thisCast->nodeIDLen, &thisCast->nodeID) )
return false;
// ackID
if(!Serialization_deserializeStrAlign4(ctx, &thisCast->ackIDLen, &thisCast->ackID) )
return false;
// nodeNumID
if(!NumNodeID_deserialize(ctx, &thisCast->nodeNumID) )
return false;
// rootNumID
if(!NumNodeID_deserialize(ctx, &thisCast->rootNumID) )
return false;
// rootIsBuddyMirrored
if(!Serialization_deserializeBool(ctx, &thisCast->rootIsBuddyMirrored) )
return false;
// portUDP
if(!Serialization_deserializeUShort(ctx, &thisCast->portUDP) )
return false;
// portTCP
if(!Serialization_deserializeUShort(ctx, &thisCast->portTCP) )
return false;
// nicList
if(!Serialization_deserializeNicListPreprocess(ctx, &thisCast->rawNicList) )
return false;
// machineUUID
if(!Serialization_deserializeStr(ctx, &thisCast->machineUUIDLen, &thisCast->machineUUID) )
return false;
return true;
}
bool __HeartbeatMsgEx_processIncoming(NetMessage* this, struct App* app,
fhgfs_sockaddr_in* fromAddr, struct Socket* sock, char* respBuf, size_t bufLen)
{
Logger* log = App_getLogger(app);
const char* logContext = "Heartbeat incoming";
HeartbeatMsgEx* thisCast = (HeartbeatMsgEx*)this;
NicAddressList nicList;
Node* node;
NodeConnPool* connPool;
Node* localNode;
NicAddressList localNicList;
NicListCapabilities localNicCaps;
NodeStoreEx* nodes = NULL;
bool isNodeNew;
NumNodeID nodeNumID;
int nodeType;
// check if nodeNumID is set
nodeNumID = HeartbeatMsgEx_getNodeNumID(thisCast);
if(NumNodeID_isZero(&nodeNumID))
{ // shouldn't happen: this node would need to register first to get a nodeNumID assigned
Logger_logFormatted(log, Log_WARNING, logContext,
"Rejecting heartbeat of node without numeric ID: %s (Type: %s)",
HeartbeatMsgEx_getNodeID(thisCast),
Node_nodeTypeToStr(HeartbeatMsgEx_getNodeType(thisCast) ) );
goto ack_resp;
}
// find the corresponding node store for this node type
nodeType = HeartbeatMsgEx_getNodeType(thisCast);
switch(nodeType)
{
case NODETYPE_Meta:
nodes = App_getMetaNodes(app); break;
case NODETYPE_Storage:
nodes = App_getStorageNodes(app); break;
case NODETYPE_Mgmt:
nodes = App_getMgmtNodes(app); break;
default:
{
const char* nodeID = HeartbeatMsgEx_getNodeID(thisCast);
Logger_logErrFormatted(log, logContext, "Invalid node type: %d (%s); ID: %s",
nodeType, Node_nodeTypeToStr(nodeType), nodeID);
goto ack_resp;
} break;
}
// construct node
NicAddressList_init(&nicList);
HeartbeatMsgEx_parseNicList(thisCast, &nicList);
App_lockNicList(app);
node = Node_construct(app,
HeartbeatMsgEx_getNodeID(thisCast), HeartbeatMsgEx_getNodeNumID(thisCast),
HeartbeatMsgEx_getPortUDP(thisCast), HeartbeatMsgEx_getPortTCP(thisCast), &nicList,
nodeType == NODETYPE_Meta || nodeType == NODETYPE_Storage? App_getLocalRDMANicListLocked(app) : NULL);
// (will belong to the NodeStore => no destruct() required)
App_unlockNicList(app);
Node_setNodeAliasAndType(node, NULL, nodeType);
// set local nic capabilities
localNode = App_getLocalNode(app);
Node_cloneNicList(localNode, &localNicList);
connPool = Node_getConnPool(node);
NIC_supportedCapabilities(&localNicList, &localNicCaps);
NodeConnPool_setLocalNicCaps(connPool, &localNicCaps);
// add node to store (or update it)
isNodeNew = NodeStoreEx_addOrUpdateNode(nodes, &node);
if(isNodeNew)
{
bool supportsRDMA = NIC_supportsRDMA(&nicList);
Logger_logFormatted(log, Log_WARNING, logContext,
"New node: %s %s [ID: %hu]; %s",
Node_nodeTypeToStr(nodeType),
HeartbeatMsgEx_getNodeID(thisCast),
HeartbeatMsgEx_getNodeNumID(thisCast).value,
(supportsRDMA ? "RDMA; " : "") );
}
__HeartbeatMsgEx_processIncomingRoot(thisCast, app);
ack_resp:
// send ack
MsgHelperAck_respondToAckRequest(app, HeartbeatMsgEx_getAckID(thisCast), fromAddr, sock,
respBuf, bufLen);
// clean-up
ListTk_kfreeNicAddressListElems(&nicList);
NicAddressList_uninit(&nicList);
ListTk_kfreeNicAddressListElems(&localNicList);
NicAddressList_uninit(&localNicList);
return true;
}
/**
* Handles the contained root information.
*/
void __HeartbeatMsgEx_processIncomingRoot(HeartbeatMsgEx* this, App* app)
{
Logger* log = App_getLogger(app);
const char* logContext = "Heartbeat incoming (root)";
NodeStoreEx* metaNodes;
bool setRootRes;
NodeOrGroup rootOwner = this->rootIsBuddyMirrored
? NodeOrGroup_fromGroup(this->rootNumID.value)
: NodeOrGroup_fromNode(this->rootNumID);
NumNodeID rootNumID = HeartbeatMsgEx_getRootNumID(this);
// check whether root info is defined
if( (HeartbeatMsgEx_getNodeType(this) != NODETYPE_Meta) || (NumNodeID_isZero(&rootNumID)))
return;
// try to apply the contained root info
metaNodes = App_getMetaNodes(app);
setRootRes = NodeStoreEx_setRootOwner(metaNodes, rootOwner, false);
if(setRootRes)
{ // found the very first root
Logger_logFormatted(log, Log_CRITICAL, logContext, "Root (by Heartbeat): %hu",
HeartbeatMsgEx_getRootNumID(this).value );
}
}

View File

@@ -0,0 +1,152 @@
#ifndef HEARTBEATMSG_H_
#define HEARTBEATMSG_H_
#include <common/net/message/NetMessage.h>
#include <common/net/sock/NetworkInterfaceCard.h>
struct HeartbeatMsgEx;
typedef struct HeartbeatMsgEx HeartbeatMsgEx;
static inline void HeartbeatMsgEx_init(HeartbeatMsgEx* this);
static inline void HeartbeatMsgEx_initFromNodeData(HeartbeatMsgEx* this,
const char* nodeID, NumNodeID nodeNumID, int nodeType, NicAddressList* nicList);
extern void __HeartbeatMsgEx_processIncomingRoot(HeartbeatMsgEx* this, struct App* app);
// virtual functions
extern void HeartbeatMsgEx_serializePayload(NetMessage* this, SerializeCtx* ctx);
extern bool HeartbeatMsgEx_deserializePayload(NetMessage* this, DeserializeCtx* ctx);
extern bool __HeartbeatMsgEx_processIncoming(NetMessage* this, struct App* app,
fhgfs_sockaddr_in* fromAddr, struct Socket* sock, char* respBuf, size_t bufLen);
// inliners
static inline void HeartbeatMsgEx_parseNicList(HeartbeatMsgEx* this,
NicAddressList* outNicList);
// getters & setters
static inline const char* HeartbeatMsgEx_getNodeID(HeartbeatMsgEx* this);
static inline NumNodeID HeartbeatMsgEx_getNodeNumID(HeartbeatMsgEx* this);
static inline int HeartbeatMsgEx_getNodeType(HeartbeatMsgEx* this);
static inline NumNodeID HeartbeatMsgEx_getRootNumID(HeartbeatMsgEx* this);
static inline const char* HeartbeatMsgEx_getAckID(HeartbeatMsgEx* this);
static inline void HeartbeatMsgEx_setPorts(HeartbeatMsgEx* this,
uint16_t portUDP, uint16_t portTCP);
static inline uint16_t HeartbeatMsgEx_getPortUDP(HeartbeatMsgEx* this);
static inline uint16_t HeartbeatMsgEx_getPortTCP(HeartbeatMsgEx* this);
struct HeartbeatMsgEx
{
NetMessage netMessage;
unsigned nodeIDLen;
const char* nodeID;
int nodeType;
NumNodeID nodeNumID;
NumNodeID rootNumID; // 0 means unknown/undefined
bool rootIsBuddyMirrored;
uint64_t instanceVersion; // not used currently
uint64_t nicListVersion; // not used currently
uint16_t portUDP; // 0 means "undefined"
uint16_t portTCP; // 0 means "undefined"
unsigned ackIDLen;
const char* ackID;
const char* machineUUID;
unsigned machineUUIDLen;
// for serialization
NicAddressList* nicList; // not owned by this object
// for deserialization
RawList rawNicList;
};
extern const struct NetMessageOps HeartbeatMsgEx_Ops;
void HeartbeatMsgEx_init(HeartbeatMsgEx* this)
{
NetMessage_init(&this->netMessage, NETMSGTYPE_Heartbeat, &HeartbeatMsgEx_Ops);
}
/**
* @param nodeID just a reference, so do not free it as long as you use this object
* @param nicList just a reference, so do not free it as long as you use this object
*/
void HeartbeatMsgEx_initFromNodeData(HeartbeatMsgEx* this,
const char* nodeID, NumNodeID nodeNumID, int nodeType, NicAddressList* nicList)
{
HeartbeatMsgEx_init(this);
this->nodeID = nodeID;
this->nodeIDLen = strlen(nodeID);
this->nodeNumID = nodeNumID;
this->nodeType = nodeType;
this->rootNumID = (NumNodeID){0}; // 0 means undefined/unknown
this->rootIsBuddyMirrored = false;
this->instanceVersion = 0; // reserverd for future use
this->nicListVersion = 0; // reserverd for future use
this->nicList = nicList;
this->portUDP = 0; // 0 means "undefined"
this->portTCP = 0; // 0 means "undefined"
this->ackID = "";
this->ackIDLen = 0;
this->machineUUID = ""; // not currently needed on the client
this->machineUUIDLen = 0;
}
void HeartbeatMsgEx_parseNicList(HeartbeatMsgEx* this, NicAddressList* outNicList)
{
Serialization_deserializeNicList(&this->rawNicList, outNicList);
}
const char* HeartbeatMsgEx_getNodeID(HeartbeatMsgEx* this)
{
return this->nodeID;
}
NumNodeID HeartbeatMsgEx_getNodeNumID(HeartbeatMsgEx* this)
{
return this->nodeNumID;
}
int HeartbeatMsgEx_getNodeType(HeartbeatMsgEx* this)
{
return this->nodeType;
}
NumNodeID HeartbeatMsgEx_getRootNumID(HeartbeatMsgEx* this)
{
return this->rootNumID;
}
const char* HeartbeatMsgEx_getAckID(HeartbeatMsgEx* this)
{
return this->ackID;
}
void HeartbeatMsgEx_setPorts(HeartbeatMsgEx* this, uint16_t portUDP, uint16_t portTCP)
{
this->portUDP = portUDP;
this->portTCP = portTCP;
}
uint16_t HeartbeatMsgEx_getPortUDP(HeartbeatMsgEx* this)
{
return this->portUDP;
}
uint16_t HeartbeatMsgEx_getPortTCP(HeartbeatMsgEx* this)
{
return this->portTCP;
}
#endif /*HEARTBEATMSG_H_*/

View File

@@ -0,0 +1,65 @@
#include <common/nodes/Node.h>
#include <components/DatagramListener.h>
#include <common/toolkit/SocketTk.h>
#include <app/App.h>
#include "HeartbeatMsgEx.h"
#include "HeartbeatRequestMsgEx.h"
const struct NetMessageOps HeartbeatRequestMsgEx_Ops = {
.serializePayload = SimpleMsg_serializePayload,
.deserializePayload = SimpleMsg_deserializePayload,
.processIncoming = __HeartbeatRequestMsgEx_processIncoming,
.getSupportedHeaderFeatureFlagsMask = NetMessage_getSupportedHeaderFeatureFlagsMask,
};
bool __HeartbeatRequestMsgEx_processIncoming(NetMessage* this, struct App* app,
fhgfs_sockaddr_in* fromAddr, struct Socket* sock, char* respBuf, size_t bufLen)
{
Logger* log = App_getLogger(app);
const char* logContext = "HeartbeatRequest incoming";
Config* cfg = App_getConfig(app);
Node* localNode = App_getLocalNode(app);
NodeString alias;
NumNodeID localNodeNumID = Node_getNumID(localNode);
NicAddressList nicList;
HeartbeatMsgEx hbMsg;
unsigned respLen;
bool serializeRes;
ssize_t sendRes;
Node_cloneNicList(localNode, &nicList);
Node_copyAlias(localNode, &alias);
HeartbeatMsgEx_initFromNodeData(&hbMsg, alias.buf, localNodeNumID, NODETYPE_Client, &nicList);
HeartbeatMsgEx_setPorts(&hbMsg, Config_getConnClientPort(cfg), 0);
respLen = NetMessage_getMsgLength( (NetMessage*)&hbMsg);
serializeRes = NetMessage_serialize( (NetMessage*)&hbMsg, respBuf, bufLen);
if(unlikely(!serializeRes) )
{
Logger_logErrFormatted(log, logContext, "Unable to serialize response");
goto err_uninit;
}
if(fromAddr)
{ // datagram => sync via dgramLis send method
DatagramListener* dgramLis = App_getDatagramListener(app);
sendRes = DatagramListener_sendto_kernel(dgramLis, respBuf, respLen, 0, fromAddr);
}
else
sendRes = Socket_sendto_kernel(sock, respBuf, respLen, 0, NULL);
if(unlikely(sendRes <= 0) )
Logger_logErrFormatted(log, logContext, "Send error. ErrCode: %lld", (long long)sendRes);
err_uninit:
ListTk_kfreeNicAddressListElems(&nicList);
NicAddressList_uninit(&nicList);
return true;
}

Some files were not shown because too many files have changed in this diff Show More