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

View File

@@ -0,0 +1,351 @@
#include <common/toolkit/HashTk.h>
#include <crypto/hash.h>
#define get16bits(d) (*((const uint16_t *) (d)))
#define HashTkDefaultHash HASHTK_HALFMD4
//#define HashTkDefaultHash HASHTK_HSIEHHASH32
#define Hashtk_HALFMD4_IN_BUF_SIZE 8
#define HashTk_HALFMD4_OUT_BUF_SIZE 4
#define HashTk_INT_BYTES 4
#define HashTk_HALFMD4_MAJOR_BUFPOS 1 // as in ext4
#define HashTk_HALFMD4_MINOR_BUFPOS 2
#ifdef KERNEL_HAS_HALF_MD4_TRANSFORM
#include <linux/types.h>
#include <linux/cryptohash.h>
#else
/* half_md4_transform and macros taken from lib/halfmd4.c */
/* F, G and H are basic MD4 functions: selection, majority, parity */
#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
#define G(x, y, z) (((x) & (y)) + (((x) ^ (y)) & (z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
/*
* The generic round function. The application is so specific that
* we don't bother protecting all the arguments with parens, as is generally
* good macro practice, in favor of extra legibility.
* Rotation is separate from addition to prevent recomputation
*/
#define ROUND(f, a, b, c, d, x, s) \
(a += f(b, c, d) + x, a = rol32(a, s))
#define K1 0
#define K2 013240474631UL
#define K3 015666365641UL
/*
* Basic cut-down MD4 transform. Returns only 32 bits of result.
*/
static __u32 half_md4_transform(__u32 buf[4], __u32 const in[8])
{
__u32 a = buf[0], b = buf[1], c = buf[2], d = buf[3];
/* Round 1 */
ROUND(F, a, b, c, d, in[0] + K1, 3);
ROUND(F, d, a, b, c, in[1] + K1, 7);
ROUND(F, c, d, a, b, in[2] + K1, 11);
ROUND(F, b, c, d, a, in[3] + K1, 19);
ROUND(F, a, b, c, d, in[4] + K1, 3);
ROUND(F, d, a, b, c, in[5] + K1, 7);
ROUND(F, c, d, a, b, in[6] + K1, 11);
ROUND(F, b, c, d, a, in[7] + K1, 19);
/* Round 2 */
ROUND(G, a, b, c, d, in[1] + K2, 3);
ROUND(G, d, a, b, c, in[3] + K2, 5);
ROUND(G, c, d, a, b, in[5] + K2, 9);
ROUND(G, b, c, d, a, in[7] + K2, 13);
ROUND(G, a, b, c, d, in[0] + K2, 3);
ROUND(G, d, a, b, c, in[2] + K2, 5);
ROUND(G, c, d, a, b, in[4] + K2, 9);
ROUND(G, b, c, d, a, in[6] + K2, 13);
/* Round 3 */
ROUND(H, a, b, c, d, in[3] + K3, 3);
ROUND(H, d, a, b, c, in[7] + K3, 9);
ROUND(H, c, d, a, b, in[2] + K3, 11);
ROUND(H, b, c, d, a, in[6] + K3, 15);
ROUND(H, a, b, c, d, in[1] + K3, 3);
ROUND(H, d, a, b, c, in[5] + K3, 9);
ROUND(H, c, d, a, b, in[0] + K3, 11);
ROUND(H, b, c, d, a, in[4] + K3, 15);
buf[0] += a;
buf[1] += b;
buf[2] += c;
buf[3] += d;
return buf[1]; /* "most hashed" word */
}
#endif
static uint32_t HashTk_HsiehHash32(const char* data, int len);
static void HashTk_string2HashBufSigned(const char *msg, int len, __u32 *buf, int num);
/**
* Copied from ext4 hash.c (str2hashbuf_signed() )
*/
static void HashTk_string2HashBufSigned(const char *msg, int len, __u32 *buf, int num)
{
__u32 pad, val;
int i;
const signed char *scp = (const signed char *) msg;
pad = (__u32)len | ((__u32)len << 8);
pad |= pad << 16;
val = pad;
if (len > num*4)
len = num * 4;
for (i = 0; i < len; i++) {
if ((i % 4) == 0)
val = pad;
val = ((int) scp[i]) + (val << 8);
if ((i % 4) == 3) {
*buf++ = val;
val = pad;
num--;
}
}
if (--num >= 0)
*buf++ = val;
while (--num >= 0)
*buf++ = pad;
}
/**
* Note: This is the Hsieh hash function, which is available under old BSD-style license.
* (It performs very well on x86 and PowerPC archs compared to other famous hash functions.)
*
* @data the buffer for which you want the hash value to be computed (arbitraty length)
* @len length of the data buffer
*/
uint32_t HashTk_HsiehHash32(const char* data, int len)
{
uint32_t hash = len, tmp;
int rem;
if(unlikely(len <= 0 || data == NULL) )
return 0;
rem = len & 3;
len >>= 2;
/* Main loop */
for(; len > 0; len--)
{
hash += get16bits(data);
tmp = (get16bits(data+2) << 11) ^ hash;
hash = (hash << 16) ^ tmp;
data += 2 * sizeof(uint16_t);
hash += hash >> 11;
}
/* Handle end cases */
switch(rem)
{
case 3:
hash += get16bits(data);
hash ^= hash << 16;
hash ^= data[sizeof(uint16_t)] << 18;
hash += hash >> 11;
break;
case 2:
hash += get16bits(data);
hash ^= hash << 11;
hash += hash >> 17;
break;
case 1:
hash += *data;
hash ^= hash << 10;
hash += hash >> 1;
}
/* Force "avalanching" of final 127 bits */
hash ^= hash << 3;
hash += hash >> 5;
hash ^= hash << 4;
hash += hash >> 17;
hash ^= hash << 25;
hash += hash >> 6;
return hash;
}
/**
* Do the halfMD4 hash computation.
* Note: OutBuf must be an array of size HashTk_HALFMD4_OUT_BUF_SIZE
*/
static void HashTk_halfMD4(const char* data, int len, uint32_t* outBuf)
{
uint32_t inBuf[Hashtk_HALFMD4_IN_BUF_SIZE];
int maxMD4StrLen = Hashtk_HALFMD4_IN_BUF_SIZE * HashTk_INT_BYTES; // 32
const char* dataPtr = data;
int remainingLen = len;
/* Initialize the default seed for the hash checksum functions, magic numbers taken from
* ext4fs_dirhash() */
outBuf[0] = 0x67452301;
outBuf[1] = 0xefcdab89;
outBuf[2] = 0x98badcfe;
outBuf[3] = 0x10325476;
while (remainingLen > 0) {
HashTk_string2HashBufSigned(dataPtr, len, inBuf, Hashtk_HALFMD4_IN_BUF_SIZE);
half_md4_transform(outBuf, inBuf);
remainingLen -= maxMD4StrLen;
dataPtr += maxMD4StrLen;
}
}
uint32_t HashTk_hash32(HashTkHashTypes hashType, const char* data, int len)
{
switch (hashType)
{
default:
{
printk_fhgfs(KERN_INFO, "Unknown hashtype: %d\n", hashType);
hashType = HashTkDefaultHash;
}
BEEGFS_FALLTHROUGH;
case HASHTK_HSIEHHASH32:
{
return HashTk_HsiehHash32(data, len);
} break;
case HASHTK_HALFMD4:
{
uint32_t buf[HashTk_HALFMD4_OUT_BUF_SIZE];
uint32_t majHash;
HashTk_halfMD4(data, len, buf);
majHash = buf[HashTk_HALFMD4_MAJOR_BUFPOS];
return majHash;
} break;
}
}
/**
* Note: This generates the 64bit hash by computing two 32bit hashes for the first and second half
* of the data buf.
*
* @data the buffer for which you want the hash value to be computed (arbitraty length)
* @len length of the data buffer
*/
uint64_t HashTk_hash64(HashTkHashTypes hashType, const char* data, int len)
{
uint64_t hash64;
switch (hashType)
{
default:
{
printk_fhgfs(KERN_INFO, "Unknown hashtype: %d\n", hashType);
hashType = HashTkDefaultHash;
}
BEEGFS_FALLTHROUGH;
case HASHTK_HSIEHHASH32:
{
int len1stHalf = len / 2;
int len2ndHalf = len - len1stHalf;
uint64_t high = HashTk_HsiehHash32(data, len1stHalf);
uint64_t low = HashTk_HsiehHash32(&data[len1stHalf], len2ndHalf);
hash64 = (high << 32) | low;
} break;
case HASHTK_HALFMD4:
{
uint32_t buf[HashTk_HALFMD4_OUT_BUF_SIZE];
uint32_t majHash;
uint32_t minHash;
HashTk_halfMD4(data, len, buf);
majHash = buf[HashTk_HALFMD4_MAJOR_BUFPOS];
minHash = buf[HashTk_HALFMD4_MINOR_BUFPOS];
hash64 = (uint64_t) majHash << 32 | (uint64_t) minHash;
} break;
}
return hash64;
}
// Generates sha256 hash using the kernel crypto interface.
int HashTk_sha256(const unsigned char* data, unsigned int dataLen, unsigned char* outHash)
{
const char* hashAlgName = "sha256";
struct crypto_shash *alg;
struct shash_desc *sdesc;
int res = 0;
alg = crypto_alloc_shash(hashAlgName, 0, 0);
if(IS_ERR(alg))
{
printk_fhgfs(KERN_ERR, "Allocating shash failed: %ld\n", PTR_ERR(alg));
return -1;
}
sdesc = kmalloc(crypto_shash_descsize(alg), GFP_KERNEL);
if (sdesc == NULL)
{
printk_fhgfs(KERN_ERR, "Allocating hash memory failed\n");
crypto_free_shash(alg);
return -1;
}
sdesc->tfm = alg;
res = crypto_shash_digest(sdesc, data, dataLen, outHash);
if (res != 0)
{
printk_fhgfs(KERN_ERR, "Calculating hash failed: %d\n", res);
}
kfree(sdesc);
crypto_free_shash(alg);
return res;
}
// Generates sha256 hash from the input byte slice and returns the auth secret containing the
// 8 most significant bytes of the hash in little endian order. Matches the behavior of other
// implementations.
int HashTk_authHash(const unsigned char* data, unsigned int dataLen, uint64_t* outHash)
{
int res;
unsigned char buf[32];
res = HashTk_sha256(data, dataLen, buf);
if (res != 0) {
return res;
}
*outHash = 0;
for(int i = 7; i >= 0; --i)
{
*outHash <<= 8;
*outHash += buf[i];
}
return 0;
}

View File

@@ -0,0 +1,36 @@
#ifndef BUFFERTK_H_
#define BUFFERTK_H_
#include <common/Common.h>
enum HashTkHashTypes;
typedef enum HashTkHashTypes HashTkHashTypes;
extern uint32_t HashTk_hash32(HashTkHashTypes hashType, const char* data, int len);
extern uint64_t HashTk_hash64(HashTkHashTypes hashType, const char* data, int len);
static inline uint64_t HashTk_hash(HashTkHashTypes hashType, size_t hashSize,
const char* data, int len);
int HashTk_sha256(const unsigned char* data, unsigned dataLen, unsigned char* outHash);
int HashTk_authHash(const unsigned char* data, unsigned dataLen, uint64_t* outHash);
enum HashTkHashTypes
{
HASHTK_HSIEHHASH32 = 0,
HASHTK_HALFMD4, // as used by ext4
};
/**
* Caller decides if it wants a 32- or 64-bit hash
*/
uint64_t HashTk_hash(HashTkHashTypes hashType, size_t hashSize, const char* data, int len)
{
if (hashSize == 64)
return HashTk_hash64(hashType, data, len);
else
return HashTk_hash32(hashType, data, len);
}
#endif /* BUFFERTK_H_ */

View File

@@ -0,0 +1,185 @@
#include <common/nodes/ConnectionListIter.h>
#include <common/net/sock/NicAddressListIter.h>
#include <common/net/sock/NicAddressStatsListIter.h>
#include <common/toolkit/list/StrCpyListIter.h>
#include <common/toolkit/list/UInt16ListIter.h>
#include <common/toolkit/tree/PointerRBTree.h>
#include <common/toolkit/tree/PointerRBTreeIter.h>
#include "ListTk.h"
#include <linux/sort.h>
struct nicaddr_sort_entry {
StrCpyList* preferences;
NicAddress* addr;
};
static int nicaddr_sort_comp(const void* l, const void* r)
{
const struct nicaddr_sort_entry* lhs = l;
const struct nicaddr_sort_entry* rhs = r;
StrCpyListIter it;
StrCpyListIter_init(&it, lhs->preferences);
while (!StrCpyListIter_end(&it)) {
const char* value = StrCpyListIter_value(&it);
if (strcmp(value, lhs->addr->name) == 0)
return -1;
if (strcmp(value, rhs->addr->name) == 0)
return 1;
StrCpyListIter_next(&it);
}
if (NicAddress_preferenceComp(lhs->addr, rhs->addr))
return -1;
if (NicAddress_preferenceComp(rhs->addr, lhs->addr))
return 1;
return 0;
}
void ListTk_cloneNicAddressList(NicAddressList* nicList, NicAddressList* nicListClone, bool includeTcp)
{
NicAddressListIter iter;
NicAddressList_init(nicListClone);
NicAddressListIter_init(&iter, nicList);
for( ; !NicAddressListIter_end(&iter); NicAddressListIter_next(&iter) )
{
NicAddress* nicAddr = NicAddressListIter_value(&iter);
if (includeTcp || nicAddr->nicType != NICADDRTYPE_STANDARD)
{
NicAddress* nicAddrClone;
// clone element
nicAddrClone = (NicAddress*)os_kmalloc(sizeof(NicAddress) );
memcpy(nicAddrClone, nicAddr, sizeof(NicAddress) );
// append to the clone list
NicAddressList_append(nicListClone, nicAddrClone);
}
}
}
/**
* Returns a sorted clone of a nicList.
*
* Note: the comparison implemented here is a valid only if preferences contains
* all possible names ever encountered, or none at all.
*/
void ListTk_cloneSortNicAddressList(NicAddressList* nicList, NicAddressList* nicListClone,
StrCpyList* preferences)
{
NicAddressListIter listIter;
struct nicaddr_sort_entry* list, *p;
/* i'm so sorry. we can't indicate failure here without a lot of work in App, and the
* lists are usually tiny anyway. */
list = kcalloc(NicAddressList_length(nicList), sizeof(*list), GFP_NOFS | __GFP_NOFAIL);
p = list;
NicAddressListIter_init(&listIter, nicList);
while (!NicAddressListIter_end(&listIter)) {
p->preferences = preferences;
p->addr = NicAddressListIter_value(&listIter);
NicAddressListIter_next(&listIter);
p++;
}
sort(list, NicAddressList_length(nicList), sizeof(*list), nicaddr_sort_comp, NULL);
/* *maybe* the clone already contains elements, don't rely on its size */
p = list;
NicAddressList_init(nicListClone);
while (NicAddressList_length(nicList) != NicAddressList_length(nicListClone)) {
NicAddress* clone = os_kmalloc(sizeof(*clone));
memcpy(clone, p->addr, sizeof(*clone));
NicAddressList_append(nicListClone, clone);
p++;
}
kfree(list);
}
void ListTk_kfreeNicAddressListElems(NicAddressList* nicList)
{
NicAddressListIter nicIter;
NicAddressListIter_init(&nicIter, nicList);
for( ; !NicAddressListIter_end(&nicIter); NicAddressListIter_next(&nicIter) )
{
NicAddress* nicAddr = NicAddressListIter_value(&nicIter);
kfree(nicAddr);
}
}
void ListTk_kfreeNicAddressStatsListElems(NicAddressStatsList* nicStatsList)
{
NicAddressStatsListIter nicStatsIter;
NicAddressStatsListIter_init(&nicStatsIter, nicStatsList);
for( ; !NicAddressStatsListIter_end(&nicStatsIter); NicAddressStatsListIter_next(&nicStatsIter) )
{
NicAddressStats* nicStats = NicAddressStatsListIter_value(&nicStatsIter);
NicAddressStats_uninit(nicStats);
kfree(nicStats);
}
}
void ListTk_copyUInt16ListToVec(UInt16List* srcList, UInt16Vec* destVec)
{
UInt16ListIter listIter;
UInt16ListIter_init(&listIter, srcList);
for( ; !UInt16ListIter_end(&listIter); UInt16ListIter_next(&listIter) )
{
int currentElem = UInt16ListIter_value(&listIter);
UInt16Vec_append(destVec, currentElem);
}
}
/**
* @param outPos zero-based list position of the searchStr if found, undefined otherwise
*/
bool ListTk_listContains(char* searchStr, StrCpyList* list, ssize_t* outPos)
{
StrCpyListIter iter;
(*outPos) = 0;
StrCpyListIter_init(&iter, list);
for( ; !StrCpyListIter_end(&iter); StrCpyListIter_next(&iter) )
{
char* currentElem = StrCpyListIter_value(&iter);
if(!strcmp(searchStr, currentElem) )
return true;
(*outPos)++;
}
(*outPos) = -1;
return false;
}

View File

@@ -0,0 +1,26 @@
#ifndef LISTTK_H_
#define LISTTK_H_
#include <common/Common.h>
#include <common/net/sock/NicAddressList.h>
#include <common/net/sock/NicAddressStatsList.h>
#include <common/nodes/ConnectionList.h>
#include <common/toolkit/list/StrCpyList.h>
#include <common/toolkit/vector/StrCpyVec.h>
#include <common/toolkit/vector/UInt16Vec.h>
/* includeTcp indicates whether or not to include TCP NICs in the cloned list */
extern void ListTk_cloneNicAddressList(NicAddressList* nicList, NicAddressList* nicListClone, bool includeTcp);
extern void ListTk_cloneSortNicAddressList(NicAddressList* nicList, NicAddressList* nicListClone,
StrCpyList* preferences);
extern void ListTk_copyUInt16ListToVec(UInt16List* srcList, UInt16Vec* destVec);
extern void ListTk_kfreeNicAddressListElems(NicAddressList* nicList);
extern void ListTk_kfreeNicAddressStatsListElems(NicAddressStatsList* nicStatsList);
extern bool ListTk_listContains(char* searchStr, StrCpyList* list, ssize_t* outPos);
#endif /*LISTTK_H_*/

View File

@@ -0,0 +1,46 @@
#ifndef LOCKINGTK_H_
#define LOCKINGTK_H_
#include <common/Common.h>
#include <common/storage/StorageDefinitions.h>
static inline const char* LockingTk_lockTypeToStr(int entryLockType);
/**
* @param entryLockType ENTRYLOCKTYPE_...
* @return pointer to static string (no freeing by caller required)
*/
const char* LockingTk_lockTypeToStr(int entryLockType)
{
if(entryLockType & ENTRYLOCKTYPE_NOWAIT)
{
if(entryLockType & ENTRYLOCKTYPE_UNLOCK)
return "unlock|nowait";
else
if(entryLockType & ENTRYLOCKTYPE_EXCLUSIVE)
return "exclusive|nowait";
else
if(entryLockType & ENTRYLOCKTYPE_SHARED)
return "shared|nowait";
else
return "unknown|nowait";
}
else
{ // waiting allowed
if(entryLockType & ENTRYLOCKTYPE_UNLOCK)
return "unlock|wait";
else
if(entryLockType & ENTRYLOCKTYPE_EXCLUSIVE)
return "exclusive|wait";
else
if(entryLockType & ENTRYLOCKTYPE_SHARED)
return "shared|wait";
else
return "unknown|wait";
}
}
#endif /* LOCKINGTK_H_ */

View File

@@ -0,0 +1,164 @@
#ifndef LOOKUPINTENTINFO_H_
#define LOOKUPINTENTINFO_H_
#include <app/App.h>
#include <common/Common.h>
#include <common/net/message/storage/lookup/LookupIntentRespMsg.h>
#include <common/nodes/Node.h>
#include <common/storage/Path.h>
#include <common/storage/StorageErrors.h>
#include <common/storage/EntryInfo.h>
#include <common/storage/PathInfo.h>
#include <common/storage/StorageErrors.h>
#include <common/storage/StorageDefinitions.h>
#include <common/storage/striping/StripePattern.h>
#include <common/toolkit/list/UInt16List.h>
struct LookupIntentInfoOut;
typedef struct LookupIntentInfoOut LookupIntentInfoOut;
static inline void LookupIntentInfoOut_initFromRespMsg(LookupIntentInfoOut* this,
LookupIntentRespMsg* respMsg);
static inline void LookupIntentInfoOut_setEntryInfoPtr(LookupIntentInfoOut* this,
EntryInfo* entryInfo);
static inline void LookupIntentInfoOut_setStripePattern(LookupIntentInfoOut* this,
StripePattern *pattern);
static inline void LookupIntentInfoOut_uninit(LookupIntentInfoOut* this);
/**
* Out-Args for _lookupCreateStat operations. Init only with LookupIntentInfoOut_prepare().
*
* Note: This needs preparation by the same caller that does init of LookupIntentInfoIn
* (to assign some out-pointers before the actual method is called).
*/
struct LookupIntentInfoOut
{
int responseFlags; // combination of LOOKUPINTENTRESPMSG_FLAG_...
int lookupRes;
int statRes;
int createRes; // FhgfsOpsErr_...
int revalidateRes; // FhgfsOpsErr_SUCCESS if still valid, any other value otherwise
int openRes;
fhgfs_stat* fhgfsStat;
EntryInfo* entryInfoPtr; // Note: Not owned by this object.
// Only deserialized if either lookup or create was successful.
int revalidateUpdatedFlags;
unsigned fileHandleIDLen;
const char* fileHandleID;
// only set if open was successful
PathInfo pathInfo;
StripePattern* stripePattern;
};
static inline void LookupIntentInfoOut_prepare(LookupIntentInfoOut* this,
EntryInfo* outEntryInfo, fhgfs_stat* outFhgfsStat)
{
// note: we only assign the pointers to the out-structs here
this->entryInfoPtr = outEntryInfo;
this->fhgfsStat = outFhgfsStat;
this->responseFlags = 0;
this->lookupRes = FhgfsOpsErr_INTERNAL;
this->statRes = FhgfsOpsErr_INTERNAL;
this->createRes = FhgfsOpsErr_INTERNAL;
this->revalidateRes = FhgfsOpsErr_INTERNAL;
this->openRes = FhgfsOpsErr_INTERNAL;
this->stripePattern = NULL;
}
void LookupIntentInfoOut_initFromRespMsg(LookupIntentInfoOut* this,
LookupIntentRespMsg* respMsg)
{
this->responseFlags = respMsg->responseFlags;
this->lookupRes = respMsg->lookupResult;
if (this->responseFlags & LOOKUPINTENTRESPMSG_FLAG_CREATE)
this->createRes = respMsg->createResult;
if (respMsg->responseFlags & LOOKUPINTENTRESPMSG_FLAG_STAT)
{
this->statRes = respMsg->statResult;
if (this->statRes == FhgfsOpsErr_SUCCESS)
StatData_getOsStat(&respMsg->statData, this->fhgfsStat);
}
if (respMsg->responseFlags & LOOKUPINTENTRESPMSG_FLAG_REVALIDATE)
{
this->revalidateRes = respMsg->revalidateResult;
/* no need to fill in EntryInfo on revalidate, we (the client) already have it. Only flags
* might need to be updated. */
this->revalidateUpdatedFlags = respMsg->entryInfo.featureFlags;
}
else
if (respMsg->lookupResult == FhgfsOpsErr_SUCCESS || respMsg->createResult == FhgfsOpsErr_SUCCESS)
EntryInfo_dup(&respMsg->entryInfo, this->entryInfoPtr);
// only provided by the server on open
if (respMsg->responseFlags & LOOKUPINTENTRESPMSG_FLAG_OPEN)
{
this->openRes = respMsg->openResult;
if (respMsg->openResult == FhgfsOpsErr_SUCCESS)
{
this->fileHandleIDLen = respMsg->fileHandleIDLen;
this->fileHandleID = kstrndup(respMsg->fileHandleID, respMsg->fileHandleIDLen, GFP_NOFS);
PathInfo_dup(&respMsg->pathInfo, &this->pathInfo);
this->stripePattern =
StripePattern_createFromBuf(respMsg->patternStart, respMsg->patternLength);
}
}
}
void LookupIntentInfoOut_setEntryInfoPtr(LookupIntentInfoOut* this, EntryInfo* entryInfo)
{
this->entryInfoPtr = entryInfo;
}
void LookupIntentInfoOut_setStripePattern(LookupIntentInfoOut* this, StripePattern *pattern)
{
this->stripePattern = pattern;
}
/**
* Uninitialize (free) LookupIntentInfoOut values
*/
void LookupIntentInfoOut_uninit(LookupIntentInfoOut* this)
{
// Free EntryInfo values
if ( (this->entryInfoPtr) &&
(this->createRes == FhgfsOpsErr_SUCCESS || this->lookupRes == FhgfsOpsErr_SUCCESS) )
EntryInfo_uninit(this->entryInfoPtr);
// Destruct PathInfo
if (this->openRes == FhgfsOpsErr_SUCCESS)
{ // unitialize values only set on open success and if there was an open at all
PathInfo_uninit(&this->pathInfo);
if (this->stripePattern)
StripePattern_virtualDestruct(this->stripePattern);
}
}
#endif /*LOOKUPINTENTINFO_H_*/

View File

@@ -0,0 +1,40 @@
#ifndef OPEN_MATHTK_H_
#define OPEN_MATHTK_H_
#include <common/Common.h>
static inline unsigned MathTk_log2Int32(unsigned value);
static inline bool MathTk_isPowerOfTwo(unsigned value);
/**
* Base 2 logarithm.
*
* See log2Int64() for details.
*/
unsigned MathTk_log2Int32(unsigned value)
{
/* __builtin_clz: Count leading zeros - returns the number of leading 0-bits in x, starting
* at the most significant bit position. If x is 0, the result is undefined. */
// (note: 8 is bits_per_byte)
unsigned result = (sizeof(value) * 8) - 1 - __builtin_clz(value);
return result;
}
/**
* Checks whether there is only a single bit set in value, in which case value is a power of
* two.
*
* @param value may not be 0 (result is undefined in that case).
* @return true if only a single bit is set (=> value is a power of two), false otherwise
*/
bool MathTk_isPowerOfTwo(unsigned value)
{
//return ( (x != 0) && !(x & (x - 1) ) ); // this version is compatible with value==0
return !(value & (value - 1) );
}
#endif /* OPEN_MATHTK_H_ */

View File

@@ -0,0 +1,826 @@
#include <app/App.h>
#include <common/net/message/control/GenericResponseMsg.h>
#include <common/nodes/MirrorBuddyGroupMapper.h>
#include <common/nodes/Node.h>
#include <common/nodes/NodeConnPool.h>
#include <common/nodes/Node.h>
#include <common/nodes/TargetStateStore.h>
#include <nodes/NodeStoreEx.h>
#include <toolkit/NoAllocBufferStore.h>
#include "MessagingTk.h"
#define MSGTK_KMALLOC_RECV_BUF_LEN (4*1024) /* kmalloc-style recv is only ok for small replies */
#define MSGTK_STATE_SLEEP_MS 5000 /* how long to sleep if target state not good/offline */
#define MSGTK_INFINITE_RETRY_WAIT_MS 5000 // how long to wait if peer asks for retry
/**
* Note: rrArgs->outRespBuf must be returned/freed by the caller (depending on respBufType)
* @param sock socket to use. If null, one will be pulled from Node's pool
*/
FhgfsOpsErr MessagingTk_requestResponseWithRRArgsSock(App* app,
RequestResponseArgs* rrArgs, Socket* sock)
{
Logger* log = App_getLogger(app);
const char* logContext = "Messaging (RPC)";
bool infiniteRetries = rrArgs->numRetries ? false : true;
unsigned currentRetryNum = 0;
FhgfsOpsErr commRes;
bool wasIndirectCommErr = false;
for( ; ; ) // retry loop
{
App_incNumRPCs(app);
commRes = __MessagingTk_requestResponseWithRRArgsComm(app, rrArgs, NULL, &wasIndirectCommErr, sock);
if(likely(commRes == FhgfsOpsErr_SUCCESS) )
return FhgfsOpsErr_SUCCESS;
else
if (fatal_signal_pending(current))
{ // no retry allowed in this situation
return FhgfsOpsErr_INTERRUPTED;
}
else
if(!Node_getIsActive(rrArgs->node) )
{ // no retry allowed in this situation
return FhgfsOpsErr_UNKNOWNNODE;
}
else
if(commRes == FhgfsOpsErr_WOULDBLOCK)
return FhgfsOpsErr_COMMUNICATION; // no retries in this case
else
if( (commRes == FhgfsOpsErr_AGAIN) && App_getConnRetriesEnabled(app) )
{ // retry infinitely
currentRetryNum = 0;
Thread_sleep(MSGTK_INFINITE_RETRY_WAIT_MS);
continue;
}
else
if(commRes != FhgfsOpsErr_COMMUNICATION)
{ // no retry allowed in this situation
return commRes;
}
if(App_getConnRetriesEnabled(app) &&
(infiniteRetries || (currentRetryNum < rrArgs->numRetries) ) )
{ // we have a retry left
MessagingTk_waitBeforeRetry(currentRetryNum);
currentRetryNum++;
if(currentRetryNum == 1 // log retry message only on first retry (to not spam the log)
&& !(rrArgs->logFlags & REQUESTRESPONSEARGS_LOGFLAG_RETRY) )
{
NodeString nodeAndType;
Node_copyAliasWithTypeStr(rrArgs->node, &nodeAndType);
Logger_logFormatted(log, Log_NOTICE, logContext,
"Retrying communication with node: %s", nodeAndType.buf);
Logger_logFormatted(log, Log_DEBUG, logContext,
"Message type: %hu", NetMessage_getMsgType(rrArgs->requestMsg) );
}
}
else
{ // no more retries left
return FhgfsOpsErr_COMMUNICATION;
}
}
}
/**
* Note: You probably rather want to call the alternative method, which gets buffers from the
* store (unless you are the logger and want to avoid a deadlock wrt depleted msg buffers from the
* store).
* Note: Allows only a single retry. (One retry allowed because we might have gotten an already
* broken connection from the conn pool.)
*
* @param outRespBuf will be kmalloced and needs to be kfreed by the caller
*/
FhgfsOpsErr MessagingTk_requestResponseKMalloc(App* app, Node* node, NetMessage* requestMsg,
unsigned respMsgType, char** outRespBuf, NetMessage** outRespMsg)
{
RequestResponseArgs rrArgs;
FhgfsOpsErr rrRes;
RequestResponseArgs_prepare(&rrArgs, node, requestMsg, respMsgType);
rrArgs.respBufType = MessagingTkBufType_kmalloc;
rrRes = MessagingTk_requestResponseWithRRArgs(app, &rrArgs);
*outRespBuf = rrArgs.outRespBuf;
*outRespMsg = rrArgs.outRespMsg;
return rrRes;
}
/**
* Note: Allows only a single retry. (One retry allowed because we might have gotten an already
* broken connection from the conn pool.)
*
* @param outRespBuf must be returned to the store - not freed!
* @param sock socket to use. If null, one will be pulled from Node's pool
*/
FhgfsOpsErr MessagingTk_requestResponseSock(App* app, Node* node, NetMessage* requestMsg,
unsigned respMsgType, char** outRespBuf, NetMessage** outRespMsg, Socket* sock)
{
RequestResponseArgs rrArgs;
FhgfsOpsErr rrRes;
RequestResponseArgs_prepare(&rrArgs, node, requestMsg, respMsgType);
rrRes = MessagingTk_requestResponseWithRRArgsSock(app, &rrArgs, sock);
*outRespBuf = rrArgs.outRespBuf;
*outRespMsg = rrArgs.outRespMsg;
return rrRes;
}
/**
* Note: Uses the number of retries that has been defined in the app config.
*
* @param outRespBuf must be returned to the store - not freed!
*/
FhgfsOpsErr MessagingTk_requestResponseRetry(App* app, Node* node, NetMessage* requestMsg,
unsigned respMsgType, char** outRespBuf, NetMessage** outRespMsg)
{
Config* cfg = App_getConfig(app);
RequestResponseArgs rrArgs;
FhgfsOpsErr rrRes;
RequestResponseArgs_prepare(&rrArgs, node, requestMsg, respMsgType);
rrArgs.numRetries = Config_getConnNumCommRetries(cfg);
rrRes = MessagingTk_requestResponseWithRRArgs(app, &rrArgs);
*outRespBuf = rrArgs.outRespBuf;
*outRespMsg = rrArgs.outRespMsg;
return rrRes;
}
/**
* Sends a message to a node and receives a response.
* Can handle target states and mapped mirror IDs. Node does not need to be referenced by caller.
*
* If target states are provided, communication might be skipped for certain states.
*
* This version allows only a single retry. (One retry allowed because we might have gotten an
* already broken connection from the conn pool.)
*
* note: uses the number of retries that has been defined in the app config.
*
* @param rrArgs outRespBuf must be returned to the store - not freed; rrArgs->nodeID may optionally
* be provided when calling this.
* @return received message and buffer are available through rrArgs in case of success.
*/
FhgfsOpsErr MessagingTk_requestResponseNode(App* app,
RequestResponseNode* rrNode, RequestResponseArgs* rrArgs)
{
FhgfsOpsErr rrRes;
rrArgs->numRetries = 1;
rrArgs->rrFlags = 0;
rrArgs->respBufType = MessagingTkBufType_BufStore;
rrRes = __MessagingTk_requestResponseNodeRetry(app, rrNode, rrArgs);
return rrRes;
}
/**
* Sends a message to a node and receives a response.
* Can handle target states and mapped mirror IDs. Node does not need to be referenced by caller.
*
* If target states are provided, communication might be skipped for certain states.
*
* note: uses the number of retries that has been defined in the app config.
*
* @param rrArgs outRespBuf must be returned to the store - not freed; rrArgs->nodeID may optionally
* be provided when calling this.
* @return received message and buffer are available through rrArgs in case of success.
*/
FhgfsOpsErr MessagingTk_requestResponseNodeRetryAutoIntr(App* app, RequestResponseNode* rrNode,
RequestResponseArgs* rrArgs)
{
Config* cfg = App_getConfig(app);
rrArgs->numRetries = Config_getConnNumCommRetries(cfg);
rrArgs->rrFlags = REQUESTRESPONSEARGS_FLAG_ALLOWSTATESLEEP;
rrArgs->respBufType = MessagingTkBufType_BufStore;
return __MessagingTk_requestResponseNodeRetry(app, rrNode, rrArgs);
}
/**
* Sends a message to a node and receives a response.
* Can handle target states and mapped mirror IDs. Node does not need to be referenced by caller.
*
* If target states are provided, communication might be skipped for certain states.
*
* @param rrArgs rrArgs->nodeID may optionally be provided when calling this.
* @return received message and buffer are available through rrArgs in case of success.
*/
FhgfsOpsErr __MessagingTk_requestResponseNodeRetry(App* app, RequestResponseNode* rrNode,
RequestResponseArgs* rrArgs)
{
const char* logContext = "Messaging (RPC node)";
unsigned currentRetryNum = 0; // used number of retries so far
FhgfsOpsErr commRes;
struct BuddySequenceNumber* handle = NULL;
struct MirrorBuddyGroup* group = NULL;
bool wasIndirectCommErr = false;
BEEGFS_BUG_ON_DEBUG(rrNode->targetStates == NULL, "targetStates missing");
BEEGFS_BUG_ON_DEBUG(rrNode->mirrorBuddies == NULL, "mirrorBuddies missing");
for( ; ; ) // retry loop
{
bool nodeNeedsRelease = false;
int acquireSeqRes = 0;
bool seqAckIsSelective = false;
// select the right targetID
NumNodeID nodeID; // don't modify caller's nodeID
if (rrNode->peer.isMirrorGroup)
{ // given targetID refers to a buddy mirror group
nodeID = (NumNodeID){MirrorBuddyGroupMapper_getPrimaryTargetID(rrNode->mirrorBuddies,
rrNode->peer.address.group)};
if (unlikely(NumNodeID_isZero(&nodeID)))
{
Logger* log = App_getLogger(app);
Logger_logErrFormatted(log, logContext, "Invalid mirror buddy group ID: %u",
rrNode->peer.address.group);
commRes = FhgfsOpsErr_UNKNOWNNODE;
goto exit;
}
if (rrArgs->requestMsg->ops->supportsSequenceNumbers)
{
rrArgs->requestMsg->msgHeader.msgFlags |= MSGHDRFLAG_HAS_SEQUENCE_NO;
if (rrArgs->requestMsg->msgHeader.msgSequence == 0)
acquireSeqRes = MirrorBuddyGroupMapper_acquireSequenceNumber(rrNode->mirrorBuddies,
rrNode->peer.address.group, &rrArgs->requestMsg->msgHeader.msgSequence,
&rrArgs->requestMsg->msgHeader.msgSequenceDone, &seqAckIsSelective, &handle,
&group);
if (!acquireSeqRes)
{
if (seqAckIsSelective)
rrArgs->requestMsg->msgHeader.msgFlags |= MSGHDRFLAG_IS_SELECTIVE_ACK;
}
else
{
Logger* log = App_getLogger(app);
NodeType storeType = NodeStoreEx_getStoreType(rrNode->nodeStore);
Logger_logFormatted(log, Log_WARNING, logContext,
"Could not generate seq#. Group IP: %u; type: %s", rrNode->peer.address.group,
Node_nodeTypeToStr(storeType));
commRes = acquireSeqRes == EINTR ? FhgfsOpsErr_INTERRUPTED : FhgfsOpsErr_UNKNOWNNODE;
goto exit;
}
}
}
else
nodeID = rrNode->peer.address.target;
// check target state
if (rrNode->targetStates)
{
CombinedTargetState state;
bool getStateRes = TargetStateStore_getState(rrNode->targetStates, nodeID.value,
&state);
if (!getStateRes ||
state.reachabilityState != TargetReachabilityState_ONLINE ||
(rrNode->peer.isMirrorGroup &&
state.consistencyState != TargetConsistencyState_GOOD))
{
if(state.reachabilityState == TargetReachabilityState_OFFLINE)
{ // no need to wait for offline servers
LOG_DEBUG_FORMATTED(App_getLogger(app), Log_SPAM, logContext,
"Skipping communication with offline nodeID: %u", nodeID.value);
commRes = FhgfsOpsErr_COMMUNICATION;
goto exit;
}
if(!(rrArgs->rrFlags & REQUESTRESPONSEARGS_FLAG_ALLOWSTATESLEEP) )
{ // caller did not allow sleeping if target state is not {good, offline}
LOG_DEBUG_FORMATTED(App_getLogger(app), Log_SPAM, logContext,
"Skipping communication with nodeID: %u; "
"target state: %s / %s",
nodeID.value, TargetStateStore_reachabilityStateToStr(state.reachabilityState),
TargetStateStore_consistencyStateToStr(state.consistencyState) );
commRes = FhgfsOpsErr_COMMUNICATION;
goto exit;
}
// sleep on states other than "good" and "offline" with mirroring
if(rrNode->mirrorBuddies)
{
LOG_DEBUG_FORMATTED(App_getLogger(app), Log_DEBUG, logContext,
"Waiting before communication because of node state. "
"nodeID: %u; node state: %s / %s",
nodeID.value, TargetStateStore_reachabilityStateToStr(state.reachabilityState),
TargetStateStore_consistencyStateToStr(state.consistencyState) );
Thread_sleep(MSGTK_STATE_SLEEP_MS);
if (fatal_signal_pending(current))
{ // make sure we don't loop endless if signal pending
LOG_DEBUG_FORMATTED(App_getLogger(app), Log_DEBUG, logContext,
"Waiting before communication was interrupted by signal. "
"nodeID: %u; node state: %s / %s",
nodeID.value, TargetStateStore_reachabilityStateToStr(state.reachabilityState),
TargetStateStore_consistencyStateToStr(state.consistencyState) );
commRes = FhgfsOpsErr_INTERRUPTED;
goto exit;
}
currentRetryNum = 0; // reset retries in case of unusable target state
continue;
}
}
}
// reference node (if not provided by caller already)
if(!rrArgs->node)
{
rrArgs->node = NodeStoreEx_referenceNode(rrNode->nodeStore, nodeID);
if(!rrArgs->node)
{
Logger* log = App_getLogger(app);
NodeType storeType = NodeStoreEx_getStoreType(rrNode->nodeStore);
Logger_logFormatted(log, Log_WARNING, logContext, "Unknown nodeID: %u; type: %s",
nodeID.value, Node_nodeTypeToStr(storeType));
commRes = FhgfsOpsErr_UNKNOWNNODE;
goto exit;
}
nodeNeedsRelease = true;
}
else
BEEGFS_BUG_ON_DEBUG(Node_getNumID(rrArgs->node).value != nodeID.value,
"Mismatch between given rrArgs->node ID and nodeID");
// communicate
commRes = __MessagingTk_requestResponseWithRRArgsComm(app, rrArgs, group,
&wasIndirectCommErr, NULL);
if(likely(commRes == FhgfsOpsErr_SUCCESS) )
goto release_node_and_break;
else
if (fatal_signal_pending(current))
{ // no retry allowed in this situation
commRes = FhgfsOpsErr_INTERRUPTED;
goto release_node_and_break;
}
else
if(!Node_getIsActive(rrArgs->node) )
{ // no retry allowed in this situation
commRes = FhgfsOpsErr_UNKNOWNNODE;
goto release_node_and_break;
}
else
if(commRes == FhgfsOpsErr_WOULDBLOCK)
{ // no retries in this case
commRes = FhgfsOpsErr_COMMUNICATION;
goto release_node_and_break;
}
else
if( (commRes == FhgfsOpsErr_AGAIN) && App_getConnRetriesEnabled(app) )
{ // retry infinitely
currentRetryNum = 0;
Thread_sleep(MSGTK_INFINITE_RETRY_WAIT_MS);
goto release_node_and_continue;
}
else
if(commRes != FhgfsOpsErr_COMMUNICATION)
{ // no retry allowed in this situation
goto release_node_and_break;
}
if(App_getConnRetriesEnabled(app) &&
(!rrArgs->numRetries || (currentRetryNum < rrArgs->numRetries) ) )
{ // we have a retry left
MessagingTk_waitBeforeRetry(currentRetryNum);
currentRetryNum++;
/* if the metadata server reports an indirect communication error, we must retry the
* communication with a new sequence number. if we reuse the current sequence number, the
* meta server will continue to reply "indirect communication error", sending us into a
* very long loop of pointless retries, followed by -EIO to userspace. */
if (wasIndirectCommErr && handle)
{
MirrorBuddyGroup_releaseSequenceNumber(group, &handle);
rrArgs->requestMsg->msgHeader.msgSequence = 0;
wasIndirectCommErr = false;
handle = NULL;
}
if(currentRetryNum == 1 // log retry message only on first retry (to not spam the log)
&& !(rrArgs->logFlags & REQUESTRESPONSEARGS_LOGFLAG_RETRY) )
{
Logger* log = App_getLogger(app);
NodeString nodeAndType;
Node_copyAliasWithTypeStr(rrArgs->node, &nodeAndType);
Logger_logFormatted(log, Log_NOTICE, logContext,
"Retrying communication with node: %s", nodeAndType.buf);
Logger_logFormatted(log, Log_DEBUG, logContext,
"Message type: %hu", NetMessage_getMsgType(rrArgs->requestMsg) );
}
}
else
{ // no more retries left
commRes = FhgfsOpsErr_COMMUNICATION;
goto release_node_and_break;
}
release_node_and_continue:
if(nodeNeedsRelease)
{
Node_put(rrArgs->node);
rrArgs->node = NULL;
}
continue;
// cleanup before early loop exit
release_node_and_break:
if(nodeNeedsRelease)
{
Node_put(rrArgs->node);
rrArgs->node = NULL;
}
break;
}
exit:
if (handle)
MirrorBuddyGroup_releaseSequenceNumber(group, &handle);
return commRes;
}
/**
* Send a request message to a node and receive the response.
*
* @param rrArgs:
* .node receiver of msg;
* .requestMsg the message that should be sent to the receiver;
* .respMsgType expected response message type;
* .outRespBuf response buffer if successful (must be returned to store by the caller);
* .outRespMsg response message if successful (must be deleted by the caller);
* @param sock socket to use. If NULL, one will be pulled from Node's pool
* @return FhgfsOpsErr_COMMUNICATION on comm error, FhgfsOpsErr_WOULDBLOCK if remote side
* encountered an indirect comm error and suggests not to try again, FhgfsOpsErr_AGAIN if other
* side is suggesting infinite retries.
*/
FhgfsOpsErr __MessagingTk_requestResponseWithRRArgsComm(App* app,
RequestResponseArgs* rrArgs, MirrorBuddyGroup* group, bool* wasIndirectCommErr,
Socket* sock)
{
/* note: keep in mind that there are multiple alternative response buf alloc types avilable,
e.g. "kmalloc" or "get from store". */
Logger* log = App_getLogger(app);
const char* logContext = "Messaging (RPC)";
NodeConnPool* connPool = Node_getConnPool(rrArgs->node);
FhgfsOpsErr retVal = FhgfsOpsErr_COMMUNICATION;
unsigned bufLen; // length of shared send/recv buffer
unsigned sendBufLen; // serialization length for sending
ssize_t respRes = 0;
ssize_t sendRes;
// cleanup init
bool releaseSock = sock == NULL;
rrArgs->outRespBuf = NULL;
rrArgs->outRespMsg = NULL;
// connect
// note: acquireStreamSocket() will fail immediately if a signal is pending
if (sock == NULL)
sock = NodeConnPool_acquireStreamSocket(connPool);
if(unlikely(!sock) )
{ // not connected
if(!(rrArgs->logFlags & REQUESTRESPONSEARGS_LOGFLAG_CONNESTABLISHFAILED) &&
!fatal_signal_pending(current))
{ // only log once and only if user didn't manually interrupt with signal (to avoid log spam)
NodeString nodeAndType;
Node_copyAliasWithTypeStr(rrArgs->node, &nodeAndType);
Logger_logFormatted(log, Log_WARNING, logContext,
"Unable to connect to: %s", nodeAndType.buf);
Logger_logFormatted(log, Log_DEBUG, logContext,
"Message type: %hu", NetMessage_getMsgType(rrArgs->requestMsg) );
rrArgs->logFlags |= REQUESTRESPONSEARGS_LOGFLAG_CONNESTABLISHFAILED;
}
return FhgfsOpsErr_COMMUNICATION;
}
// prepare send buffer
sendBufLen = NetMessage_getMsgLength(rrArgs->requestMsg);
if(rrArgs->respBufType == MessagingTkBufType_BufStore)
{ // pre-alloc'ed buffer from store
NoAllocBufferStore* bufStore = App_getMsgBufStore(app);
bufLen = NoAllocBufferStore_getBufSize(bufStore);
if(unlikely(bufLen < sendBufLen) )
{ // should never happen: trying to send a msg that is larger than pre-alloc'ed buf size
Logger_logFormatted(log, Log_CRITICAL, logContext,
"BufferStore buf size (%u) too small for msg length (%u). Message type: %hu",
bufLen, sendBufLen, NetMessage_getMsgType(rrArgs->requestMsg) );
retVal = FhgfsOpsErr_INTERNAL;
goto socket_invalidate;
}
rrArgs->outRespBuf = NoAllocBufferStore_waitForBuf(bufStore);
}
else
{ // alloc'ed buffer
bufLen = MAX(MSGTK_KMALLOC_RECV_BUF_LEN, sendBufLen);
rrArgs->outRespBuf = (char*)os_kmalloc(bufLen);
if(unlikely(!rrArgs->outRespBuf) )
{
Logger_logFormatted(log, Log_CRITICAL, logContext,
"Buffer allocation failed. Message type: %hu; Alloc size: %u",
NetMessage_getMsgType(rrArgs->requestMsg), bufLen);
retVal = FhgfsOpsErr_OUTOFMEM;
goto socket_invalidate;
}
}
NetMessage_serialize(rrArgs->requestMsg, rrArgs->outRespBuf, sendBufLen);
// send request
sendRes = Socket_send_kernel(sock, rrArgs->outRespBuf, sendBufLen, 0);
if(unlikely(sendRes != (ssize_t)sendBufLen) )
goto socket_exception;
// receive response
respRes = MessagingTk_recvMsgBuf(app, sock, rrArgs->outRespBuf, bufLen);
if(unlikely(respRes <= 0) )
{ // error
if(!(rrArgs->logFlags & REQUESTRESPONSEARGS_LOGFLAG_COMMERR) )
{
NodeString nodeAndType;
Node_copyAliasWithTypeStr(rrArgs->node, &nodeAndType);
if (fatal_signal_pending(current)){
Logger_logFormatted(log, Log_NOTICE, logContext,
"Receive interrupted by signal. Node: %s @ %s",
nodeAndType.buf, Socket_getPeername(sock) );
}
else
if(respRes == -ETIMEDOUT) {
Logger_logFormatted(log, Log_WARNING, logContext,
"Receive timed out from %s @ %s",
nodeAndType.buf, Socket_getPeername(sock) );
}
else {
Logger_logFormatted(log, Log_WARNING, logContext,
"Receive failed from %s @ %s (recv result: %zi)",
nodeAndType.buf, Socket_getPeername(sock), respRes);
}
Logger_logFormatted(log, Log_DEBUG, logContext,
"Expected response type: %u", rrArgs->respMsgType);
}
goto socket_invalidate;
}
// got response => deserialize it
rrArgs->outRespMsg = NetMessageFactory_createFromBuf(app, rrArgs->outRespBuf, respRes);
if (unlikely(rrArgs->outRespMsg->msgHeader.msgType == NETMSGTYPE_AckNotifyResp))
{
/* a failover happened before the primary could send a negative response to us, and the
* secondary has already received word about the failed operation. treat this case like a
* communication error and retry the message with a new sequence number. */
*wasIndirectCommErr = true;
goto socket_invalidate;
}
if(unlikely(NetMessage_getMsgType(rrArgs->outRespMsg) == NETMSGTYPE_GenericResponse) )
{ // special control msg received
retVal = __MessagingTk_handleGenericResponse(app, rrArgs, group, wasIndirectCommErr);
if(retVal != FhgfsOpsErr_INTERNAL)
{ // we can re-use the connection
if (releaseSock)
NodeConnPool_releaseStreamSocket(connPool, sock);
goto cleanup_no_socket;
}
goto socket_invalidate;
}
if(unlikely(NetMessage_getMsgType(rrArgs->outRespMsg) != rrArgs->respMsgType) )
{ // response invalid (wrong msgType)
NodeString nodeAndType;
Node_copyAliasWithTypeStr(rrArgs->node, &nodeAndType);
Logger_logErrFormatted(log, logContext,
"Received invalid response type: %hu; expected: %d. Disconnecting: %s (%s)",
NetMessage_getMsgType(rrArgs->outRespMsg), rrArgs->respMsgType,
nodeAndType.buf, Socket_getPeername(sock) );
retVal = FhgfsOpsErr_INTERNAL;
goto socket_invalidate;
}
// correct response => return it (through rrArgs)
if (releaseSock)
NodeConnPool_releaseStreamSocket(connPool, sock);
return FhgfsOpsErr_SUCCESS;
// error handling (something went wrong)...
socket_exception:
{
if(!(rrArgs->logFlags & REQUESTRESPONSEARGS_LOGFLAG_COMMERR) )
{
NodeString nodeAndType;
Node_copyAliasWithTypeStr(rrArgs->node, &nodeAndType);
Logger_logErrFormatted(log, logContext,
"Communication error: Node: %s (comm result: %lld; message type: %hu)",
nodeAndType.buf,
(long long)( (sendRes <= 0) ? sendRes : respRes),
NetMessage_getMsgType(rrArgs->requestMsg) );
rrArgs->logFlags |= REQUESTRESPONSEARGS_LOGFLAG_COMMERR;
}
}
socket_invalidate:
if (releaseSock)
{
NodeConnPool_invalidateStreamSocket(connPool, sock);
}
// clean up
cleanup_no_socket:
if(rrArgs->outRespMsg)
{
NETMESSAGE_FREE(rrArgs->outRespMsg);
rrArgs->outRespMsg = NULL;
}
if(rrArgs->outRespBuf)
{
if(rrArgs->respBufType == MessagingTkBufType_BufStore)
{
NoAllocBufferStore* bufStore = App_getMsgBufStore(app);
NoAllocBufferStore_addBuf(bufStore, rrArgs->outRespBuf);
}
else
kfree(rrArgs->outRespBuf);
rrArgs->outRespBuf = NULL;
}
return retVal;
}
/**
* Print log message and determine appropriate return code for requestResponseComm.
*
* If FhgfsOpsErr_INTERNAL is returned, the connection should be invalidated.
*
* @return FhgfsOpsErr_COMMUNICATION on indirect comm error (retry suggested),
* FhgfsOpsErr_WOULDBLOCK if remote side encountered an indirect comm error and suggests not to
* try again, FhgfsOpsErr_AGAIN if other side is suggesting infinite retries.
*/
FhgfsOpsErr __MessagingTk_handleGenericResponse(App* app, RequestResponseArgs* rrArgs,
MirrorBuddyGroup* group, bool* wasIndirectCommErr)
{
Logger* log = App_getLogger(app);
const char* logContext = "Messaging (RPC)";
FhgfsOpsErr retVal;
GenericResponseMsg* genericResp = (GenericResponseMsg*)rrArgs->outRespMsg;
NodeString nodeAndType;
Node_copyAliasWithTypeStr(rrArgs->node, &nodeAndType);
*wasIndirectCommErr = false;
switch(GenericResponseMsg_getControlCode(genericResp) )
{
case GenericRespMsgCode_TRYAGAIN:
{
if(!(rrArgs->logFlags & REQUESTRESPONSEARGS_LOGFLAG_PEERTRYAGAIN) )
{
rrArgs->logFlags |= REQUESTRESPONSEARGS_LOGFLAG_PEERTRYAGAIN;
Logger_logFormatted(log, Log_NOTICE, logContext,
"Peer is asking for a retry: %s; Reason: %s",
nodeAndType.buf,
GenericResponseMsg_getLogStr(genericResp) );
Logger_logFormatted(log, Log_DEBUG, logContext,
"Message type: %hu", NetMessage_getMsgType(rrArgs->requestMsg) );
}
retVal = FhgfsOpsErr_AGAIN;
} break;
case GenericRespMsgCode_INDIRECTCOMMERR:
{
if(!(rrArgs->logFlags & REQUESTRESPONSEARGS_LOGFLAG_PEERINDIRECTCOMMM) )
{
rrArgs->logFlags |= REQUESTRESPONSEARGS_LOGFLAG_PEERINDIRECTCOMMM;
Logger_logFormatted(log, Log_NOTICE, logContext,
"Peer reported indirect communication error: %s; Reason: %s",
nodeAndType.buf,
GenericResponseMsg_getLogStr(genericResp) );
Logger_logFormatted(log, Log_DEBUG, logContext,
"Message type: %hu", NetMessage_getMsgType(rrArgs->requestMsg) );
}
retVal = FhgfsOpsErr_COMMUNICATION;
*wasIndirectCommErr = true;
} break;
case GenericRespMsgCode_NEWSEQNOBASE:
{
if (group)
{
MirrorBuddyGroup_setSeqNoBase(group,
genericResp->simpleIntStringMsg.netMessage.msgHeader.msgSequence);
retVal = FhgfsOpsErr_COMMUNICATION;
}
else
{
Logger_logFormatted(log, Log_WARNING, logContext,
"Received invalid seqNoBase update");
retVal = FhgfsOpsErr_INTERNAL;
}
break;
}
default:
{
Logger_logFormatted(log, Log_NOTICE, logContext,
"Peer replied with unknown control code: %s; Code: %u; Reason: %s",
nodeAndType.buf,
(unsigned)GenericResponseMsg_getControlCode(genericResp),
GenericResponseMsg_getLogStr(genericResp) );
Logger_logFormatted(log, Log_DEBUG, logContext,
"Message type: %hu", NetMessage_getMsgType(rrArgs->requestMsg) );
retVal = FhgfsOpsErr_INTERNAL;
} break;
}
return retVal;
}

View File

@@ -0,0 +1,208 @@
#ifndef MESSAGINGTK_H_
#define MESSAGINGTK_H_
#include <app/log/Logger.h>
#include <app/App.h>
#include <app/config/Config.h>
#include <common/net/message/NetMessage.h>
#include <common/net/sock/Socket.h>
#include <common/nodes/MirrorBuddyGroup.h>
#include <common/nodes/Node.h>
#include <common/threading/Thread.h>
#include <common/toolkit/MessagingTkArgs.h>
#include <common/storage/StorageErrors.h>
#include <common/Common.h>
#include <net/message/NetMessageFactory.h>
struct Socket;
extern FhgfsOpsErr MessagingTk_requestResponseWithRRArgsSock(App* app,
RequestResponseArgs* rrArgs, Socket* sock);
extern FhgfsOpsErr MessagingTk_requestResponseKMalloc(App* app, Node* node,
NetMessage* requestMsg, unsigned respMsgType, char** outRespBuf, NetMessage** outRespMsg);
extern FhgfsOpsErr MessagingTk_requestResponseSock(App* app, Node* node,
NetMessage* requestMsg, unsigned respMsgType, char** outRespBuf, NetMessage** outRespMsg,
Socket* sock);
extern FhgfsOpsErr MessagingTk_requestResponseRetry(App* app, Node* node,
NetMessage* requestMsg, unsigned respMsgType, char** outRespBuf, NetMessage** outRespMsg);
extern FhgfsOpsErr MessagingTk_requestResponseNode(App* app,
RequestResponseNode* rrNode, RequestResponseArgs* rrArgs);
extern FhgfsOpsErr MessagingTk_requestResponseNodeRetryAutoIntr(App* app,
RequestResponseNode* rrNode, RequestResponseArgs* rrArgs);
// private
extern FhgfsOpsErr __MessagingTk_requestResponseWithRRArgsComm(App* app,
RequestResponseArgs* rrArgs, MirrorBuddyGroup* group, bool* wasIndirectCommErr, Socket* sock);
extern FhgfsOpsErr __MessagingTk_handleGenericResponse(App* app, RequestResponseArgs* rrArgs,
MirrorBuddyGroup* group, bool* wasIndirectCommErr);
extern FhgfsOpsErr __MessagingTk_requestResponseNodeRetry(App* app,
RequestResponseNode* rrNode, RequestResponseArgs* rrArgs);
// inliners
static inline char* MessagingTk_createMsgBuf(NetMessage* msg);
static inline ssize_t MessagingTk_recvMsgBuf(App* app, Socket* sock, char* bufIn, size_t bufInLen);
static inline void MessagingTk_waitBeforeRetry(unsigned currentNumRetry);
static inline int MessagingTk_getRetryWaitMS(unsigned currentNumRetry);
static inline FhgfsOpsErr MessagingTk_requestResponseWithRRArgs(App* app,
RequestResponseArgs* rrArgs);
static inline FhgfsOpsErr MessagingTk_requestResponse(App* app, Node* node,
NetMessage* requestMsg, unsigned respMsgType, char** outRespBuf, NetMessage** outRespMsg);
/**
* Creates a message buffer of the required size and serializes the message to it.
* Note: Uses kmalloc, so this is only safe for messages < 128kB
*
* @return buffer must be kfreed by the caller
*/
char* MessagingTk_createMsgBuf(NetMessage* msg)
{
size_t bufLen = NetMessage_getMsgLength(msg);
char* buf = (char*)os_kmalloc(bufLen);
NetMessage_serialize(msg, buf, buf ? bufLen : 0);
return buf;
}
/**
* Receive a complete message into given buffer, extended version.
*
* Note: This is the version for pre-allocated buffers.
*
* @param bufIn incoming message buffer.
* @return positive message length on success, <=0 on error (e.g. -ETIMEDOUT on recv timeout,
* -EMSGSIZE if msg too large for buffer).
*/
ssize_t MessagingTk_recvMsgBuf(App* app, Socket* sock, char* bufIn, size_t bufInLen)
{
const char* logContext = "MessagingTk (recv msg)";
size_t numReceived = 0;
ssize_t recvRes;
size_t msgLength;
Config* cfg = App_getConfig(app);
// receive at least the message header
recvRes = Socket_recvExactTEx_kernel(sock, bufIn, NETMSG_MIN_LENGTH, 0, cfg->connMsgLongTimeout,
&numReceived);
if(unlikely(recvRes <= 0) )
{ // socket error
Logger* log = App_getLogger(app);
Logger_logFormatted(log, Log_DEBUG, logContext, "Failed to receive message header from: %s",
Socket_getPeername(sock) );
goto socket_exception;
}
msgLength = NetMessage_extractMsgLengthFromBuf(bufIn);
if(msgLength <= numReceived)
return msgLength; // success (msg had no additional payload)
// receive the message payload part
if(unlikely(msgLength > bufInLen) )
{ // message too big to be accepted
Logger* log = App_getLogger(app);
Logger_logFormatted(log, Log_WARNING, logContext,
"Received a message that is too large from: %s (bufLen: %lld, msgLen: %lld)",
Socket_getPeername(sock), (long long)bufInLen, (long long)msgLength);
return -EMSGSIZE;
}
recvRes = Socket_recvExactTEx_kernel(sock, &bufIn[numReceived], msgLength-numReceived, 0,
cfg->connMsgLongTimeout, &numReceived);
if(unlikely(recvRes <= 0) )
goto socket_exception;
// success
return msgLength;
socket_exception:
{
Logger* log = App_getLogger(app);
if (fatal_signal_pending(current))
Logger_logFormatted(log, Log_DEBUG, logContext,
"Receive interrupted by signal");
else
Logger_logFormatted(log, Log_DEBUG, logContext,
"Receive failed from: %s (ErrCode: %lld)",
Socket_getPeername(sock), (long long)recvRes);
}
return recvRes;
}
void MessagingTk_waitBeforeRetry(unsigned currentNumRetry)
{
int retryWaitMS = MessagingTk_getRetryWaitMS(currentNumRetry);
if(retryWaitMS)
Thread_sleep(retryWaitMS);
}
int MessagingTk_getRetryWaitMS(unsigned currentNumRetry)
{
// note: keep in sync with __Config_initConnNumCommRetries()
int retryWaitMS ;
if(!currentNumRetry)
{
retryWaitMS = 0;
}
else
if(currentNumRetry <= 12) // 1st minute
{
retryWaitMS = 5000;
}
else
if(currentNumRetry <= 24) // 2nd to 5th minute
{
retryWaitMS = 20000;
}
else // after 5th minute
{
retryWaitMS = 60000;
}
return retryWaitMS;
}
/**
* Note: rrArgs->outRespBuf must be returned/freed by the caller (depending on respBufType)
*/
FhgfsOpsErr MessagingTk_requestResponseWithRRArgs(App* app, RequestResponseArgs* rrArgs)
{
return MessagingTk_requestResponseWithRRArgsSock(app, rrArgs, NULL);
}
/**
* Note: Allows only a single retry. (One retry allowed because we might have gotten an already
* broken connection from the conn pool.)
*
* @param outRespBuf must be returned to the store - not freed!
*/
FhgfsOpsErr MessagingTk_requestResponse(App* app, Node* node, NetMessage* requestMsg,
unsigned respMsgType, char** outRespBuf, NetMessage** outRespMsg)
{
return MessagingTk_requestResponseSock(app, node, requestMsg, respMsgType,
outRespBuf, outRespMsg, NULL);
}
#endif /*MESSAGINGTK_H_*/

View File

@@ -0,0 +1,157 @@
#ifndef MESSAGINGTKARGS_H_
#define MESSAGINGTKARGS_H_
#include <common/Common.h>
#include <common/Types.h>
#include <toolkit/NoAllocBufferStore.h>
#define REQUESTRESPONSEARGS_FLAG_ALLOWSTATESLEEP 2 // sleep on non-{good,offline} state
#define REQUESTRESPONSEARGS_LOGFLAG_PEERTRYAGAIN 1 // peer asked for retry
#define REQUESTRESPONSEARGS_LOGFLAG_PEERINDIRECTCOMMM 2 /* peer encountered indirect comm
error, suggests retry */
#define REQUESTRESPONSEARGS_LOGFLAG_PEERINDIRECTCOMMM_NOTAGAIN 4 /* peer encountered indirect comm
error, suggests no retry */
#define REQUESTRESPONSEARGS_LOGFLAG_CONNESTABLISHFAILED 8 // unable to establish connection
#define REQUESTRESPONSEARGS_LOGFLAG_COMMERR 16 // communication error
#define REQUESTRESPONSEARGS_LOGFLAG_RETRY 32 // communication retry
struct TargetMapper; // forward declaration
struct TargetStateStore; // forward declaration
struct NodeStoreEx; // forward declaration
struct MirrorBuddyGroupMapper; // forward declaration
struct RequestResponseNode;
typedef struct RequestResponseNode RequestResponseNode;
enum MessagingTkBufType;
typedef enum MessagingTkBufType MessagingTkBufType;
struct RequestResponseArgs;
typedef struct RequestResponseArgs RequestResponseArgs;
static inline void RequestResponseArgs_prepare(RequestResponseArgs* this, Node* node,
NetMessage* requestMsg, unsigned respMsgType);
static inline void RequestResponseArgs_freeRespBuffers(RequestResponseArgs* this, App* app);
struct RRPeer
{
union {
NumNodeID target;
uint32_t group;
} address;
bool isMirrorGroup;
};
static inline struct RRPeer RRPeer_target(NumNodeID target)
{
struct RRPeer result = {
.address = {
.target = target,
},
.isMirrorGroup = false,
};
return result;
}
static inline struct RRPeer RRPeer_group(uint32_t group)
{
struct RRPeer result = {
.address = {
.group = group,
},
.isMirrorGroup = true,
};
return result;
}
/**
* This value container contains arguments for requestResponse() with a certain node.
*/
struct RequestResponseNode
{
struct RRPeer peer;
struct NodeStoreEx* nodeStore; // for nodeID lookup
struct TargetStateStore* targetStates; /* if !NULL, check for state "good" or fail immediately if
offline (other states handling depend on mirrorBuddies) */
struct MirrorBuddyGroupMapper* mirrorBuddies; // if !NULL, the given targetID is a mirror groupID
};
enum MessagingTkBufType
{
MessagingTkBufType_BufStore = 0,
MessagingTkBufType_kmalloc = 1, // only for small response messages (<4KiB)
};
/**
* Arguments for request-response communication.
*/
struct RequestResponseArgs
{
Node* node; // receiver
NetMessage* requestMsg;
unsigned respMsgType; // expected type of response message
unsigned numRetries; // 0 means infinite retries
unsigned rrFlags; // combination of REQUESTRESPONSEARGS_FLAG_... flags
MessagingTkBufType respBufType; // defines how to get/alloc outRespBuf
char* outRespBuf;
NetMessage* outRespMsg;
// internal (initialized by MessagingTk_requestResponseWithRRArgs() )
unsigned char logFlags; // REQUESTRESPONSEARGS_LOGFLAG_... combination to avoid double-logging
};
/**
* Default initializer.
* Some of the default values will overridden by the corresponding MessagingTk methods.
*
* @param node may be NULL, depending on which requestResponse...() method is used.
* @param respMsgType expected type of response message (NETMSGTYPE_...)
*/
void RequestResponseArgs_prepare(RequestResponseArgs* this, Node* node, NetMessage* requestMsg,
unsigned respMsgType)
{
this->node = node;
this->requestMsg = requestMsg;
this->respMsgType = respMsgType;
this->numRetries = 1;
this->rrFlags = 0;
this->respBufType = MessagingTkBufType_BufStore;
this->outRespBuf = NULL;
this->outRespMsg = NULL;
this->logFlags = 0;
}
/**
* Free/release outRespBuf and desctruct outRespMsg if they are not NULL.
*/
void RequestResponseArgs_freeRespBuffers(RequestResponseArgs* this, App* app)
{
NETMESSAGE_FREE(this->outRespMsg);
if(this->outRespBuf)
{
if(this->respBufType == MessagingTkBufType_BufStore)
{
NoAllocBufferStore* bufStore = App_getMsgBufStore(app);
NoAllocBufferStore_addBuf(bufStore, this->outRespBuf);
}
else
SAFE_KFREE(this->outRespBuf);
}
}
#endif /* MESSAGINGTKARGS_H_ */

View File

@@ -0,0 +1,71 @@
#include <app/App.h>
#include <app/log/Logger.h>
#include <common/net/message/NetMessage.h>
#include <common/storage/Metadata.h>
#include <common/storage/StorageDefinitions.h>
#include <common/storage/StorageErrors.h>
#include <common/toolkit/MessagingTk.h>
#include <nodes/NodeStoreEx.h>
#include <toolkit/NoAllocBufferStore.h>
#include "MetadataTk.h"
/**
* Used to initialize struct CreateInfo. This function always should be used, to make sure,
* values are not forgotten.
*
* Note: preferred meta/storage targets are automatically set to app's preferred meta/storage
* targets; keep that in mind when you're cleaning up.
*/
void CreateInfo_init(App* app, struct inode* parentDirInode, const char* entryName,
int mode, int umask, bool isExclusiveCreate, const struct FileEvent* fileEvent,
CreateInfo* outCreateInfo)
{
MountConfig *mountConfig = app->mountConfig;
outCreateInfo->userID = FhgfsCommon_getCurrentUserID();
// groupID and mode logic taken from inode_init_owner()
if (parentDirInode && ((parentDirInode->i_mode & S_ISGID) || mountConfig->grpid))
{
outCreateInfo->groupID = i_gid_read(parentDirInode);
if (S_ISDIR(mode) && (parentDirInode->i_mode & S_ISGID))
mode |= S_ISGID;
}
else
outCreateInfo->groupID = FhgfsCommon_getCurrentGroupID();
outCreateInfo->entryName = entryName;
outCreateInfo->mode = mode;
outCreateInfo->umask = umask;
outCreateInfo->isExclusiveCreate = isExclusiveCreate;
outCreateInfo->preferredStorageTargets = App_getPreferredStorageTargets(app);
outCreateInfo->preferredMetaTargets = App_getPreferredMetaNodes(app);
outCreateInfo->fileEvent = fileEvent;
StoragePoolId_set(&(outCreateInfo->storagePoolId), STORAGEPOOLID_INVALIDPOOLID);
}
/**
* @param outEntryInfo contained values will be kalloced (on success) and need to be kfreed with
* FhgfsInode_freeEntryMinInfoVals() later.
*/
bool MetadataTk_getRootEntryInfoCopy(App* app, EntryInfo* outEntryInfo)
{
NodeStoreEx* nodes = App_getMetaNodes(app);
NodeOrGroup rootOwner = NodeStoreEx_getRootOwner(nodes);
const char* parentEntryID = StringTk_strDup("");
const char* entryID = StringTk_strDup(META_ROOTDIR_ID_STR);
const char* dirName = StringTk_strDup("");
DirEntryType entryType = (DirEntryType) DirEntryType_DIRECTORY;
/* Even if rootOwner is invalid, we still init outEntryInfo and malloc as FhGFS
* policy says that kfree(NULL) is not allowed (the kernel allows it). */
EntryInfo_init(outEntryInfo, rootOwner, parentEntryID, entryID, dirName, entryType, 0);
return NodeOrGroup_valid(rootOwner);
}

View File

@@ -0,0 +1,149 @@
#ifndef METADATATK_H_
#define METADATATK_H_
#include <app/App.h>
#include <common/Common.h>
#include <common/nodes/Node.h>
#include <common/storage/Path.h>
#include <common/storage/StorageErrors.h>
#include <common/storage/EntryInfo.h>
#include <common/storage/StorageErrors.h>
#include <common/storage/StorageDefinitions.h>
#include <common/toolkit/list/UInt16List.h>
#include <common/toolkit/MetadataTk.h>
#include <os/OsTypeConversion.h>
#include "LookupIntentInfoOut.h"
#include <linux/fs.h>
#define METADATATK_OWNERSEARCH_MAX_STEPS 128 /* to avoid infinite searching */
struct CreateInfo;
typedef struct CreateInfo CreateInfo;
struct OpenInfo;
typedef struct OpenInfo OpenInfo;
struct LookupIntentInfoIn;
typedef struct LookupIntentInfoIn LookupIntentInfoIn;
struct FileEvent;
extern bool MetadataTk_getRootEntryInfoCopy(App* app, EntryInfo* outEntryInfo);
// inliners
void CreateInfo_init(App* app, struct inode* parentDirInode, const char* entryName,
int mode, int umask, bool isExclusiveCreate, const struct FileEvent* fileEvent,
struct CreateInfo* outCreateInfo);
static inline void CreateInfo_setStoragePoolId(CreateInfo* this, StoragePoolId storagePoolId);
static inline void LookupIntentInfoIn_init(LookupIntentInfoIn* this,
const EntryInfo* parentEntryInfo, const char* entryName);
static inline void LookupIntentInfoIn_addEntryInfo(LookupIntentInfoIn* this,
const EntryInfo* entryInfo);
static inline void LookupIntentInfoIn_addMetaVersion(LookupIntentInfoIn* this,
uint32_t metaVersion);
static inline void LookupIntentInfoIn_addOpenInfo(LookupIntentInfoIn* this,
const OpenInfo* openInfo);
static inline void LookupIntentInfoIn_addCreateInfo(LookupIntentInfoIn* this,
const CreateInfo* createInfo);
static inline void OpenInfo_init(OpenInfo* this, int accessFlags, bool isPagedMode);
static inline void LookupIntentInfoOut_prepare(LookupIntentInfoOut* this,
EntryInfo* outEntryInfo, fhgfs_stat* outFhgfsStat);
/**
* File/Dir create information. Should be initialized using CreateInfo_init().
*/
struct CreateInfo
{
const char* entryName; // file name
unsigned userID;
unsigned groupID;
int mode;
int umask;
UInt16List* preferredMetaTargets;
UInt16List* preferredStorageTargets;
bool isExclusiveCreate; // only for open() and creat(), is O_CREAT set?
StoragePoolId storagePoolId; // can be set to override storage pool information of parent
// directory
const struct FileEvent* fileEvent;
};
struct OpenInfo
{
int accessFlags; // fhgfs flags, not in-kernel open/access flags
// const char* sessionID; // set at lower level on initializing LookupIntentMsg
};
/**
* In-Args for _lookupCreateStat operations. Init only with LookupIntentInfoIn_init().
*/
struct LookupIntentInfoIn
{
const EntryInfo* parentEntryInfo;
const EntryInfo* entryInfoPtr; // only set on revalidate
const char* entryName; // file name
const CreateInfo* createInfo; // only set on file create
bool isExclusiveCreate; // true iff O_EXCL is set
const OpenInfo* openInfo; // only set on file open
uint32_t metaVersion; //only set on revalidate
};
/**
* @param accessFlags is the same as openFlags
*/
void OpenInfo_init(OpenInfo* this, int accessFlags, bool isPagedMode)
{
this->accessFlags = OsTypeConv_openFlagsOsToFhgfs(accessFlags, isPagedMode);
// this->sessionID = sessionID; // see OpenInfo definition
}
static inline void LookupIntentInfoIn_init(LookupIntentInfoIn* this,
const EntryInfo* parentEntryInfo, const char* entryName)
{
this->parentEntryInfo = parentEntryInfo;
this->entryName = entryName;
this->entryInfoPtr = NULL;
this->openInfo = NULL;
this->createInfo = NULL;
}
void LookupIntentInfoIn_addEntryInfo(LookupIntentInfoIn* this, const EntryInfo* entryInfo)
{
this->entryInfoPtr = entryInfo;
}
void LookupIntentInfoIn_addMetaVersion(LookupIntentInfoIn* this, uint32_t version)
{
this->metaVersion = version;
}
void LookupIntentInfoIn_addOpenInfo(LookupIntentInfoIn* this, const OpenInfo* openInfo)
{
this->openInfo = openInfo;
}
void LookupIntentInfoIn_addCreateInfo(LookupIntentInfoIn* this, const CreateInfo* createInfo)
{
this->createInfo = createInfo;
if (likely(createInfo) )
this->isExclusiveCreate = createInfo->isExclusiveCreate;
}
static inline void CreateInfo_setStoragePoolId(CreateInfo* this, StoragePoolId storagePoolId)
{
this->storagePoolId = storagePoolId;
}
#endif /*METADATATK_H_*/

View File

@@ -0,0 +1,198 @@
#ifndef NETFILTER_H_
#define NETFILTER_H_
#include <app/config/Config.h>
#include <common/toolkit/Serialization.h>
#include <common/toolkit/SocketTk.h>
#include <common/Common.h>
#include <linux/in.h>
struct NetFilterEntry;
typedef struct NetFilterEntry NetFilterEntry;
struct NetFilter;
typedef struct NetFilter NetFilter;
static inline __must_check bool NetFilter_init(NetFilter* this, const char* filename);
static inline NetFilter* NetFilter_construct(const char* filename);
static inline void NetFilter_uninit(NetFilter* this);
static inline void NetFilter_destruct(NetFilter* this);
// inliners
static inline bool NetFilter_isAllowed(NetFilter* this, struct in_addr ipAddr);
static inline bool NetFilter_isContained(NetFilter* this, struct in_addr ipAddr);
static inline bool __NetFilter_prepareArray(NetFilter* this, const char* filename);
// getters & setters
static inline size_t NetFilter_getNumFilterEntries(NetFilter* this);
struct NetFilterEntry
{
uint32_t netAddressShifted; // shifted by number of significant bits
// Note: this address is in host(!) byte order to enable correct shift operator usage
int shiftBitsNum; // for right shift
};
struct NetFilter
{
NetFilterEntry* filterArray;
size_t filterArrayLen;
};
/**
* @param filename path to filter file.
*/
bool NetFilter_init(NetFilter* this, const char* filename)
{
return __NetFilter_prepareArray(this, filename);
}
NetFilter* NetFilter_construct(const char* filename)
{
NetFilter* this = kmalloc(sizeof(*this), GFP_NOFS);
if(!this ||
!NetFilter_init(this, filename) )
{
kfree(this);
return NULL;
}
return this;
}
void NetFilter_uninit(NetFilter* this)
{
SAFE_KFREE(this->filterArray);
}
void NetFilter_destruct(NetFilter* this)
{
NetFilter_uninit(this);
kfree(this);
}
/**
* Note: Empty filter will always return allowed (i.e. "true").
* Note: Will always allow the loopback address.
*/
bool NetFilter_isAllowed(NetFilter* this, struct in_addr ipAddr)
{
if(!this->filterArrayLen)
return true;
return NetFilter_isContained(this, ipAddr);
}
/**
* Note: Always implicitly contains the loopback address.
*/
bool NetFilter_isContained(NetFilter* this, struct in_addr ipAddr)
{
uint32_t ipHostOrder;
size_t i;
// note: stored addresses are in host byte order to enable correct shift operator usage
ipHostOrder = ntohl(ipAddr.s_addr);
if(ipHostOrder == INADDR_LOOPBACK) // (inaddr_loopback is in host byte order)
return true;
for(i = 0; i < this->filterArrayLen; i++)
{
const uint32_t ipHostOrderShifted = ipHostOrder >> this->filterArray[i].shiftBitsNum;
if(this->filterArray[i].netAddressShifted == ipHostOrderShifted)
{ // address match
return true;
}
}
// no match found
return false;
}
/**
* @param filename path to filter file.
* @return false if a specified file could not be opened.
*/
bool __NetFilter_prepareArray(NetFilter* this, const char* filename)
{
bool loadRes = true;
StrCpyList filterList;
this->filterArray = NULL;
this->filterArrayLen = 0;
if(!StringTk_hasLength(filename) )
{ // no file specified => no filter entries
return true;
}
StrCpyList_init(&filterList);
loadRes = Config_loadStringListFile(filename, &filterList);
if(!loadRes)
{ // file error
printk_fhgfs(KERN_WARNING,
"Unable to load configured net filter file: %s\n", filename);
return false;
}
if(StrCpyList_length(&filterList) )
{ // file did contain some lines
StrCpyListIter iter;
size_t i;
this->filterArrayLen = StrCpyList_length(&filterList);
this->filterArray = kmalloc(this->filterArrayLen * sizeof(NetFilterEntry), GFP_NOFS);
if(!this->filterArray)
goto err_alloc;
StrCpyListIter_init(&iter, &filterList);
i = 0;
for( ; !StrCpyListIter_end(&iter); StrCpyListIter_next(&iter) )
{
char* line = StrCpyListIter_value(&iter);
uint32_t entryAddr;
char* findRes = strchr(line, '/');
if(!findRes)
{ // slash character missing => ignore this faulty line (and reduce filter length)
this->filterArrayLen--;
continue;
}
*findRes = 0;
// note: we store addresses in host byte order to enable correct shift operator usage
entryAddr = ntohl(SocketTk_in_aton(line).s_addr);
this->filterArray[i].shiftBitsNum = 32 - StringTk_strToUInt(findRes + 1);
this->filterArray[i].netAddressShifted = entryAddr >> this->filterArray[i].shiftBitsNum;
i++; // must be increased here because of the faulty line handling
}
}
StrCpyList_uninit(&filterList);
return true;
err_alloc:
StrCpyList_uninit(&filterList);
return false;
}
size_t NetFilter_getNumFilterEntries(NetFilter* this)
{
return this->filterArrayLen;
}
#endif /* NETFILTER_H_ */

View File

@@ -0,0 +1,188 @@
#include <toolkit/NoAllocBufferStore.h>
#include <common/net/message/nodes/GetMirrorBuddyGroupsMsg.h>
#include <common/net/message/nodes/GetNodesMsg.h>
#include <common/net/message/nodes/GetNodesRespMsg.h>
#include <common/net/message/nodes/GetStatesAndBuddyGroupsMsg.h>
#include <common/net/message/nodes/GetStatesAndBuddyGroupsRespMsg.h>
#include <common/net/message/nodes/GetTargetMappingsMsg.h>
#include <common/net/message/nodes/GetTargetMappingsRespMsg.h>
#include <common/threading/Thread.h>
#include <common/toolkit/MessagingTk.h>
#include <common/toolkit/Random.h>
#include "NodesTk.h"
/**
* Download node list from given source node.
*
* @param sourceNode the node from which node you want to download
* @param nodeType which type of node list you want to download
* @param outNodeList caller is responsible for the deletion of the received nodes
* @param outRootID may be NULL if caller is not interested
* @param outRootIsBuddyMirrored may be NULL if caller is not interested
* @return true if download successful
*/
bool NodesTk_downloadNodes(App* app, Node* sourceNode, NodeType nodeType, NodeList* outNodeList,
NumNodeID* outRootNodeID, bool* outRootIsBuddyMirrored)
{
bool retVal = false;
GetNodesMsg msg;
FhgfsOpsErr commRes;
GetNodesRespMsg* respMsgCast;
RequestResponseArgs rrArgs;
// prepare request
GetNodesMsg_initFromValue(&msg, nodeType);
RequestResponseArgs_prepare(&rrArgs, sourceNode, (NetMessage*)&msg, NETMSGTYPE_GetNodesResp);
#ifndef BEEGFS_DEBUG
// Silence log message unless built in debug mode.
rrArgs.logFlags |= ( REQUESTRESPONSEARGS_LOGFLAG_CONNESTABLISHFAILED
| REQUESTRESPONSEARGS_LOGFLAG_RETRY );
#endif // BEEGFS_DEBUG
// connect & communicate
commRes = MessagingTk_requestResponseWithRRArgs(app, &rrArgs);
if(unlikely(commRes != FhgfsOpsErr_SUCCESS) )
goto cleanup_request;
// handle result
respMsgCast = (GetNodesRespMsg*)rrArgs.outRespMsg;
GetNodesRespMsg_parseNodeList(app, respMsgCast, outNodeList);
if(outRootNodeID)
*outRootNodeID = GetNodesRespMsg_getRootNumID(respMsgCast);
if (outRootIsBuddyMirrored)
*outRootIsBuddyMirrored = GetNodesRespMsg_getRootIsBuddyMirrored(respMsgCast);
retVal = true;
// cleanup
RequestResponseArgs_freeRespBuffers(&rrArgs, app);
cleanup_request:
return retVal;
}
/**
* Downloads target mappings from given source node.
*
* @return true if download successful
*/
bool NodesTk_downloadTargetMappings(App* app, Node* sourceNode, struct list_head* mappings)
{
GetTargetMappingsMsg msg;
FhgfsOpsErr commRes;
GetTargetMappingsRespMsg* respMsgCast;
RequestResponseArgs rrArgs;
// prepare request
GetTargetMappingsMsg_init(&msg);
RequestResponseArgs_prepare(&rrArgs, sourceNode, (NetMessage*)&msg,
NETMSGTYPE_GetTargetMappingsResp);
#ifndef BEEGFS_DEBUG
// Silence log message unless built in debug mode.
rrArgs.logFlags |= ( REQUESTRESPONSEARGS_LOGFLAG_CONNESTABLISHFAILED
| REQUESTRESPONSEARGS_LOGFLAG_RETRY );
#endif // BEEGFS_DEBUG
// communicate
commRes = MessagingTk_requestResponseWithRRArgs(app, &rrArgs);
if(unlikely(commRes != FhgfsOpsErr_SUCCESS) )
return false;
// handle result
respMsgCast = (GetTargetMappingsRespMsg*)rrArgs.outRespMsg;
list_splice_tail_init(&respMsgCast->mappings, mappings);
// cleanup
RequestResponseArgs_freeRespBuffers(&rrArgs, app);
return true;
}
/**
* Download target states and buddy groups combined in a single message.
*/
bool NodesTk_downloadStatesAndBuddyGroups(App* app, Node* sourceNode, NodeType nodeType,
struct list_head* groups, struct list_head* states)
{
bool retVal = false;
GetStatesAndBuddyGroupsMsg msg;
FhgfsOpsErr commRes;
GetStatesAndBuddyGroupsRespMsg* respMsgCast;
RequestResponseArgs rrArgs;
Node* localNode = App_getLocalNode(app);
NumNodeID localNodeNumID = Node_getNumID(localNode);
// prepare request
GetStatesAndBuddyGroupsMsg_init(&msg, nodeType, localNodeNumID);
RequestResponseArgs_prepare(&rrArgs, sourceNode, (NetMessage*)&msg,
NETMSGTYPE_GetStatesAndBuddyGroupsResp);
#ifndef BEEGFS_DEBUG
// Silence log message unless built in debug mode.
rrArgs.logFlags |= ( REQUESTRESPONSEARGS_LOGFLAG_CONNESTABLISHFAILED
| REQUESTRESPONSEARGS_LOGFLAG_RETRY );
#endif // BEEGFS_DEBUG
// communicate
commRes = MessagingTk_requestResponseWithRRArgs(app, &rrArgs);
if(unlikely(commRes != FhgfsOpsErr_SUCCESS) )
goto cleanup_request;
// handle result
respMsgCast = (GetStatesAndBuddyGroupsRespMsg*)rrArgs.outRespMsg;
list_splice_tail_init(&respMsgCast->groups, groups);
list_splice_tail_init(&respMsgCast->states, states);
retVal = true;
// cleanup
RequestResponseArgs_freeRespBuffers(&rrArgs, app);
cleanup_request:
return retVal;
}
/**
* Walk over all nodes in the given store and drop established (available) connections.
*
* @return number of dropped connections
*/
unsigned NodesTk_dropAllConnsByStore(NodeStoreEx* nodes)
{
unsigned numDroppedConns = 0;
Node* node = NodeStoreEx_referenceFirstNode(nodes);
while(node)
{
NodeConnPool* connPool = Node_getConnPool(node);
numDroppedConns += NodeConnPool_disconnectAvailableStreams(connPool);
node = NodeStoreEx_referenceNextNodeAndReleaseOld(nodes, node); // iterate to next node
}
return numDroppedConns;
}

View File

@@ -0,0 +1,18 @@
#ifndef NODESTK_H_
#define NODESTK_H_
#include <nodes/NodeStoreEx.h>
#include <common/Common.h>
#include <common/toolkit/list/StrCpyListIter.h>
#include <common/toolkit/list/UInt8List.h>
extern bool NodesTk_downloadNodes(App* app, Node* sourceNode, NodeType nodeType,
NodeList* outNodeList, NumNodeID* outRootNodeID, bool* outRootIsBuddyMirrored);
extern bool NodesTk_downloadTargetMappings(App* app, Node* sourceNode, struct list_head* mappings);
extern bool NodesTk_downloadStatesAndBuddyGroups(App* app, Node* sourceNode,
NodeType nodeType, struct list_head* groups, struct list_head* states);
extern unsigned NodesTk_dropAllConnsByStore(NodeStoreEx* nodes);
#endif /* NODESTK_H_ */

View File

@@ -0,0 +1,31 @@
#include <common/toolkit/Random.h>
#include <common/Common.h>
#include <linux/random.h>
/**
* @return positive (incl. zero) random number
*/
int Random_getNextInt(void)
{
int randVal;
get_random_bytes(&randVal, sizeof(randVal) );
// Note: -randVal (instead of ~randVal) wouldn't work for INT_MIN
return (randVal < 0) ? (~randVal) : randVal;
}
/**
* @param min inclusive min value
* @param max inclusive max value
*/
int Random_getNextInRange(int min, int max)
{
int randVal = Random_getNextInt() % (max - min + 1);
return(min + randVal);
}

View File

@@ -0,0 +1,10 @@
#ifndef OPEN_RANDOM_H_
#define OPEN_RANDOM_H_
#include <common/Common.h>
extern int Random_getNextInt(void);
extern int Random_getNextInRange(int min, int max);
#endif /* OPEN_RANDOM_H_ */

View File

@@ -0,0 +1,919 @@
#include "Serialization.h"
#include "common/Common.h"
#include <os/OsDeps.h>
bool __Serialization_deserializeNestedField(DeserializeCtx* ctx, DeserializeCtx* outCtx)
{
unsigned length;
if(!Serialization_deserializeUInt(ctx, &length) )
return false;
length -= Serialization_serialLenUInt();
if (ctx->length < length)
return false;
outCtx->data = ctx->data;
outCtx->length = length;
ctx->data += length;
ctx->length -= length;
return true;
}
/**
* @return 0 on error (e.g. strLen is greater than bufLen), used buffer size otherwise
*/
void Serialization_serializeStr(SerializeCtx* ctx, unsigned strLen, const char* strStart)
{
// write length field
Serialization_serializeUInt(ctx, strLen);
// write raw string
Serialization_serializeBlock(ctx, strStart, strLen);
// write termination char
Serialization_serializeChar(ctx, 0);
}
/**
* @return false on error (e.g. strLen is greater than bufLen)
*/
bool Serialization_deserializeStr(DeserializeCtx* ctx,
unsigned* outStrLen, const char** outStrStart)
{
// length field
if(unlikely(!Serialization_deserializeUInt(ctx, outStrLen) ) )
return false;
// check length and terminating zero
if(unlikely( (ctx->length < *outStrLen + 1) || ( (ctx->data)[*outStrLen] != 0) ) )
return false;
// string start
*outStrStart = ctx->data;
ctx->data += *outStrLen + 1;
ctx->length -= *outStrLen + 1;
return true;
}
/**
* @return 0 on error (e.g. arrLen is greater than bufLen), used buffer size otherwise
*/
void Serialization_serializeCharArray(SerializeCtx* ctx, unsigned arrLen, const char* arrStart)
{
// elem count info field
Serialization_serializeUInt(ctx, arrLen);
// copy raw array data
Serialization_serializeBlock(ctx, arrStart, arrLen);
}
/**
* @return false on error (e.g. arrLen is greater than bufLen)
*/
bool Serialization_deserializeCharArray(DeserializeCtx* ctx,
unsigned* outElemNum, const char** outArrStart, unsigned* outLen)
{
if(unlikely(!Serialization_deserializeUInt(ctx, outElemNum) ) )
return false;
if(ctx->length < *outElemNum)
return false;
// array start
*outArrStart = ctx->data;
ctx->data += *outElemNum;
ctx->length -= *outElemNum;
return true;
}
/**
* Note: adds padding to achieve 4 byte alignment
*
* @return 0 on error (e.g. strLen is greater than bufLen), used buffer size otherwise
*/
void Serialization_serializeStrAlign4(SerializeCtx* ctx, unsigned strLen, const char* strStart)
{
// write length field
Serialization_serializeUInt(ctx, strLen);
// write raw string
Serialization_serializeBlock(ctx, strStart, strLen);
// write termination char
Serialization_serializeChar(ctx, 0);
// align to 4b length
if( (strLen + 1) % 4)
Serialization_serializeBlock(ctx, "\0\0\0", 4 - (strLen + 1) % 4);
}
/**
* @return false on error (e.g. strLen is greater than bufLen)
*/
bool Serialization_deserializeStrAlign4(DeserializeCtx* ctx,
unsigned* outStrLen, const char** outStrStart)
{
const char* const bufAtStart = ctx->data;
unsigned padding;
// length field
if(unlikely(!Serialization_deserializeUInt(ctx, outStrLen) ) )
return false;
// check length and terminating zero
if(unlikely( (ctx->length < *outStrLen + 1) || ( (ctx->data)[*outStrLen] != 0) ) )
return false;
// string start
*outStrStart = ctx->data;
ctx->data += *outStrLen + 1;
ctx->length -= *outStrLen + 1;
padding = (ctx->data - bufAtStart) % 4;
if(padding != 0)
{
if(unlikely(ctx->length < padding) )
return false;
ctx->data += 4 - padding;
ctx->length -= 4 - padding;
}
return true;
}
/**
* Serialization of a NicList.
*
* note: 4 byte aligned.
*
* @return 0 on error, used buffer size otherwise
*/
void Serialization_serializeNicList(SerializeCtx* ctx, NicAddressList* nicList)
{
unsigned nicListSize = NicAddressList_length(nicList);
NicAddressListIter iter;
unsigned startOffset = ctx->length;
// length field placeholder
Serialization_serializeUInt(ctx, 0xFFFFFFFF);
// elem count info field
Serialization_serializeUInt(ctx, nicListSize);
// serialize each element of the nicList
NicAddressListIter_init(&iter, nicList);
for(unsigned i = 0; i < nicListSize; i++, NicAddressListIter_next(&iter) )
{
NicAddress* nicAddr = NicAddressListIter_value(&iter);
const size_t minNameSize = MIN(sizeof(nicAddr->name), SERIALIZATION_NICLISTELEM_NAME_SIZE);
// We currently only support and store ipv4 addresses internally, so we always set the
// protocol field to 4.
Serialization_serializeUInt8(ctx, 4);
{ // ipAddress
Serialization_serializeBlock(ctx, &nicAddr->ipAddr.s_addr, sizeof(nicAddr->ipAddr.s_addr) );
}
{ // name
Serialization_serializeBlock(ctx, nicAddr->name, minNameSize);
}
{ // nicType
Serialization_serializeBlock(ctx, &nicAddr->nicType, sizeof(uint8_t) );
}
{ // 2 bytes padding (for 4 byte alignment)
Serialization_serializeBlock(ctx, "\0\0", 2);
}
}
// Overwrite placeholder with length
if (ctx->data)
put_unaligned_le32(ctx->length - startOffset, ctx->data + startOffset);
}
/**
* Pre-processes a serialized NicList for deserialization via deserializeNicList().
*
* @return false on error or inconsistency
*/
bool Serialization_deserializeNicListPreprocess(DeserializeCtx* ctx, RawList* outList)
{
if(!Serialization_deserializeUInt(ctx, &outList->length) )
return false;
if(!Serialization_deserializeUInt(ctx, &outList->elemCount) )
return false;
outList->data = ctx->data;
// We need the length of the actual list without the two header fields above (which are included
// in the sequence length field)
outList->length -= 8;
if(unlikely(ctx->length < outList->length) )
return false;
ctx->data += outList->length;
ctx->length -= outList->length;
return true;
}
/**
* Deserializes a NicList.
* (requires pre-processing via nicListBufToMsg() )
*/
void Serialization_deserializeNicList(const RawList* inList, NicAddressList* outNicList)
{
const char* currentNicListPos = inList->data;
unsigned skipped = 0;
for(unsigned i = 0; i < inList->elemCount; i++)
{
uint8_t protocol;
NicAddress* nicAddr = os_kmalloc(sizeof(NicAddress) );
const size_t minNameSize = MIN(sizeof(nicAddr->name), SERIALIZATION_NICLISTELEM_NAME_SIZE);
memset(nicAddr, 0, sizeof(NicAddress) ); // clear unused fields
{ // protocol
protocol = (uint8_t) get_unaligned((char*)currentNicListPos);
currentNicListPos += 1;
}
if (protocol == 4)
{ // ipAddress
// Ipv4 address
nicAddr->ipAddr.s_addr = get_unaligned((unsigned*)currentNicListPos);
currentNicListPos += 4;
} else {
// If this is an ipv6 address, skip it as it is not supported yet.
// 16 bytes ipv6 address + name + nicType + padding
currentNicListPos += 16 + SERIALIZATION_NICLISTELEM_NAME_SIZE + 1 + 2;
skipped += 1;
continue;
}
{ // name
memcpy(&nicAddr->name, currentNicListPos, minNameSize);
(nicAddr->name)[minNameSize-1] = 0; // make sure the string is zero-terminated
currentNicListPos += SERIALIZATION_NICLISTELEM_NAME_SIZE;
}
{ // nicType
nicAddr->nicType = (NicAddrType_t) get_unaligned((char*)currentNicListPos);
currentNicListPos += 1;
}
{ // 2 bytes padding (for 4 byte alignment)
currentNicListPos += 2;
}
NicAddressList_append(outNicList, nicAddr);
}
if (skipped > 0) {
printk_fhgfs(KERN_INFO, "Skipped deserializing %d unsupported IPv6 Nics", skipped);
}
}
/**
* Pre-processes a serialized NodeList for deserialization via deserializeNodeList().
*
* @return false on error or inconsistency
*/
bool Serialization_deserializeNodeListPreprocess(DeserializeCtx* ctx, RawList* outList)
{
unsigned i;
if(!Serialization_deserializeUInt(ctx, &outList->elemCount) )
return false;
// store start pos for later deserialize()
outList->data = ctx->data;
for(i=0; i < outList->elemCount; i++)
{
{// nodeID
unsigned nodeIDLen = 0;
const char* nodeID = NULL;
if(unlikely(!Serialization_deserializeStr(ctx, &nodeIDLen, &nodeID) ) )
return false;
}
{// nicList (4b aligned)
RawList nicList;
if(unlikely(!Serialization_deserializeNicListPreprocess(ctx, &nicList) ) )
return false;
}
{// nodeNumID
NumNodeID nodeNumID = {0};
if(unlikely(!NumNodeID_deserialize(ctx, &nodeNumID) ) )
return false;
}
{// portUDP
uint16_t portUDP = 0;
if(unlikely(!Serialization_deserializeUShort(ctx, &portUDP) ) )
return false;
}
{// portTCP
uint16_t portTCP = 0;
if(unlikely(!Serialization_deserializeUShort(ctx, &portTCP) ) )
return false;
}
{// nodeType
char nodeType = 0;
if(unlikely(!Serialization_deserializeChar(ctx, &nodeType) ) )
return false;
}
}
return true;
}
/**
* Deserializes a NodeList.
* (requires pre-processing)
*
* Note: Nodes will be constructed and need to be deleted later
*/
void Serialization_deserializeNodeList(App* app, const RawList* inList, NodeList* outNodeList)
{
unsigned i;
DeserializeCtx ctx = {
.data = inList->data,
.length = -1,
};
for(i=0; i < inList->elemCount; i++)
{
NicAddressList nicList;
const char* nodeID = NULL;
NumNodeID nodeNumID = (NumNodeID){0};
uint16_t portUDP = 0;
uint16_t portTCP = 0;
char nodeType = 0;
NicAddressList_init(&nicList);
{// nodeID
unsigned nodeIDLen = 0;
Serialization_deserializeStr(&ctx, &nodeIDLen, &nodeID);
}
{// nicList (4b aligned)
RawList rawNicList;
Serialization_deserializeNicListPreprocess(&ctx, &rawNicList);
Serialization_deserializeNicList(&rawNicList, &nicList);
}
// nodeNumID
NumNodeID_deserialize(&ctx, &nodeNumID);
// portUDP
Serialization_deserializeUShort(&ctx, &portUDP);
// portTCP
Serialization_deserializeUShort(&ctx, &portTCP);
// nodeType
Serialization_deserializeChar(&ctx, &nodeType);
{// construct node
Node* node;
App_lockNicList(app);
node = Node_construct(app, nodeID, nodeNumID, portUDP, portTCP, &nicList,
nodeType == NODETYPE_Meta || nodeType == NODETYPE_Storage? App_getLocalRDMANicListLocked(app) : NULL);
App_unlockNicList(app);
Node_setNodeAliasAndType(node, NULL, (NodeType)nodeType);
// append node to outList
NodeList_append(outNodeList, node);
}
// cleanup
ListTk_kfreeNicAddressListElems(&nicList);
NicAddressList_uninit(&nicList);
}
}
/**
* Serialization of a StrCpyList.
*
* Note: We keep the serialiazation format compatible with string vec serialization
*/
void Serialization_serializeStrCpyList(SerializeCtx* ctx, StrCpyList* list)
{
SerializeCtx startCtx = *ctx;
StrCpyListIter iter;
size_t listSize = StrCpyList_length(list);
size_t i;
// totalBufLen info field
Serialization_serializeUInt(ctx, 0);
// elem count info field
Serialization_serializeUInt(ctx, listSize);
// store each element of the list as a raw zero-terminated string
StrCpyListIter_init(&iter, list);
for(i=0; i < listSize; i++, StrCpyListIter_next(&iter) )
{
char* currentElem = StrCpyListIter_value(&iter);
size_t serialElemLen = strlen(currentElem) + 1; // +1 for the terminating zero
Serialization_serializeBlock(ctx, currentElem, serialElemLen);
}
// fix totalBufLen info field
Serialization_serializeUInt(&startCtx, ctx->length - startCtx.length);
}
/**
* Pre-processes a serialized StrCpyList.
*
* @return false on error or inconsistency
*/
bool Serialization_deserializeStrCpyListPreprocess(DeserializeCtx* ctx, RawList* outList)
{
DeserializeCtx outCtx;
if(!__Serialization_deserializeNestedField(ctx, &outCtx) )
return false;
// elem count field
if(unlikely(!Serialization_deserializeUInt(&outCtx, &outList->elemCount) ) )
return false;
if(unlikely(outList->elemCount && ( outCtx.data[outCtx.length - 1] != 0) ) )
return false;
outList->data = outCtx.data;
outList->length = outCtx.length;
return true;
}
/**
* Deserializes a StrCpyList.
* (requires pre-processing)
*
* @return false on error or inconsistency
*/
bool Serialization_deserializeStrCpyList(const RawList* inList, StrCpyList* outList)
{
const char* listStart = inList->data;
unsigned listBufLen = inList->length;
unsigned i;
// read each list element as a raw zero-terminated string
// and make sure that we do not read beyond the specified end position
for(i = 0; (i < inList->elemCount) && (listBufLen > 0); i++)
{
size_t elemLen = strlen(listStart);
StrCpyList_append(outList, listStart);
listStart += elemLen + 1; // +1 for the terminating zero
listBufLen -= elemLen + 1; // +1 for the terminating zero
}
return i == inList->elemCount;
}
/**
* Serialization of a StrCpyVec.
*
* Note: We keep the serialiazation format compatible with string list serialization
*/
void Serialization_serializeStrCpyVec(SerializeCtx* ctx, StrCpyVec* vec)
{
Serialization_serializeStrCpyList(ctx, &vec->strCpyList);
}
/**
* Pre-processes a serialized StrCpyVec.
*
* Note: We keep the serialization format compatible to the string list format.
*
* @return false on error or inconsistency
*/
bool Serialization_deserializeStrCpyVecPreprocess(DeserializeCtx* ctx, RawList* outList)
{
// serialization format is 100% compatible to the list version, so we can just use the list
// version code here...
return Serialization_deserializeStrCpyListPreprocess(ctx, outList);
}
/**
* Deserializes a StrCpyVec.
* (requires pre-processing)
*
* @return false on error or inconsistency
*/
bool Serialization_deserializeStrCpyVec(const RawList* inList, StrCpyVec* outVec)
{
const char* listStart = inList->data;
unsigned listBufLen = inList->length;
unsigned i;
// read each list element as a raw zero-terminated string
// and make sure that we do not read beyond the specified end position
for(i = 0; (i < inList->elemCount) && (listBufLen > 0); i++)
{
size_t elemLen = strlen(listStart);
StrCpyVec_append(outVec, listStart);
listStart += elemLen + 1; // +1 for the terminating zero
listBufLen -= elemLen + 1; // +1 for the terminating zero
}
return i == inList->elemCount;
}
/**
* Pre-processes a serialized UInt8List().
*
* @return false on error or inconsistency
*/
bool Serialization_deserializeUInt8ListPreprocess(DeserializeCtx* ctx, RawList* outList)
{
DeserializeCtx outCtx;
if(!__Serialization_deserializeNestedField(ctx, &outCtx) )
return false;
// elem count field
if(unlikely(!Serialization_deserializeUInt(&outCtx, &outList->elemCount) ) )
return false;
if(outCtx.length != outList->elemCount * Serialization_serialLenUInt8() )
return false;
outList->data = outCtx.data;
outList->length = outCtx.length;
return true;
}
/**
* Deserializes a UInt8List.
* (requires pre-processing)
*
* @return false on error or inconsistency
*/
bool Serialization_deserializeUInt8List(const RawList* inList, UInt8List* outList)
{
DeserializeCtx ctx = { inList->data, inList->length };
unsigned i;
// read each list element
for(i=0; i < inList->elemCount; i++)
{
uint8_t value;
if(!Serialization_deserializeUInt8(&ctx, &value) )
return false;
UInt8List_append(outList, value);
}
return true;
}
/**
* Pre-processes a serialized UInt8Vec().
*
* @return false on error or inconsistency
*/
bool Serialization_deserializeUInt8VecPreprocess(DeserializeCtx* ctx, RawList* outList)
{
// serialization format is 100% compatible to the list version, so we can just use the list
// version code here...
return Serialization_deserializeUInt8ListPreprocess(ctx, outList);
}
/**
* Deserializes a UInt8Vec.
* (requires pre-processing)
*
* @return false on error or inconsistency
*/
bool Serialization_deserializeUInt8Vec(const RawList* inList, UInt8Vec* outVec)
{
DeserializeCtx ctx = { inList->data, inList->length };
unsigned i;
// read each list element
for(i=0; i < inList->elemCount; i++)
{
uint8_t value;
if(!Serialization_deserializeUInt8(&ctx, &value) )
return false;
UInt8Vec_append(outVec, value);
}
return true;
}
/**
* Serialization of a UInt16List.
*
* Note: We keep the serialization format compatible with int vec serialization
*/
void Serialization_serializeUInt16List(SerializeCtx* ctx, UInt16List* list)
{
SerializeCtx startCtx = *ctx;
UInt16ListIter iter;
unsigned i;
unsigned listSize = UInt16List_length(list);
// totalBufLen info field
Serialization_serializeUInt(ctx, 0);
// elem count info field
Serialization_serializeUInt(ctx, listSize);
// store each element of the list
UInt16ListIter_init(&iter, list);
for(i=0; i < listSize; i++, UInt16ListIter_next(&iter) )
{
uint16_t currentValue = UInt16ListIter_value(&iter);
Serialization_serializeUShort(ctx, currentValue);
}
// fix totalBufLen info field
Serialization_serializeUInt(&startCtx, ctx->length - startCtx.length);
}
/**
* Pre-processes a serialized UInt16List().
*
* @return false on error or inconsistency
*/
bool Serialization_deserializeUInt16ListPreprocess(DeserializeCtx* ctx, RawList* outList)
{
DeserializeCtx outCtx;
if(!__Serialization_deserializeNestedField(ctx, &outCtx) )
return false;
// elem count field
if(unlikely(!Serialization_deserializeUInt(&outCtx, &outList->elemCount) ) )
return false;
if(outCtx.length != outList->elemCount * Serialization_serialLenUShort() )
return false;
outList->data = outCtx.data;
outList->length = outCtx.length;
return true;
}
/**
* Deserializes a UInt16List.
* (requires pre-processing)
*
* @return false on error or inconsistency
*/
bool Serialization_deserializeUInt16List(const RawList* inList, UInt16List* outList)
{
DeserializeCtx ctx = { inList->data, inList->length };
unsigned i;
// read each list element
for(i=0; i < inList->elemCount; i++)
{
uint16_t value;
if(!Serialization_deserializeUShort(&ctx, &value) )
return false;
UInt16List_append(outList, value);
}
return true;
}
/**
* Note: We keep the serialiazation format compatible with string list serialization
*/
void Serialization_serializeUInt16Vec(SerializeCtx* ctx, UInt16Vec* vec)
{
// UInt16Vecs are derived from UInt16Lists, so we can just do a cast here and use the list
// version code...
Serialization_serializeUInt16List(ctx, (UInt16List*)vec);
}
/**
* Pre-processes a serialized UInt16Vec().
*
* @return false on error or inconsistency
*/
bool Serialization_deserializeUInt16VecPreprocess(DeserializeCtx* ctx, RawList* outList)
{
// serialization format is 100% compatible to the list version, so we can just use the list
// version code here...
return Serialization_deserializeUInt16ListPreprocess(ctx, outList);
}
/**
* Deserializes a UInt16Vec.
* (requires pre-processing)
*
* @return false on error or inconsistency
*/
bool Serialization_deserializeUInt16Vec(const RawList* inList, UInt16Vec* outVec)
{
DeserializeCtx ctx = { inList->data, inList->length };
unsigned i;
// read each list element
for(i=0; i < inList->elemCount; i++)
{
uint16_t value;
if(!Serialization_deserializeUShort(&ctx, &value) )
return false;
UInt16Vec_append(outVec, value);
}
return true;
}
/**
* Serialization of a Int64CpyList.
*
* Note: We keep the serialization format compatible with int vec serialization
*/
void Serialization_serializeInt64CpyList(SerializeCtx* ctx, Int64CpyList* list)
{
SerializeCtx startCtx = *ctx;
Int64CpyListIter iter;
unsigned i;
unsigned listSize = Int64CpyList_length(list);
// totalBufLen info field
Serialization_serializeUInt(ctx, 0);
// elem count info field
Serialization_serializeUInt(ctx, listSize);
// store each element of the list
Int64CpyListIter_init(&iter, list);
for(i=0; i < listSize; i++, Int64CpyListIter_next(&iter) )
{
int64_t currentValue = Int64CpyListIter_value(&iter);
Serialization_serializeInt64(ctx, currentValue);
}
// fix totalBufLen info field
Serialization_serializeUInt(&startCtx, ctx->length - startCtx.length);
}
/**
* Pre-processes a serialized Int64CpyList().
*
* @return false on error or inconsistency
*/
bool Serialization_deserializeInt64CpyListPreprocess(DeserializeCtx* ctx, RawList* outList)
{
DeserializeCtx outCtx;
if(!__Serialization_deserializeNestedField(ctx, &outCtx) )
return false;
// elem count field
if(unlikely(!Serialization_deserializeUInt(&outCtx, &outList->elemCount) ) )
return false;
if(outCtx.length != (outList->elemCount * Serialization_serialLenInt64() ) )
return false;
outList->data = outCtx.data;
outList->length = outCtx.length;
return true;
}
/**
* Deserializes a Int64CpyList.
* (requires pre-processing)
*
* @return false on error or inconsistency
*/
bool Serialization_deserializeInt64CpyList(const RawList* inList, Int64CpyList* outList)
{
DeserializeCtx ctx = { inList->data, inList->length };
unsigned i;
// read each list element
for(i=0; i < inList->elemCount; i++)
{
int64_t value;
if(!Serialization_deserializeInt64(&ctx, &value) )
return false;
Int64CpyList_append(outList, value);
}
return true;
}
/**
* Note: We keep the serialiazation format compatible with string list serialization
*/
void Serialization_serializeInt64CpyVec(SerializeCtx* ctx, Int64CpyVec* vec)
{
// Int64CpyVecs are derived from Int64CpyLists, so we can just do a cast here and use the list
// version code...
Serialization_serializeInt64CpyList(ctx, (Int64CpyList*)vec);
}
/**
* Pre-processes a serialized Int64CpyVec().
*
* @return false on error or inconsistency
*/
bool Serialization_deserializeInt64CpyVecPreprocess(DeserializeCtx* ctx, RawList* outList)
{
// serialization format is 100% compatible to the list version, so we can just use the list
// version code here...
return Serialization_deserializeInt64CpyListPreprocess(ctx, outList);
}
/**
* Deserializes a Int64CpyVec.
* (requires pre-processing)
*
* @return false on error or inconsistency
*/
bool Serialization_deserializeInt64CpyVec(const RawList* inList, Int64CpyVec* outVec)
{
DeserializeCtx ctx = { inList->data, inList->length };
unsigned i;
// read each list element
for(i=0; i < inList->elemCount; i++)
{
int64_t value;
if(!Serialization_deserializeInt64(&ctx, &value) )
return false;
Int64CpyVec_append(outVec, value);
}
return true;
}

View File

@@ -0,0 +1,617 @@
#ifndef SERIALIZATION_H_
#define SERIALIZATION_H_
#include <common/Common.h>
#include <common/net/sock/NetworkInterfaceCard.h>
#include <common/net/sock/NicAddressList.h>
#include <common/toolkit/list/Int64CpyList.h>
#include <common/toolkit/list/Int64CpyListIter.h>
#include <common/toolkit/list/NumNodeIDList.h>
#include <common/toolkit/list/NumNodeIDListIter.h>
#include <common/toolkit/list/StrCpyList.h>
#include <common/toolkit/list/StrCpyListIter.h>
#include <common/toolkit/list/UInt8List.h>
#include <common/toolkit/list/UInt8ListIter.h>
#include <common/toolkit/list/UInt16List.h>
#include <common/toolkit/list/UInt16ListIter.h>
#include <common/toolkit/vector/Int64CpyVec.h>
#include <common/toolkit/vector/StrCpyVec.h>
#include <common/toolkit/vector/UInt16Vec.h>
#include <common/toolkit/vector/UInt8Vec.h>
#include <common/toolkit/ListTk.h>
#include <common/toolkit/Serialization.h>
#include <common/storage/Path.h>
#include <common/nodes/Node.h>
#include <common/nodes/NodeList.h>
#include <common/nodes/NodeListIter.h>
#include <os/OsCompat.h>
#ifdef KERNEL_HAS_LINUX_UNALIGNED_H
#include <linux/unaligned.h>
#else
#include <asm/unaligned.h>
#endif
#define SERIALIZATION_NICLISTELEM_NAME_SIZE (16)
bool __Serialization_deserializeNestedField(DeserializeCtx* ctx, DeserializeCtx* outCtx);
// string (de)serialization
void Serialization_serializeStr(SerializeCtx* ctx, unsigned strLen, const char* strStart);
bool Serialization_deserializeStr(DeserializeCtx* ctx,
unsigned* outStrLen, const char** outStrStart);
// string aligned (de)serialization
void Serialization_serializeStrAlign4(SerializeCtx* ctx, unsigned strLen, const char* strStart);
bool Serialization_deserializeStrAlign4(DeserializeCtx* ctx,
unsigned* outStrLen, const char** outStrStart);
// char array (arbitrary binary data) (de)serialization
void Serialization_serializeCharArray(SerializeCtx* ctx, unsigned arrLen, const char* arrStart);
bool Serialization_deserializeCharArray(DeserializeCtx* ctx,
unsigned* outArrLen, const char** outArrStart, unsigned* outLen);
// nicList (de)serialization
void Serialization_serializeNicList(SerializeCtx* ctx, NicAddressList* nicList);
bool Serialization_deserializeNicListPreprocess(DeserializeCtx* ctx, RawList* outList);
void Serialization_deserializeNicList(const RawList* inList, NicAddressList* outNicList);
// nodeList (de)serialization
bool Serialization_deserializeNodeListPreprocess(DeserializeCtx* ctx, RawList* outList);
void Serialization_deserializeNodeList(App* app, const RawList* inList, NodeList* outNodeList);
// strCpyList (de)serialization
void Serialization_serializeStrCpyList(SerializeCtx* ctx, StrCpyList* list);
bool Serialization_deserializeStrCpyListPreprocess(DeserializeCtx* ctx, RawList* outList);
bool Serialization_deserializeStrCpyList(const RawList* inList, StrCpyList* outList);
// strCpyVec (de)serialization
void Serialization_serializeStrCpyVec(SerializeCtx* ctx, StrCpyVec* vec);
bool Serialization_deserializeStrCpyVecPreprocess(DeserializeCtx* ctx, RawList* outList);
bool Serialization_deserializeStrCpyVec(const RawList* inList, StrCpyVec* outVec);
// uint8List (de)serialization
bool Serialization_deserializeUInt8ListPreprocess(DeserializeCtx* ctx, RawList* outList);
bool Serialization_deserializeUInt8List(const RawList* inList, UInt8List* outList);
// uint8Vec (de)serialization
bool Serialization_deserializeUInt8VecPreprocess(DeserializeCtx* ctx, RawList* outList);
bool Serialization_deserializeUInt8Vec(const RawList* inList, UInt8Vec* outList);
// uint16List (de)serialization
void Serialization_serializeUInt16List(SerializeCtx* ctx, UInt16List* list);
bool Serialization_deserializeUInt16ListPreprocess(DeserializeCtx* ctx, RawList* outList);
bool Serialization_deserializeUInt16List(const RawList* inList, UInt16List* outList);
// uint16Vec (de)serialization
void Serialization_serializeUInt16Vec(SerializeCtx* ctx, UInt16Vec* vec);
bool Serialization_deserializeUInt16VecPreprocess(DeserializeCtx* ctx, RawList* outList);
bool Serialization_deserializeUInt16Vec(const RawList* inList, UInt16Vec* outVec);
// int64CpyList (de)serialization
void Serialization_serializeInt64CpyList(SerializeCtx* ctx, Int64CpyList* list);
bool Serialization_deserializeInt64CpyListPreprocess(DeserializeCtx* ctx, RawList* outList);
bool Serialization_deserializeInt64CpyList(const RawList* inList, Int64CpyList* outList);
// uint64Vec (de)serialization
void Serialization_serializeInt64CpyVec(SerializeCtx* ctx, Int64CpyVec* vec);
bool Serialization_deserializeInt64CpyVecPreprocess(DeserializeCtx* ctx, RawList* outList);
bool Serialization_deserializeInt64CpyVec(const RawList* inList, Int64CpyVec* outVec);
// inliners
static inline void Serialization_serializeBlock(SerializeCtx* ctx, const void* value,
unsigned length);
static inline unsigned Serialization_serialLenChar(void);
static inline void Serialization_serializeChar(SerializeCtx* ctx, char value);
static inline bool Serialization_deserializeChar(DeserializeCtx* ctx, char* outValue);
static inline unsigned Serialization_serialLenBool(void);
static inline void Serialization_serializeBool(SerializeCtx* ctx, bool value);
static inline bool Serialization_deserializeBool(DeserializeCtx* ctx, bool* outValue);
static inline unsigned Serialization_serialLenUInt8(void);
static inline bool Serialization_deserializeUInt8(DeserializeCtx* ctx, uint8_t* outValue);
static inline unsigned Serialization_serialLenShort(void);
static inline void Serialization_serializeShort(SerializeCtx* ctx, short value);
static inline bool Serialization_deserializeShort(DeserializeCtx* ctx, short* outValue);
static inline unsigned Serialization_serialLenUShort(void);
static inline void Serialization_serializeUShort(SerializeCtx* ctx, unsigned short value);
static inline bool Serialization_deserializeUShort(DeserializeCtx* ctx, unsigned short* outValue);
static inline void Serialization_serializeInt(SerializeCtx* ctx, int value);
static inline bool Serialization_deserializeInt(DeserializeCtx* ctx, int* outValue);
static inline unsigned Serialization_serialLenInt(void);
static inline void Serialization_serializeUInt(SerializeCtx* ctx, unsigned value);
static inline bool Serialization_deserializeUInt(DeserializeCtx* ctx, unsigned* outValue);
static inline unsigned Serialization_serialLenUInt(void);
static inline void Serialization_serializeInt64(SerializeCtx* ctx, int64_t value);
static inline bool Serialization_deserializeInt64(DeserializeCtx* ctx, int64_t* outValue);
static inline unsigned Serialization_serialLenInt64(void);
static inline void Serialization_serializeUInt64(SerializeCtx* ctx, uint64_t value);
static inline bool Serialization_deserializeUInt64(DeserializeCtx* ctx, uint64_t* outValue);
static inline unsigned Serialization_serialLenUInt64(void);
void Serialization_serializeBlock(SerializeCtx* ctx, const void* value, unsigned length)
{
if(ctx->data)
memcpy(ctx->data + ctx->length, value, length);
ctx->length += length;
}
#define __Serialization_deserializeRaw(ctx, convert, outValue) \
({ \
DeserializeCtx* ctx__ = (ctx); \
bool result = false; \
(void) (outValue == (__typeof__(convert(ctx__->data) )*) 0); \
if(likely(ctx__->length >= sizeof(*(outValue) ) ) ) \
{ \
*(outValue) = convert(ctx__->data); \
ctx__->data += sizeof(*(outValue) ); \
ctx__->length -= sizeof(*(outValue) ); \
result = true; \
} \
result; \
})
// char (de)serialization
static inline unsigned Serialization_serialLenChar(void)
{
return sizeof(char);
}
static inline void Serialization_serializeChar(SerializeCtx* ctx, char value)
{
if(ctx->data)
ctx->data[ctx->length] = value;
ctx->length += sizeof(value);
}
static inline bool Serialization_deserializeChar(DeserializeCtx* ctx, char* outValue)
{
return __Serialization_deserializeRaw(ctx, *, outValue);
}
// bool (de)serialization
static inline unsigned Serialization_serialLenBool(void)
{
return Serialization_serialLenChar();
}
static inline void Serialization_serializeBool(SerializeCtx* ctx, bool value)
{
Serialization_serializeChar(ctx, value ? 1 : 0);
}
static inline bool Serialization_deserializeBool(DeserializeCtx* ctx, bool* outValue)
{
char charVal = 0;
bool deserRes = Serialization_deserializeChar(ctx, &charVal);
*outValue = (charVal != 0);
return deserRes;
}
// uint8_t (de)serialization
static inline void Serialization_serializeUInt8(SerializeCtx* ctx, uint8_t value)
{
Serialization_serializeChar(ctx, (char) value);
}
static inline unsigned Serialization_serialLenUInt8(void)
{
return Serialization_serialLenChar();
}
static inline bool Serialization_deserializeUInt8(DeserializeCtx* ctx,
uint8_t* outValue)
{
return Serialization_deserializeChar(ctx, (char*)outValue);
}
// short (de)serialization
static inline unsigned Serialization_serialLenShort(void)
{
return Serialization_serialLenUShort();
}
static inline void Serialization_serializeShort(SerializeCtx* ctx, short value)
{
Serialization_serializeUShort(ctx, value);
}
static inline bool Serialization_deserializeShort(DeserializeCtx* ctx,
short* outValue)
{
return Serialization_deserializeUShort(ctx, (unsigned short*)outValue);
}
// ushort (de)serialization
static inline unsigned Serialization_serialLenUShort(void)
{
return sizeof(unsigned short);
}
static inline void Serialization_serializeUShort(SerializeCtx* ctx, unsigned short value)
{
if(ctx->data)
put_unaligned_le16(value, ctx->data + ctx->length);
ctx->length += sizeof(value);
}
static inline bool Serialization_deserializeUShort(DeserializeCtx* ctx, unsigned short* outValue)
{
return __Serialization_deserializeRaw(ctx, get_unaligned_le16, outValue);
}
// int (de)serialization
static inline unsigned Serialization_serialLenInt(void)
{
return Serialization_serialLenUInt();
}
static inline void Serialization_serializeInt(SerializeCtx* ctx, int value)
{
Serialization_serializeUInt(ctx, value);
}
static inline bool Serialization_deserializeInt(DeserializeCtx* ctx, int* outValue)
{
return Serialization_deserializeUInt(ctx, (unsigned*)outValue);
}
// uint (de)serialization
static inline void Serialization_serializeUInt(SerializeCtx* ctx, unsigned value)
{
if(ctx->data)
put_unaligned_le32(value, ctx->data + ctx->length);
ctx->length += sizeof(value);
}
static inline bool Serialization_deserializeUInt(DeserializeCtx* ctx, unsigned* outValue)
{
return __Serialization_deserializeRaw(ctx, get_unaligned_le32, outValue);
}
static inline unsigned Serialization_serialLenUInt(void)
{
return sizeof(unsigned);
}
// int64 (de)serialization
static inline void Serialization_serializeInt64(SerializeCtx* ctx, int64_t value)
{
Serialization_serializeUInt64(ctx, value);
}
static inline bool Serialization_deserializeInt64(DeserializeCtx* ctx,
int64_t* outValue)
{
return Serialization_deserializeUInt64(ctx, (uint64_t*)outValue);
}
static inline unsigned Serialization_serialLenInt64(void)
{
return Serialization_serialLenUInt64();
}
// uint64 (de)serialization
static inline void Serialization_serializeUInt64(SerializeCtx* ctx, uint64_t value)
{
if(ctx->data)
put_unaligned_le64(value, ctx->data + ctx->length);
ctx->length += sizeof(value);
}
static inline bool Serialization_deserializeUInt64(DeserializeCtx* ctx,
uint64_t* outValue)
{
return __Serialization_deserializeRaw(ctx, get_unaligned_le64, outValue);
}
static inline unsigned Serialization_serialLenUInt64(void)
{
return sizeof(uint64_t);
}
#define __SERDES_CONCAT_I(a, b) a ## b
#define __SERDES_CONCAT(a, b) __SERDES_CONCAT_I(a, b)
#define __SERDES_COUNT_I(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, count, ...) count
#define __SERDES_COUNT(...) __SERDES_COUNT_I(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#define __SERDES_CALL(Base, ...) __SERDES_CONCAT(Base, __SERDES_COUNT(__VA_ARGS__))(__VA_ARGS__)
#define __SERDES_FIELD_NAME(Name, SerMod, NS, Suffix) Name
#define __SERDES_FIELD_SER(Name, SerMod, NS, Suffix) NS##_serialize##Suffix
#define __SERDES_FIELD_SER_MOD(Name, SerMod, NS, Suffix) SerMod
#define __SERDES_FIELD_DES(Name, SerMod, NS, Suffix) NS##_deserialize##Suffix
#define __SERDES_DEFINE_SER_1(Field) \
__SERDES_FIELD_SER Field(ctx, __SERDES_FIELD_SER_MOD Field(value->__SERDES_FIELD_NAME Field));
#define __SERDES_DEFINE_SER_2(Field, ...) __SERDES_DEFINE_SER_1(Field) __SERDES_DEFINE_SER_1(__VA_ARGS__)
#define __SERDES_DEFINE_SER_3(Field, ...) __SERDES_DEFINE_SER_1(Field) __SERDES_DEFINE_SER_2(__VA_ARGS__)
#define __SERDES_DEFINE_SER_4(Field, ...) __SERDES_DEFINE_SER_1(Field) __SERDES_DEFINE_SER_3(__VA_ARGS__)
#define __SERDES_DEFINE_SER_5(Field, ...) __SERDES_DEFINE_SER_1(Field) __SERDES_DEFINE_SER_4(__VA_ARGS__)
#define __SERDES_DEFINE_SER_6(Field, ...) __SERDES_DEFINE_SER_1(Field) __SERDES_DEFINE_SER_5(__VA_ARGS__)
#define __SERDES_DEFINE_SER_7(Field, ...) __SERDES_DEFINE_SER_1(Field) __SERDES_DEFINE_SER_6(__VA_ARGS__)
#define __SERDES_DEFINE_SER_8(Field, ...) __SERDES_DEFINE_SER_1(Field) __SERDES_DEFINE_SER_7(__VA_ARGS__)
#define __SERDES_DEFINE_SER_9(Field, ...) __SERDES_DEFINE_SER_1(Field) __SERDES_DEFINE_SER_8(__VA_ARGS__)
#define __SERDES_DEFINE_SER_10(Field, ...) __SERDES_DEFINE_SER_1(Field) __SERDES_DEFINE_SER_9(__VA_ARGS__)
#define __SERDES_DEFINE_SER(NS, Type, ...) \
__attribute__((unused)) \
void NS##_serialize(SerializeCtx* ctx, const Type* value) \
{ \
__SERDES_CALL(__SERDES_DEFINE_SER_, __VA_ARGS__) \
}
#define __SERDES_DEFINE_DES_1(Field) \
if (!__SERDES_FIELD_DES Field(ctx, &value->__SERDES_FIELD_NAME Field)) \
goto err;
#define __SERDES_DEFINE_DES_2(Field, ...) __SERDES_DEFINE_DES_1(Field) __SERDES_DEFINE_DES_1(__VA_ARGS__)
#define __SERDES_DEFINE_DES_3(Field, ...) __SERDES_DEFINE_DES_1(Field) __SERDES_DEFINE_DES_2(__VA_ARGS__)
#define __SERDES_DEFINE_DES_4(Field, ...) __SERDES_DEFINE_DES_1(Field) __SERDES_DEFINE_DES_3(__VA_ARGS__)
#define __SERDES_DEFINE_DES_5(Field, ...) __SERDES_DEFINE_DES_1(Field) __SERDES_DEFINE_DES_4(__VA_ARGS__)
#define __SERDES_DEFINE_DES_6(Field, ...) __SERDES_DEFINE_DES_1(Field) __SERDES_DEFINE_DES_5(__VA_ARGS__)
#define __SERDES_DEFINE_DES_7(Field, ...) __SERDES_DEFINE_DES_1(Field) __SERDES_DEFINE_DES_6(__VA_ARGS__)
#define __SERDES_DEFINE_DES_8(Field, ...) __SERDES_DEFINE_DES_1(Field) __SERDES_DEFINE_DES_7(__VA_ARGS__)
#define __SERDES_DEFINE_DES_9(Field, ...) __SERDES_DEFINE_DES_1(Field) __SERDES_DEFINE_DES_8(__VA_ARGS__)
#define __SERDES_DEFINE_DES_10(Field, ...) __SERDES_DEFINE_DES_1(Field) __SERDES_DEFINE_DES_9(__VA_ARGS__)
#define __SERDES_DEFINE_DES(NS, Type, Init, ErrFini, ...) \
__attribute__((unused)) \
bool NS##_deserialize(DeserializeCtx* ctx, Type* value) \
{ \
Init; \
__SERDES_CALL(__SERDES_DEFINE_DES_, __VA_ARGS__) \
return true; \
err: \
ErrFini; \
return false; \
}
/**
* SERDES_DECLARE_SERIALIZERS() - declares serialize and deserialize functions for a given type.
* @NS namespace prefix for the generated functions
* @Type the type to be made serializable/deserializable
*
* creates ``extern`` declarations for serializer functions as generated by
* ``SERDES_DEFINE_SERIALIZERS`` or ``SERDES_DEFINE_SERIALIZERS_SIMPLE``.
*/
#define SERDES_DECLARE_SERIALIZERS(NS, Type) \
extern void NS##_serialize(SerializeCtx* ctx, const Type* value); \
extern bool NS##_deserialize(DeserializeCtx* ctx, Type* value);
/**
* SERDES_DEFINE_SERIALIZERS() - defines serialize and deserialize functions for a given type.
* @Access access modifiers for the generated functions
* @NS namespace prefix for the generated functions
* @Type the type to be made serializable/deserializable
* @DesInit initialization code to be run before an instance is deserialized
* @DesErrFini finalization code to be run when deserialization fails
* @... description of @Type
*
* Declares a function ``NS##_serialize(SerializeCtx* ctx, const Type* value)`` and a function
* ``NS##_deserialize(DeserializeCtx* ctx, Type* value)`` that follow the
* serializer and deserializer conventions.
*
* During deserialization, ``DesInit`` is evaluated as an expression in the scope of the
* deserializer function (ie, ``ctx`` and ``value`` are available). @DesInit may be called on
* objects that have been initialized previously, via @DesInit or some other method. The invoker
* must be careful to not introduce memory leaks via this expression. @DesInit and @DesErrFini
* should always call the usual initialization and release functions for the type.
*
* If deserialization fails for any reason, ``DesErrFini`` is evaluated in the context of the
* deserializer function just like ``DesInit``. All resources allocated during initialization or
* deserialization must be released by ``DesErrFini``.
*
* @Type is exposed to the serializer as a list if one to 10 comma-separated tuples of the form
* ``(FieldName, SerMod, SerNS, Suffix)``.
*
* * ``FieldName`` is the name of the serialized field. Fields are serialized and deserialized in
* the order they appear in the description list.
* * ``SerMod`` is a modifier applied to the serialized value before passing it on to the
* serializer (see example).
* * ``SerNS`` is the namespace of the serializer and deserializer functions for this field.
* * ``Suffix`` is appended to the canonical name of the serializer and deserializer functions for
* the field.
*
* For the generated serializer, each field expands into a single call to a serializer.
* ``SerNS##_serialize##Suffix(ctx, SerMod (value->FieldName);``
*
* For the generated deserializer, each field expands into a single call to a deserializer. For
* deserializers the ``SerMod`` field of the description is ignored and a pointer is always passed.
* ``SerNS##_deserialize##Suffix(ctx, &(value->FieldName));``
*
* Example:
* ``
* struct S
* {
* const char* str;
* };
* SERDES_DEFINE_SERIALIZERS(static inline, _S, struct S,
* value->str = NULL,
* kfree(value->str),
* (str, &, Serdes, CStr))
* ``
* will expand to this serializer and deserializer code:
* ``
* static inline void _S_serialize(SerializeCtx* ctx, const struct S* value)
* {
* Serdes_serializeCStr(ctx, &(value->str));
* }
* static inline bool _S_deserialize(DeserializeCtx* ctx, struct S* value)
* {
* value->str = NULL;
* if (!Serdes_deserializeCStr(ctx, &value->str))
* goto err;
* return true;
* err:
* kfree(value->str);
* return false;
* }
* ``
*/
#define SERDES_DEFINE_SERIALIZERS(Access, NS, Type, DesInit, DesErrFini, ...) \
Access __SERDES_DEFINE_SER(NS, Type, __VA_ARGS__) \
Access __SERDES_DEFINE_DES(NS, Type, DesInit, DesErrFini, __VA_ARGS__)
/**
* SERDES_DEFINE_SERIALIZERS_SIMPLE() - defines serialize and deserialize functions for a given type
* @Access access modifiers for the generated functions
* @NS namespace prefix for the generated functions
* @Type the type to be made serializable/deserializable
* @... description of @Type
*
* expands to ``SERDES_DEFINE_SERIALIZERS(Access, NS, Type, ({}), ({}), __VA_ARGS__)``, ie no
* special intialization or cleanup is done for deserialization.
*/
#define SERDES_DEFINE_SERIALIZERS_SIMPLE(Access, NS, Type, ...) \
SERDES_DEFINE_SERIALIZERS(Access, NS, Type, ({}), ({}), __VA_ARGS__)
/**
* SERDES_SERIALIZE_AS - defines enum serializers based on underlying type
* @Access access modifiers for the generated functions
* @NS namespace prefix for the generated functions
* @Type the type to be made serializable/deserializable
* @As underlying type to used for serialized data
* @AsSuffix suffix for de/serializer in ``Serialization``
*
* enum types that go over the wire must be serialized with a consistent type at both end. this
* macro defines serializers for a given enum @Type which use @As for the binary representation.
* since this is about underlying types this macro can only call ``Serialization_*`` functions.
*/
#define SERDES_SERIALIZE_AS(Access, NS, Type, As, AsSuffix) \
__attribute__((unused)) \
Access void NS##_serialize(SerializeCtx* ctx, Type value) \
{ \
Serialization_serialize##AsSuffix(ctx, (As) value); \
} \
__attribute__((unused)) \
Access bool NS##_deserialize(DeserializeCtx* ctx, Type* value) \
{ \
As tmp; \
if (!Serialization_deserialize##AsSuffix(ctx, &tmp)) \
return false; \
*value = (Type) tmp; \
return true; \
}
/**
* SERDES_DECLARE_LIST_SERIALIZERS() - declare list serializers for a given type
* @NS namespace prefix for the generated functions
* @Type type of list entry
*
* Declares ``extern`` prototypes of the functions as generated by
* ``SERDES_DEFINE_LIST_SERIALIZERS``
*/
#define SERDES_DECLARE_LIST_SERIALIZERS(NS, Type) \
extern void NS##_serialize(SerializeCtx* ctx, const struct list_head* list); \
extern bool NS##_deserialize(DeserializeCtx* ctx, struct list_head* list); \
/**
* SERDES_DEFINE_LIST_SERIALIZERS() - defines list serializers for a given type
* @Access access modifiers for the generated functions
* @NS namespace prefix for the generated functions
* @Type type of list entry
* @TypeNS namespace of serializer/deserializer functions for @Type
* @TypeFini cleanup expression for a @Type
* @ListMember name of the &struct list_head for this list in @Type
* @HasLength %true if the binary representation of the list required a length field, %false if it
* must not have a length field
*
* Defines two functions ``void NS##_serialize(SerializeCtx* ctx, const struct list_head* list)``
* and ``bool NS##_deserialize(DeserializeCtx* ctx, struct list_head* list)`` for serialization and
* deserialization of lists.
*
* For serialization, each field is serialized in order by calling ``TypeNS##_serialize``.
*
* For deserialization, each field is deserialized into a newly kmalloc()ed element by calling
* ``TypeNS##_deserialize``. Correctly deserialized elements are appended to the provided
* &struct list_head. If deserialization fails the expression ``TypeFini(entry)`` is evaluated for
* each successfully deserialized element, ``list`` is left unchanged.
*/
#define SERDES_DEFINE_LIST_SERIALIZERS(Access, NS, Type, TypeNS, TypeFini, ListMember, HasLength) \
__attribute__((unused)) \
Access void NS##_serialize(SerializeCtx* ctx, const struct list_head* list) \
{ \
unsigned items = 0; \
Type* item; \
SerializeCtx ctxAtStart = *ctx; \
if (HasLength) \
Serialization_serializeUInt(ctx, 0); /* total field size */ \
Serialization_serializeUInt(ctx, 0); /* number of elements */ \
list_for_each_entry(item, list, ListMember) \
{ \
TypeNS##_serialize(ctx, item); \
items += 1; \
} \
if (HasLength) \
Serialization_serializeUInt(&ctxAtStart, ctx->length - ctxAtStart.length); \
Serialization_serializeUInt(&ctxAtStart, items); \
} \
__attribute__((unused)) \
Access bool NS##_deserialize(DeserializeCtx* ctx, struct list_head* list) \
{ \
DeserializeCtx innerCtx = {0, 0}; \
DeserializeCtx* usedCtx = NULL; \
unsigned items = 0; \
LIST_HEAD(desItems); \
\
if (HasLength) { \
if (!__Serialization_deserializeNestedField(ctx, &innerCtx)) \
return false; \
usedCtx = &innerCtx; \
} else { \
usedCtx = ctx; \
} \
if (!Serialization_deserializeUInt(usedCtx, &items)) \
return false; \
while (items-- > 0) \
{ \
Type* entry = kmalloc(sizeof(*entry), GFP_NOFS); \
if (!entry) \
goto err; \
if (!TypeNS##_deserialize(usedCtx, entry)) \
{ \
kfree(entry); \
goto err; \
} \
list_add_tail(&entry->ListMember, &desItems); \
} \
list_splice_tail(&desItems, list); \
return true; \
err: \
BEEGFS_KFREE_LIST_DTOR(&desItems, Type, ListMember, TypeFini); \
return false; \
}
/**
* SERDES_DEFINE_ENUM_SERIALIZERS() - defines static inline serializers for an enum type with a
* given underlying type.
* @NS namespace prefix for the generated functions
* @EnumTy full enum type
* @Underlying underlying integer type of the enum
* @SerdesSuffix suffix for the ``Serialization_`` functions that serialize the underlying type
*/
#define SERDES_DEFINE_ENUM_SERIALIZERS(NS, EnumTy, Underlying, SerdesSuffix) \
static inline void NS##_serialize(SerializeCtx* ctx, EnumTy value) \
{ \
Serialization_serialize##SerdesSuffix(ctx, (Underlying) value); \
} \
static inline bool NS##_deserialize(DeserializeCtx* ctx, EnumTy* value) \
{ \
Underlying raw; \
if (!Serialization_deserialize##SerdesSuffix(ctx, &raw)) \
return false; \
*value = (EnumTy) raw; \
return true; \
}
#endif /*SERIALIZATION_H_*/

View File

@@ -0,0 +1,22 @@
#ifndef common_toolkit_SerializationTypes_h_uxGn0NqFVyO6ma2TYHAEI
#define common_toolkit_SerializationTypes_h_uxGn0NqFVyO6ma2TYHAEI
#include <common/Common.h>
typedef struct SerializeCtx {
char* const data;
unsigned length;
} SerializeCtx;
typedef struct DeserializeCtx {
const char* data;
size_t length;
} DeserializeCtx;
typedef struct RawList {
const char* data;
unsigned length;
unsigned elemCount;
} RawList;
#endif

View File

@@ -0,0 +1,235 @@
#include <common/toolkit/SocketTk.h>
#include <common/net/sock/StandardSocket.h>
#include <common/net/sock/RDMASocket.h>
#include <common/Common.h>
#include <common/toolkit/TimeTk.h>
#include <linux/in.h>
#include <linux/inet.h>
#include <linux/poll.h>
#include <linux/net.h>
#include <linux/socket.h>
struct file* SocketTkDummyFilp = NULL;
/**
* One-time initialization of a dummy file pointer (required for polling)
* Note: remember to call the corresponding uninit routine
*/
bool SocketTk_initOnce(void)
{
SocketTkDummyFilp = filp_open("/dev/null", O_RDONLY, 0);
if(IS_ERR(SocketTkDummyFilp) )
{
printk_fhgfs(KERN_WARNING, "Failed to open the dummy filp for polling\n");
return false;
}
return true;
}
void SocketTk_uninitOnce(void)
{
if(SocketTkDummyFilp && !IS_ERR(SocketTkDummyFilp) )
filp_close(SocketTkDummyFilp, NULL);
}
/*
* Synchronous I/O multiplexing for standard and RDMA sockets.
* Note: comparable to userspace poll()
*
* @param pollState list of sockets and event wishes
* @return number of socks for which interesting events are available or negative linux error code.
* (tvp is being set to time remaining)
*/
int SocketTk_poll(PollState* state, int timeoutMS)
{
struct poll_wqueues stdTable;
poll_table* stdWait = NULL; // value NULL means "don't register for waiting"
int table_err = 0;
int numSocksWithREvents = 0; // the return value
Socket* socket;
long __timeout = TimeTk_msToJiffiesSchedulable(timeoutMS);
/* 4.19 (vanilla, not stable) had a bug in the sock_poll_wait signature. rhel 4.18 backports
* this bug. 4.19.1 fixes it again. */
BUILD_BUG_ON(__builtin_types_compatible_p(
__typeof__(&sock_poll_wait),
void (*)(struct file*, poll_table*)));
poll_initwait(&stdTable);
if(__timeout)
stdWait = &stdTable.pt;
// 1st loop: register the socks that we're waiting for and wait blocking
// if no data is available yet
// 2nd loop (after event or timeout): check all socks for available data
// note: std socks return all events, even those we haven't been waiting for
// 3rd and futher loops: in case an uninteresting event occurred
for( ; ; )
{
numSocksWithREvents = 0; // (must be inside the loop to be consistent)
/* wait INTERRUPTIBLE if no signal is pending, otherwise the wait contributes to load.
* users of this function should be migrated to use socket callbacks instead. */
set_current_state(signal_pending(current) ? TASK_KILLABLE : TASK_INTERRUPTIBLE);
// for each sock: ask for available data and register waitqueue
list_for_each_entry(socket, &state->list, poll._list)
{
if(Socket_getSockType(socket) == NICADDRTYPE_RDMA)
{ // RDMA socket
struct RDMASocket* currentRDMASock = (RDMASocket*)socket;
bool finishPoll = (numSocksWithREvents || !__timeout);
unsigned long mask = RDMASocket_poll(
currentRDMASock, socket->poll._events, finishPoll);
if(mask)
{ // interesting event occurred
socket->poll.revents = mask; // save event mask as revents
numSocksWithREvents++;
}
}
else
{ // Standard socket
struct socket* currentRawSock =
StandardSocket_getRawSock( (StandardSocket*)socket);
poll_table* currentStdWait = numSocksWithREvents ? NULL : stdWait;
unsigned long mask = (*currentRawSock->ops->poll)(
SocketTkDummyFilp, currentRawSock, currentStdWait);
if(mask & (socket->poll._events | POLLERR | POLLHUP | POLLNVAL) )
{ // interesting event occurred
socket->poll.revents = mask; // save event mask as revents
numSocksWithREvents++;
}
//cond_resched(); // (commented out for latency reasons)
}
} // end of for_each_socket loop
stdWait = NULL; // don't register standard socks for waiting in following loops
// skip the waiting if we already found something
if (numSocksWithREvents || !__timeout || fatal_signal_pending(current))
break;
// skip the waiting if we have an error
if(unlikely(stdTable.error) )
{
table_err = stdTable.error;
break;
}
// wait (and reduce remaining timeout)
__timeout = schedule_timeout(__timeout);
} // end of sleep loop
__set_current_state(TASK_RUNNING);
// cleanup loop for RDMA socks
list_for_each_entry(socket, &state->list, poll._list)
{
if(Socket_getSockType(socket) == NICADDRTYPE_RDMA)
{
struct RDMASocket* currentRDMASock = (RDMASocket*)socket;
RDMASocket_poll(currentRDMASock, socket->poll._events, true);
}
}
// cleanup for standard socks
poll_freewait(&stdTable);
//printk_fhgfs(KERN_INFO, "%s:%d: return %d\n", __func__, __LINE__,
// table_err ? table_err : numSocksWithREvents); // debug in
return table_err ? table_err : numSocksWithREvents;
}
/**
* Note: Old kernel versions do not support validation of the IP string.
*
* @param outIPAddr set to INADDR_NONE if an error was detected
* @return false for wrong input on modern kernels (>= 2.6.20), old kernels always return
* true
*/
bool SocketTk_getHostByAddrStr(const char* hostAddr, struct in_addr* outIPAddr)
{
if(unlikely(!in4_pton(hostAddr, strlen(hostAddr), (u8 *)outIPAddr, -1, NULL) ) )
{ // not a valid address string
outIPAddr->s_addr = INADDR_NONE;
return false;
}
return true;
}
/**
* Note: Better use SocketTk_getHostByAddrStr(), which can also check for errors on recent kernels.
*
* @return INADDR_NONE if an error was detected (recent kernels only)
*/
struct in_addr SocketTk_in_aton(const char* hostAddr)
{
struct in_addr retVal;
// Note: retVal INADDR_NONE will be set by getHostByAddrStr()
SocketTk_getHostByAddrStr(hostAddr, &retVal);
return retVal;
}
/**
* @param buf the buffer to which <IP> should be written.
*/
void SocketTk_ipaddrToStrNoAlloc(struct in_addr ipaddress, char* ipStr, size_t ipStrLen)
{
int printRes = snprintf(ipStr, ipStrLen, "%pI4", &ipaddress);
if(unlikely( (size_t)printRes >= ipStrLen) )
ipStr[ipStrLen-1] = 0; // ipStrLen exceeded => zero-terminate result
}
/**
* @return string is kalloced and needs to be kfreed
*/
char* SocketTk_ipaddrToStr(struct in_addr ipaddress)
{
char* ipStr = os_kmalloc(SOCKETTK_IPADDRSTR_LEN);
if (likely(ipStr != NULL))
SocketTk_ipaddrToStrNoAlloc(ipaddress, ipStr, SOCKETTK_IPADDRSTR_LEN);
return ipStr;
}
/**
* @param buf the buffer to which <IP>:<port> should be written.
*/
void SocketTk_endpointAddrToStrNoAlloc(char* buf, size_t bufLen, struct in_addr ipaddress,
unsigned short port)
{
int printRes = snprintf(buf, bufLen, "%pI4:%u", &ipaddress, port);
if(unlikely( (unsigned)printRes >= bufLen) )
buf[bufLen-1] = 0; // bufLen exceeded => zero-terminate result
}
/**
* @return string is kalloced and needs to be kfreed
*/
char* SocketTk_endpointAddrToStr(struct in_addr ipaddress, unsigned short port)
{
char* endpointStr = os_kmalloc(SOCKETTK_ENDPOINTSTR_LEN);
if (likely(endpointStr != NULL))
SocketTk_endpointAddrToStrNoAlloc(endpointStr, SOCKETTK_ENDPOINTSTR_LEN, ipaddress, port);
return endpointStr;
}

View File

@@ -0,0 +1,49 @@
#ifndef OPEN_SOCKETTK_H_
#define OPEN_SOCKETTK_H_
#include <common/Common.h>
#include <common/net/sock/Socket.h>
#include <common/toolkit/Time.h>
#include <linux/poll.h>
#define SOCKETTK_ENDPOINTSTR_LEN SOCKET_PEERNAME_LEN // size for _endpointAddrToStrNoAlloc()
#define SOCKETTK_IPADDRSTR_LEN (4*4)
// forward declarations
struct PollState;
typedef struct PollState PollState;
extern bool SocketTk_initOnce(void);
extern void SocketTk_uninitOnce(void);
extern int SocketTk_poll(PollState* state, int timeoutMS);
extern bool SocketTk_getHostByAddrStr(const char* hostAddr, struct in_addr* outIPAddr);
extern struct in_addr SocketTk_in_aton(const char* hostAddr);
extern char* SocketTk_ipaddrToStr(struct in_addr ipaddress);
extern void SocketTk_ipaddrToStrNoAlloc(struct in_addr ipaddress, char* ipStr, size_t ipStrLen);
extern char* SocketTk_endpointAddrToStr(struct in_addr ipaddress, unsigned short port);
extern void SocketTk_endpointAddrToStrNoAlloc(char* buf, size_t bufLen,
struct in_addr ipaddress, unsigned short port);
struct PollState
{
struct list_head list;
};
static inline void PollState_init(PollState* state)
{
INIT_LIST_HEAD(&state->list);
}
static inline void PollState_addSocket(PollState* state, Socket* socket, short events)
{
list_add_tail(&socket->poll._list, &state->list);
socket->poll._events = events;
socket->poll.revents = 0;
}
#endif /*OPEN_SOCKETTK_H_*/

View File

@@ -0,0 +1,125 @@
#include <common/toolkit/StringTk.h>
#include <common/Common.h>
void StringTk_explode(const char* s, char delimiter, StrCpyList* outList)
{
ssize_t sLen = strlen(s);
ssize_t lastPos = (strlen(s) && (s[0] == delimiter) ) ? 0 : -1;
ssize_t currentPos;
char* findRes;
ssize_t newElemLen;
// note: starts at pos 1 because an occurence at pos 0 would lead to an empty string,
// which would be ignored anyways
// note: i think the initialization of currentPos here is useless
for(currentPos = 1; ; )
{
findRes = strchr(&s[lastPos+1], delimiter);
if(!findRes)
{
ssize_t restLen = sLen - (lastPos+1);
if(restLen)
{ // add rest
char* newElem = StringTk_subStr(&s[lastPos+1], restLen);
StrCpyList_append(outList, newElem);
kfree(newElem);
}
return;
}
currentPos = findRes - s;
// add substring to outList (leave the delimiter positions out)
newElemLen = currentPos-lastPos-1; // -1=last delimiter
if(newElemLen)
{
char* newElem = StringTk_subStr(&s[lastPos+1], newElemLen);
StrCpyList_append(outList, newElem);
kfree(newElem);
}
lastPos = currentPos;
}
}
bool StringTk_strToBool(const char* s)
{
if( !StringTk_hasLength(s) ||
!strcmp(s, "1") ||
!strcasecmp(s, "y") ||
!strcasecmp(s, "on") ||
!strcasecmp(s, "yes") ||
!strcasecmp(s, "true") )
return true;
return false;
}
/**
* @return string is kmalloc'ed and has to be kfree'd by the caller
*/
char* StringTk_trimCopy(const char* s)
{
int lastRight;
int firstLeft;
int sLen;
sLen = strlen(s);
firstLeft = 0;
while( (firstLeft < sLen) &&
(s[firstLeft]==' ' || s[firstLeft]=='\n' || s[firstLeft]=='\r' || s[firstLeft]=='\t') )
firstLeft++;
if(firstLeft == sLen)
return StringTk_strDup(""); // the string is empty or contains only space chars
// the string contains at least one non-space char
lastRight = sLen - 1;
while(s[lastRight]==' ' || s[lastRight]=='\n' || s[lastRight]=='\r' || s[lastRight]=='\t')
lastRight--;
return StringTk_subStr(&s[firstLeft], lastRight - firstLeft + 1);
}
/**
* Note: Provided, because old kernels don't provide kasprintf().
*
* @return will be kalloced and needs to be kfree'd by the caller
*/
char* StringTk_kasprintf(const char *fmt, ...)
{
char* printStr;
int printLen;
char tmpChar; // (old kernels don't seem to be able to handle vsnprintf(NULL, 0, ...) )
va_list ap;
va_list apCopy; // kasprintf uses this
va_start(ap, fmt);
va_copy(apCopy, ap);
printLen = vsnprintf(&tmpChar, 1, fmt, apCopy);
va_end(apCopy);
printStr = os_kmalloc(printLen + 1);
if(likely(printStr) )
{
vsnprintf(printStr, printLen + 1, fmt, ap);
}
va_end(ap);
return printStr;
}

View File

@@ -0,0 +1,101 @@
#ifndef OPEN_STRINGTK_H_
#define OPEN_STRINGTK_H_
#include <common/Common.h>
#include <common/toolkit/list/StrCpyList.h>
// manipulation
extern void StringTk_explode(const char* s, char delimiter, StrCpyList* outList);
static inline char* StringTk_strncpyTerminated(char* dest, const char* src, size_t count);
// numerical
static inline int StringTk_strToInt(const char* s);
static inline unsigned StringTk_strToUInt(const char* s);
static inline uint64_t StringTk_strToUInt64(const char* s);
extern bool StringTk_strToBool(const char* s);
// construction
static inline char* StringTk_strDup(const char* s);
static inline char* StringTk_subStr(const char* start, unsigned numChars);
extern char* StringTk_trimCopy(const char* s);
extern char* StringTk_kasprintf(const char *fmt, ...);
static inline char* StringTk_intToStr(int a);
static inline char* StringTk_uintToStr(unsigned a);
// inliners
static inline bool StringTk_hasLength(const char* s);
bool StringTk_hasLength(const char* s)
{
return s[0] ? true : false;
}
char* StringTk_strncpyTerminated(char* dest, const char* src, size_t count)
{
// Note: The problem with strncpy() is that dest is not guaranteed to be zero-terminated.
// strlcpy() does guarantee that.
// strlcpy() was removed in commit d26270061ae6 (string: Remove strlcpy()), use strscpy() instead.
strscpy(dest, src, count);
return dest;
}
int StringTk_strToInt(const char* s)
{
return (int)simple_strtol(s, NULL, 10);
}
unsigned StringTk_strToUInt(const char* s)
{
return (unsigned)simple_strtoul(s, NULL, 10);
}
uint64_t StringTk_strToUInt64(const char* s)
{
return simple_strtoull(s, NULL, 10);
}
char* StringTk_strDup(const char* s)
{
return kstrdup(s, GFP_NOFS);
}
/**
* @return string is kmalloc'ed and has to be kfree'd by the caller
*/
char* StringTk_subStr(const char* start, unsigned numChars)
{
char* subStr = (char*)os_kmalloc(numChars+1);
if(numChars)
memcpy(subStr, start, numChars);
subStr[numChars] = 0;
return subStr;
}
char* StringTk_intToStr(int a)
{
char aStr[24];
sprintf(aStr, "%d", a);
return StringTk_strDup(aStr);
}
char* StringTk_uintToStr(unsigned a)
{
char aStr[24];
sprintf(aStr, "%u", a);
return StringTk_strDup(aStr);
}
#endif /*OPEN_STRINGTK_H_*/

View File

@@ -0,0 +1,52 @@
#ifndef SYNCHRONIZEDCOUNTER_H_
#define SYNCHRONIZEDCOUNTER_H_
#include <common/Common.h>
#include <common/threading/Mutex.h>
#include <common/threading/Condition.h>
#include <asm/atomic.h>
#include <linux/completion.h>
struct SynchronizedCounter;
typedef struct SynchronizedCounter SynchronizedCounter;
static inline void SynchronizedCounter_init(SynchronizedCounter* this);
// inliners
static inline void SynchronizedCounter_waitForCount(SynchronizedCounter* this, int waitCount);
static inline void SynchronizedCounter_incCount(SynchronizedCounter* this);
static inline void SynchronizedCounter_incCountBy(SynchronizedCounter* this, int count);
struct SynchronizedCounter
{
atomic_t count;
struct completion barrier;
};
void SynchronizedCounter_init(SynchronizedCounter* this)
{
atomic_set(&this->count, 0);
init_completion(&this->barrier);
}
void SynchronizedCounter_waitForCount(SynchronizedCounter* this, int waitCount)
{
SynchronizedCounter_incCountBy(this, -waitCount);
wait_for_completion(&this->barrier);
}
void SynchronizedCounter_incCount(SynchronizedCounter* this)
{
SynchronizedCounter_incCountBy(this, 1);
}
void SynchronizedCounter_incCountBy(SynchronizedCounter* this, int count)
{
if (atomic_add_return(count, &this->count) == 0)
complete(&this->barrier);
}
#endif /*SYNCHRONIZEDCOUNTER_H_*/

View File

@@ -0,0 +1,122 @@
#ifndef OPEN_TIME_H_
#define OPEN_TIME_H_
#include <common/Common.h>
#include <linux/ktime.h>
#include <linux/time.h>
/**
* The basis for this Time class is a monotonic clock.
*/
#ifdef KERNEL_HAS_64BIT_TIMESTAMPS
typedef struct timespec64 Time;
#else
typedef struct timespec Time;
#endif
static inline unsigned Time_elapsedSinceMS(Time* this, Time* earlierT);
static inline unsigned long long Time_elapsedSinceNS(Time* this, Time* earlierT);
static inline unsigned Time_elapsedMS(Time* this);
static inline int Time_compare(Time* this, Time* o);
static inline unsigned long long Time_toNS(Time* this);
static inline void Time_setToNow(Time* this)
{
#ifdef KERNEL_HAS_KTIME_GET_TS64
ktime_get_ts64(this);
#else
ktime_get_ts(this);
#endif
}
/**
* Set time to to "real" time, i.e. get the time from a non-monotonic clock.
*/
static inline void Time_setToNowReal(Time *this)
{
#ifdef KERNEL_HAS_KTIME_GET_REAL_TS64
ktime_get_real_ts64(this);
#else
ktime_get_real_ts(this);
#endif
}
static inline void Time_setZero(Time *this)
{
this->tv_sec = 0;
this->tv_nsec = 0;
}
/**
* Set to current time.
*/
static inline void Time_init(Time* this)
{
Time_setToNow(this);
}
/**
* Set time values to zero, e.g. to mark this time as unitialized or far back in the past.
*/
static inline void Time_initZero(Time* this)
{
Time_setZero(this);
}
static inline bool Time_getIsZero(Time* this)
{
return (!this->tv_sec && !this->tv_sec);
}
static inline unsigned Time_elapsedSinceMS(Time* this, Time* earlierT)
{
unsigned secs = (this->tv_sec - earlierT->tv_sec) * 1000;
int micros = (this->tv_nsec - earlierT->tv_nsec) / 1000000; /* can also be negative,
so this must be signed */
return secs + micros;
}
unsigned long long Time_elapsedSinceNS(Time* this, Time* earlierT)
{
unsigned long long secs = (this->tv_sec - earlierT->tv_sec) * 1000000000ull;
long nanos = (this->tv_nsec - earlierT->tv_nsec); /* can also be negative,
so this must be signed */
return secs + nanos;
}
unsigned long long Time_toNS(Time* this)
{
return this->tv_sec * 1000000000ull + this->tv_nsec;
}
int Time_compare(Time* this, Time* o)
{
long long diff = Time_toNS(this) - Time_toNS(o);
if (diff < 0)
return -1;
else if (diff > 0)
return 1;
return 0;
}
unsigned Time_elapsedMS(Time* this)
{
unsigned elapsedMS;
Time currentT;
Time_init(&currentT);
elapsedMS = Time_elapsedSinceMS(&currentT, this);
return elapsedMS;
}
#endif /* OPEN_TIME_H_ */

View File

@@ -0,0 +1,21 @@
#ifndef TIMETK_H_
#define TIMETK_H_
#include <common/Common.h>
#include <linux/sched.h>
static inline long TimeTk_msToJiffiesSchedulable(unsigned ms);
long TimeTk_msToJiffiesSchedulable(unsigned ms)
{
unsigned long resultJiffies = msecs_to_jiffies(ms);
return (resultJiffies >= MAX_SCHEDULE_TIMEOUT) ? (MAX_SCHEDULE_TIMEOUT-1) : resultJiffies;
}
#endif /*TIMETK_H_*/

View File

@@ -0,0 +1,20 @@
#include "AckStoreMap.h"
#include "AckStoreMapIter.h"
AckStoreMapIter AckStoreMap_find(AckStoreMap* this, const char* searchKey)
{
RBTreeElem* treeElem = _PointerRBTree_findElem( (RBTree*)this, searchKey);
AckStoreMapIter iter;
AckStoreMapIter_init(&iter, this, treeElem);
return iter;
}
int compareAckStoreMapElems(const void* key1, const void* key2)
{
return strcmp(key1, key2);
}

View File

@@ -0,0 +1,117 @@
#ifndef ACKSTOREMAP_H_
#define ACKSTOREMAP_H_
#include <common/toolkit/tree/PointerRBTree.h>
#include <common/toolkit/tree/PointerRBTreeIter.h>
#include "WaitAckMap.h"
struct AckStoreEntry;
typedef struct AckStoreEntry AckStoreEntry;
struct AckStoreMapElem;
typedef struct AckStoreMapElem AckStoreMapElem;
struct AckStoreMap;
typedef struct AckStoreMap AckStoreMap;
struct AckStoreMapIter; // forward declaration of the iterator
static inline void AckStoreEntry_init(AckStoreEntry* this, char* ackID,
WaitAckMap* waitMap, WaitAckMap* receivedMap, WaitAckNotification* notifier);
static inline AckStoreEntry* AckStoreEntry_construct(char* ackID,
WaitAckMap* waitMap, WaitAckMap* receivedMap, WaitAckNotification* notifier);
static inline void AckStoreEntry_destruct(AckStoreEntry* this);
static inline void AckStoreMap_init(AckStoreMap* this);
static inline void AckStoreMap_uninit(AckStoreMap* this);
static inline bool AckStoreMap_insert(AckStoreMap* this, char* newKey,
AckStoreEntry* newValue);
static inline bool AckStoreMap_erase(AckStoreMap* this, const char* eraseKey);
extern struct AckStoreMapIter AckStoreMap_find(AckStoreMap* this, const char* searchKey);
extern int compareAckStoreMapElems(const void* key1, const void* key2);
struct AckStoreEntry
{
char* ackID;
WaitAckMap* waitMap; // ack will be removed from this map if it is received
WaitAckMap* receivedMap; // ack will be added to this map if it is received
WaitAckNotification* notifier;
};
struct AckStoreMapElem
{
RBTreeElem rbTreeElem;
};
struct AckStoreMap
{
RBTree rbTree;
};
void AckStoreEntry_init(AckStoreEntry* this, char* ackID,
WaitAckMap* waitMap, WaitAckMap* receivedMap, WaitAckNotification* notifier)
{
this->ackID = ackID;
this->waitMap = waitMap;
this->receivedMap = receivedMap;
this->notifier = notifier;
}
AckStoreEntry* AckStoreEntry_construct(char* ackID,
WaitAckMap* waitMap, WaitAckMap* receivedMap, WaitAckNotification* notifier)
{
AckStoreEntry* this = (AckStoreEntry*)os_kmalloc(sizeof(*this) );
AckStoreEntry_init(this, ackID, waitMap, receivedMap, notifier);
return this;
}
void AckStoreEntry_destruct(AckStoreEntry* this)
{
kfree(this);
}
void AckStoreMap_init(AckStoreMap* this)
{
PointerRBTree_init( (RBTree*)this, compareAckStoreMapElems);
}
void AckStoreMap_uninit(AckStoreMap* this)
{
PointerRBTree_uninit( (RBTree*)this);
}
bool AckStoreMap_insert(AckStoreMap* this, char* newKey, AckStoreEntry* newValue)
{
bool insRes;
insRes = PointerRBTree_insert( (RBTree*)this, newKey, newValue);
if(!insRes)
{
// not inserted because the key already existed
}
return insRes;
}
bool AckStoreMap_erase(AckStoreMap* this, const char* eraseKey)
{
return PointerRBTree_erase( (RBTree*)this, eraseKey);
}
#endif /* ACKSTOREMAP_H_ */

View File

@@ -0,0 +1,34 @@
#ifndef ACKSTOREMAPITER_H_
#define ACKSTOREMAPITER_H_
#include "AckStoreMap.h"
struct AckStoreMapIter;
typedef struct AckStoreMapIter AckStoreMapIter;
static inline void AckStoreMapIter_init(AckStoreMapIter* this, AckStoreMap* map, RBTreeElem* treeElem);
static inline AckStoreEntry* AckStoreMapIter_value(AckStoreMapIter* this);
static inline bool AckStoreMapIter_end(AckStoreMapIter* this);
struct AckStoreMapIter
{
RBTreeIter rbTreeIter;
};
void AckStoreMapIter_init(AckStoreMapIter* this, AckStoreMap* map, RBTreeElem* treeElem)
{
PointerRBTreeIter_init( (RBTreeIter*)this, (RBTree*)map, (RBTreeElem*)treeElem);
}
AckStoreEntry* AckStoreMapIter_value(AckStoreMapIter* this)
{
return (AckStoreEntry*)PointerRBTreeIter_value( (RBTreeIter*)this);
}
bool AckStoreMapIter_end(AckStoreMapIter* this)
{
return PointerRBTreeIter_end( (RBTreeIter*)this);
}
#endif /* ACKSTOREMAPITER_H_ */

View File

@@ -0,0 +1,117 @@
#include "AcknowledgmentStore.h"
/**
* Note: This method does not lock the notifier->waitAcksMutex, because this is typically
* called from a context that does not yet require syncing.
*
* @param waitAcks do not access this map until you called unregister (for thread-safety)
* @param receivedAcks do not access this map until you called unregister (for thread-safety)
* @param notifier used to wake up the thread waiting for acks
*/
void AcknowledgmentStore_registerWaitAcks(AcknowledgmentStore* this,
WaitAckMap* waitAcks, WaitAckMap* receivedAcks, WaitAckNotification* notifier)
{
WaitAckMapIter iter;
Mutex_lock(&this->mutex);
for(iter = WaitAckMap_begin(waitAcks); !WaitAckMapIter_end(&iter); WaitAckMapIter_next(&iter) )
{
WaitAck* currentWaitAck = WaitAckMapIter_value(&iter);
AckStoreEntry* newStoreEntry = AckStoreEntry_construct(
currentWaitAck->ackID, waitAcks, receivedAcks, notifier);
AckStoreMap_insert(&this->storeMap, currentWaitAck->ackID, newStoreEntry);
}
Mutex_unlock(&this->mutex);
}
void AcknowledgmentStore_unregisterWaitAcks(AcknowledgmentStore* this, WaitAckMap* waitAcks)
{
WaitAckMapIter iter;
Mutex_lock(&this->mutex);
for(iter = WaitAckMap_begin(waitAcks); !WaitAckMapIter_end(&iter); WaitAckMapIter_next(&iter) )
{
char* currentKey = WaitAckMapIter_key(&iter);
AckStoreMapIter storeIter = AckStoreMap_find(&this->storeMap, currentKey);
// free allocated entry and remove it from store map
AckStoreEntry_destruct(AckStoreMapIter_value(&storeIter) );
AckStoreMap_erase(&this->storeMap, currentKey);
}
Mutex_unlock(&this->mutex);
}
/**
* @return true if someone was waiting for this ackID, false otherwise
*/
bool AcknowledgmentStore_receivedAck(AcknowledgmentStore* this, const char* ackID)
{
bool retVal = false;
AckStoreMapIter storeIter;
Mutex_lock(&this->mutex); // L O C K (store)
storeIter = AckStoreMap_find(&this->storeMap, ackID);
if(!AckStoreMapIter_end(&storeIter) )
{ // ack entry exists in store
WaitAckMapIter waitIter;
AckStoreEntry* storeEntry = AckStoreMapIter_value(&storeIter);
Mutex_lock(&storeEntry->notifier->waitAcksMutex); // L O C K (notifier)
waitIter = WaitAckMap_find(storeEntry->waitMap, ackID);
if(!WaitAckMapIter_end(&waitIter) )
{ // entry exists in waitMap => move to receivedMap
char* waitAckID = WaitAckMapIter_key(&waitIter);
WaitAck* waitAck = WaitAckMapIter_value(&waitIter);
WaitAckMap_insert(storeEntry->receivedMap, waitAckID, waitAck);
WaitAckMap_erase(storeEntry->waitMap, ackID);
if(!WaitAckMap_length(storeEntry->waitMap) )
{ // all acks received => notify
WaitAckNotification* notifier = storeEntry->notifier;
Condition_broadcast(&notifier->waitAcksCompleteCond);
}
retVal = true;
}
Mutex_unlock(&storeEntry->notifier->waitAcksMutex); // U N L O C K (notifier)
AckStoreEntry_destruct(storeEntry);
AckStoreMap_erase(&this->storeMap, ackID);
}
Mutex_unlock(&this->mutex); // U N L O C K (store)
return retVal;
}
bool AcknowledgmentStore_waitForAckCompletion(AcknowledgmentStore* this,
WaitAckMap* waitAcks, WaitAckNotification* notifier, int timeoutMS)
{
bool retVal;
Mutex_lock(&notifier->waitAcksMutex);
if(WaitAckMap_length(waitAcks) )
Condition_timedwait(&notifier->waitAcksCompleteCond, &notifier->waitAcksMutex, timeoutMS);
retVal = WaitAckMap_length(waitAcks) ? false : true;
Mutex_unlock(&notifier->waitAcksMutex);
return retVal;
}

View File

@@ -0,0 +1,67 @@
#ifndef ACKNOWLEDGMENTSTORE_H_
#define ACKNOWLEDGMENTSTORE_H_
#include <common/Common.h>
#include <common/nodes/Node.h>
#include <common/threading/Mutex.h>
#include <common/threading/Condition.h>
#include "AckStoreMap.h"
#include "AckStoreMapIter.h"
#include "WaitAckMap.h"
#include "WaitAckMapIter.h"
struct AcknowledgmentStore;
typedef struct AcknowledgmentStore AcknowledgmentStore;
static inline void AcknowledgmentStore_init(AcknowledgmentStore* this);
static inline AcknowledgmentStore* AcknowledgmentStore_construct(void);
static inline void AcknowledgmentStore_uninit(AcknowledgmentStore* this);
static inline void AcknowledgmentStore_destruct(AcknowledgmentStore* this);
extern void AcknowledgmentStore_registerWaitAcks(AcknowledgmentStore* this,
WaitAckMap* waitAcks, WaitAckMap* receivedAcks, WaitAckNotification* notifier);
extern void AcknowledgmentStore_unregisterWaitAcks(AcknowledgmentStore* this, WaitAckMap* waitAcks);
extern bool AcknowledgmentStore_receivedAck(AcknowledgmentStore* this, const char* ackID);
extern bool AcknowledgmentStore_waitForAckCompletion(AcknowledgmentStore* this,
WaitAckMap* waitAcks, WaitAckNotification* notifier, int timeoutMS);
struct AcknowledgmentStore
{
AckStoreMap storeMap;
Mutex mutex;
};
void AcknowledgmentStore_init(AcknowledgmentStore* this)
{
AckStoreMap_init(&this->storeMap);
Mutex_init(&this->mutex);
}
AcknowledgmentStore* AcknowledgmentStore_construct(void)
{
AcknowledgmentStore* this = (AcknowledgmentStore*)os_kmalloc(sizeof(*this) );
AcknowledgmentStore_init(this);
return this;
}
void AcknowledgmentStore_uninit(AcknowledgmentStore* this)
{
Mutex_uninit(&this->mutex);
AckStoreMap_uninit(&this->storeMap);
}
void AcknowledgmentStore_destruct(AcknowledgmentStore* this)
{
AcknowledgmentStore_uninit(this);
kfree(this);
}
#endif /* ACKNOWLEDGMENTSTORE_H_ */

View File

@@ -0,0 +1,32 @@
#include "WaitAckMap.h"
#include "WaitAckMapIter.h"
WaitAckMapIter WaitAckMap_find(WaitAckMap* this, const char* searchKey)
{
RBTreeElem* treeElem = _PointerRBTree_findElem( (RBTree*)this, searchKey);
WaitAckMapIter iter;
WaitAckMapIter_init(&iter, this, treeElem);
return iter;
}
WaitAckMapIter WaitAckMap_begin(WaitAckMap* this)
{
struct rb_node* node = rb_first(&this->rbTree.treeroot);
RBTreeElem* treeElem = node ? container_of(node, RBTreeElem, treenode) : NULL;
WaitAckMapIter iter;
WaitAckMapIter_init(&iter, this, treeElem);
return iter;
}
int compareWaitAckMapElems(const void* key1, const void* key2)
{
return strcmp(key1, key2);
}

View File

@@ -0,0 +1,136 @@
#ifndef WAITACKMAP_H_
#define WAITACKMAP_H_
#include <common/nodes/Node.h>
#include <common/toolkit/tree/PointerRBTree.h>
#include <common/toolkit/tree/PointerRBTreeIter.h>
#include <common/threading/Mutex.h>
#include <common/threading/Condition.h>
struct WaitAckNotification;
typedef struct WaitAckNotification WaitAckNotification;
struct WaitAck;
typedef struct WaitAck WaitAck;
struct WaitAckMapElem;
typedef struct WaitAckMapElem WaitAckMapElem;
struct WaitAckMap;
typedef struct WaitAckMap WaitAckMap;
struct WaitAckMapIter; // forward declaration of the iterator
static inline void WaitAckNotification_init(WaitAckNotification* this);
static inline void WaitAckNotification_uninit(WaitAckNotification* this);
static inline void WaitAck_init(WaitAck* this, char* ackID, void* privateData);
static inline void WaitAckMap_init(WaitAckMap* this);
static inline void WaitAckMap_uninit(WaitAckMap* this);
static inline bool WaitAckMap_insert(WaitAckMap* this, char* newKey,
WaitAck* newValue);
static inline bool WaitAckMap_erase(WaitAckMap* this, const char* eraseKey);
static inline size_t WaitAckMap_length(WaitAckMap* this);
static inline void WaitAckMap_clear(WaitAckMap* this);
extern struct WaitAckMapIter WaitAckMap_find(WaitAckMap* this, const char* searchKey);
extern struct WaitAckMapIter WaitAckMap_begin(WaitAckMap* this);
extern int compareWaitAckMapElems(const void* key1, const void* key2);
struct WaitAckNotification
{
Mutex waitAcksMutex; // this mutex also syncs access to the waitMap/receivedMap during the
// wait phase (which is between registration and deregistration)
Condition waitAcksCompleteCond; // in case all WaitAcks have been received
};
struct WaitAck
{
char* ackID;
void* privateData; // caller's private data
};
struct WaitAckMapElem
{
RBTreeElem rbTreeElem;
};
struct WaitAckMap
{
RBTree rbTree;
};
void WaitAckNotification_init(WaitAckNotification* this)
{
Mutex_init(&this->waitAcksMutex);
Condition_init(&this->waitAcksCompleteCond);
}
void WaitAckNotification_uninit(WaitAckNotification* this)
{
Mutex_uninit(&this->waitAcksMutex);
}
/**
* @param ackID is not copied, so don't free or touch it while you use this object
* @param privateData any private data that helps the caller to identify to ack later
*/
void WaitAck_init(WaitAck* this, char* ackID, void* privateData)
{
this->ackID = ackID;
this->privateData = privateData;
}
void WaitAckMap_init(WaitAckMap* this)
{
PointerRBTree_init( (RBTree*)this, compareWaitAckMapElems);
}
void WaitAckMap_uninit(WaitAckMap* this)
{
PointerRBTree_uninit( (RBTree*)this);
}
bool WaitAckMap_insert(WaitAckMap* this, char* newKey, WaitAck* newValue)
{
bool insRes;
insRes = PointerRBTree_insert( (RBTree*)this, newKey, newValue);
if(!insRes)
{
// not inserted because the key already existed
}
return insRes;
}
bool WaitAckMap_erase(WaitAckMap* this, const char* eraseKey)
{
return PointerRBTree_erase( (RBTree*)this, eraseKey);
}
size_t WaitAckMap_length(WaitAckMap* this)
{
return PointerRBTree_length( (RBTree*)this);
}
void WaitAckMap_clear(WaitAckMap* this)
{
PointerRBTree_clear(&this->rbTree);
}
#endif /* WAITACKMAP_H_ */

View File

@@ -0,0 +1,46 @@
#ifndef WAITACKMAPITER_H_
#define WAITACKMAPITER_H_
#include "WaitAckMap.h"
struct WaitAckMapIter;
typedef struct WaitAckMapIter WaitAckMapIter;
static inline void WaitAckMapIter_init(WaitAckMapIter* this, WaitAckMap* map, RBTreeElem* treeElem);
static inline WaitAck* WaitAckMapIter_next(WaitAckMapIter* this);
static inline char* WaitAckMapIter_key(WaitAckMapIter* this);
static inline WaitAck* WaitAckMapIter_value(WaitAckMapIter* this);
static inline bool WaitAckMapIter_end(WaitAckMapIter* this);
struct WaitAckMapIter
{
RBTreeIter rbTreeIter;
};
void WaitAckMapIter_init(WaitAckMapIter* this, WaitAckMap* map, RBTreeElem* treeElem)
{
PointerRBTreeIter_init( (RBTreeIter*)this, (RBTree*)map, (RBTreeElem*)treeElem);
}
WaitAck* WaitAckMapIter_next(WaitAckMapIter* this)
{
return (WaitAck*)PointerRBTreeIter_next( (RBTreeIter*)this);
}
char* WaitAckMapIter_key(WaitAckMapIter* this)
{
return (char*)PointerRBTreeIter_key( (RBTreeIter*)this);
}
WaitAck* WaitAckMapIter_value(WaitAckMapIter* this)
{
return (WaitAck*)PointerRBTreeIter_value( (RBTreeIter*)this);
}
bool WaitAckMapIter_end(WaitAckMapIter* this)
{
return PointerRBTreeIter_end( (RBTreeIter*)this);
}
#endif /* WAITACKMAPITER_H_ */

View File

@@ -0,0 +1,73 @@
#ifndef INT64CPYLIST_H_
#define INT64CPYLIST_H_
#include <common/toolkit/list/PointerList.h>
/**
* We need to copy int64 values (instead of just assigning them to just to the internal pointer)
* because we might be running on 32bit archs.
*/
struct Int64CpyList;
typedef struct Int64CpyList Int64CpyList;
static inline void Int64CpyList_init(Int64CpyList* this);
static inline void Int64CpyList_uninit(Int64CpyList* this);
static inline void Int64CpyList_append(Int64CpyList* this, int64_t value);
static inline size_t Int64CpyList_length(Int64CpyList* this);
static inline void Int64CpyList_clear(Int64CpyList* this);
struct Int64CpyList
{
struct PointerList pointerList;
};
void Int64CpyList_init(Int64CpyList* this)
{
PointerList_init( (PointerList*)this);
}
void Int64CpyList_uninit(Int64CpyList* this)
{
struct PointerListElem* elem = ( (PointerList*)this)->head;
while(elem)
{
struct PointerListElem* next = elem->next;
kfree(elem->valuePointer);
elem = next;
}
PointerList_uninit( (PointerList*)this);
}
void Int64CpyList_append(Int64CpyList* this, int64_t value)
{
int64_t* valueCopyPointer = (int64_t*)os_kmalloc(sizeof(int64_t) );
*valueCopyPointer = value;
PointerList_append( (PointerList*)this, valueCopyPointer);
}
static inline size_t Int64CpyList_length(Int64CpyList* this)
{
return PointerList_length( (PointerList*)this);
}
void Int64CpyList_clear(Int64CpyList* this)
{
struct PointerListElem* elem = ( (PointerList*)this)->head;
while(elem)
{
struct PointerListElem* next = elem->next;
kfree(elem->valuePointer);
elem = next;
}
PointerList_clear( (PointerList*)this);
}
#endif /*INT64CPYLIST_H_*/

View File

@@ -0,0 +1,43 @@
#ifndef INT64CPYLISTITER_H_
#define INT64CPYLISTITER_H_
#include "Int64CpyList.h"
#include "PointerListIter.h"
struct Int64CpyListIter;
typedef struct Int64CpyListIter Int64CpyListIter;
static inline void Int64CpyListIter_init(Int64CpyListIter* this, Int64CpyList* list);
static inline void Int64CpyListIter_next(Int64CpyListIter* this);
static inline int64_t Int64CpyListIter_value(Int64CpyListIter* this);
static inline bool Int64CpyListIter_end(Int64CpyListIter* this);
struct Int64CpyListIter
{
struct PointerListIter pointerListIter;
};
void Int64CpyListIter_init(Int64CpyListIter* this, Int64CpyList* list)
{
PointerListIter_init( (PointerListIter*)this, (PointerList*)list);
}
void Int64CpyListIter_next(Int64CpyListIter* this)
{
PointerListIter_next( (PointerListIter*)this);
}
int64_t Int64CpyListIter_value(Int64CpyListIter* this)
{
return *(int64_t*)PointerListIter_value( (PointerListIter*)this);
}
bool Int64CpyListIter_end(Int64CpyListIter* this)
{
return PointerListIter_end( (PointerListIter*)this);
}
#endif /*INT64CPYLISTITER_H_*/

View File

@@ -0,0 +1,54 @@
#ifndef NUMNODEIDLIST_H_
#define NUMNODEIDLIST_H_
#include <common/nodes/NumNodeID.h>
#include <common/toolkit/list/PointerList.h>
/**
* Derived from PointerList. Internally, we cast NumNodeID values directly to pointers here (instead
* of allocating them and assigning the pointer to the allocated mem here).
*/
struct NumNodeIDList;
typedef struct NumNodeIDList NumNodeIDList;
static inline void NumNodeIDList_init(NumNodeIDList* this);
static inline void NumNodeIDList_uninit(NumNodeIDList* this);
static inline void NumNodeIDList_append(NumNodeIDList* this, NumNodeID value);
static inline size_t NumNodeIDList_length(NumNodeIDList* this);
static inline void NumNodeIDList_clear(NumNodeIDList* this);
struct NumNodeIDList
{
struct PointerList pointerList;
};
void NumNodeIDList_init(NumNodeIDList* this)
{
PointerList_init( (PointerList*)this);
}
void NumNodeIDList_uninit(NumNodeIDList* this)
{
PointerList_uninit( (PointerList*)this);
}
void NumNodeIDList_append(NumNodeIDList* this, NumNodeID value)
{
/* cast value directly to pointer type here to store value directly in the pointer variable
without allocating extra mem */
PointerList_append( (PointerList*)this, (void*)(size_t)value.value);
}
static inline size_t NumNodeIDList_length(NumNodeIDList* this)
{
return PointerList_length( (PointerList*)this);
}
void NumNodeIDList_clear(NumNodeIDList* this)
{
PointerList_clear( (PointerList*)this);
}
#endif /* NUMNODEIDLIST_H_ */

View File

@@ -0,0 +1,43 @@
#ifndef NUMNODEIDLISTITER_H_
#define NUMNODEIDLISTITER_H_
#include <common/toolkit/list/PointerListIter.h>
#include "NumNodeIDList.h"
struct NumNodeIDListIter;
typedef struct NumNodeIDListIter NumNodeIDListIter;
static inline void NumNodeIDListIter_init(NumNodeIDListIter* this, NumNodeIDList* list);
static inline void NumNodeIDListIter_next(NumNodeIDListIter* this);
static inline NumNodeID NumNodeIDListIter_value(NumNodeIDListIter* this);
static inline bool NumNodeIDListIter_end(NumNodeIDListIter* this);
struct NumNodeIDListIter
{
struct PointerListIter pointerListIter;
};
void NumNodeIDListIter_init(NumNodeIDListIter* this, NumNodeIDList* list)
{
PointerListIter_init( (PointerListIter*)this, (PointerList*)list);
}
void NumNodeIDListIter_next(NumNodeIDListIter* this)
{
PointerListIter_next( (PointerListIter*)this);
}
NumNodeID NumNodeIDListIter_value(NumNodeIDListIter* this)
{
return (NumNodeID){(size_t)PointerListIter_value( (PointerListIter*)this)};
}
bool NumNodeIDListIter_end(NumNodeIDListIter* this)
{
return PointerListIter_end( (PointerListIter*)this);
}
#endif /* NUMNODEIDLISTITER_H_ */

View File

@@ -0,0 +1,267 @@
#ifndef POINTERLIST_H_
#define POINTERLIST_H_
#include <common/Common.h>
struct PointerListElem;
typedef struct PointerListElem PointerListElem;
struct PointerList;
typedef struct PointerList PointerList;
static inline void PointerList_init(PointerList* this);
static inline void PointerList_uninit(PointerList* this);
static inline void PointerList_addHead(PointerList* this, void* valuePointer);
static inline void PointerList_addTail(PointerList* this, void* valuePointer);
static inline void PointerList_append(PointerList* this, void* valuePointer);
static inline void PointerList_removeHead(PointerList* this);
static inline void PointerList_removeTail(PointerList* this);
static inline void PointerList_removeElem(PointerList* this, PointerListElem* elem);
static inline void PointerList_moveToHead(PointerList* this, PointerListElem* elem);
static inline void PointerList_moveToTail(PointerList* this, PointerListElem* elem);
static inline size_t PointerList_length(const PointerList* this);
static inline void PointerList_clear(PointerList* this);
static inline PointerListElem* PointerList_getTail(PointerList* this);
static inline PointerListElem* PointerList_getHead(PointerList* this);
struct PointerListElem
{
void* valuePointer;
struct PointerListElem* prev;
struct PointerListElem* next;
};
struct PointerList
{
struct PointerListElem* head;
struct PointerListElem* tail;
size_t length;
};
void PointerList_init(PointerList* this)
{
this->head = NULL;
this->tail = NULL;
this->length = 0;
}
void PointerList_uninit(PointerList* this)
{
PointerList_clear(this);
}
static inline void __PointerList_addHead(PointerList* this, PointerListElem* elem)
{
if(this->length)
{ // elements exist => replace head
elem->next = this->head;
this->head->prev = elem;
this->head = elem;
}
else
{ // no elements exist yet
this->head = elem;
this->tail = elem;
elem->next = NULL;
}
elem->prev = NULL;
this->length++;
}
void PointerList_addHead(PointerList* this, void* valuePointer)
{
PointerListElem* elem = (PointerListElem*)os_kmalloc(
sizeof(PointerListElem) );
elem->valuePointer = valuePointer;
__PointerList_addHead(this, elem);
}
static inline void __PointerList_addTail(PointerList* this, PointerListElem* elem)
{
if(this->length)
{ // elements exist => replace tail
elem->prev = this->tail;
this->tail->next = elem;
this->tail = elem;
}
else
{ // no elements exist yet
this->head = elem;
this->tail = elem;
elem->prev = NULL;
}
elem->next = NULL;
this->length++;
}
void PointerList_addTail(PointerList* this, void* valuePointer)
{
PointerListElem* elem = (PointerListElem*)os_kmalloc(sizeof(PointerListElem) );
elem->valuePointer = valuePointer;
__PointerList_addTail(this, elem);
}
void PointerList_append(PointerList* this, void* valuePointer)
{
PointerList_addTail(this, valuePointer);
}
static inline void __PointerList_removeHead(PointerList* this, bool freeElem)
{
#ifdef BEEGFS_DEBUG
if(!this->length)
{
BEEGFS_BUG_ON(true, "Attempt to remove head from empty list");
return;
}
#endif
if(this->length == 1)
{ // removing the last element
if (freeElem)
kfree(this->head);
this->head = NULL;
this->tail = NULL;
this->length = 0;
}
else
{ // there are more elements in the list
PointerListElem* newHead = this->head->next;
if (freeElem)
kfree(this->head);
this->head = newHead;
this->head->prev = NULL;
this->length--;
}
}
void PointerList_removeHead(PointerList* this)
{
__PointerList_removeHead(this, true);
}
static inline void __PointerList_removeTail(PointerList* this, bool freeElem)
{
#ifdef BEEGFS_DEBUG
if(!this->length)
{
BEEGFS_BUG_ON(true, "Attempt to remove tail from empty list");
return;
}
#endif
if(this->length == 1)
{ // removing the last element
if (freeElem)
kfree(this->tail);
this->head = NULL;
this->tail = NULL;
this->length = 0;
}
else
{ // there are more elements in the list
PointerListElem* newTail = this->tail->prev;
if (freeElem)
kfree(this->tail);
this->tail = newTail;
this->tail->next = NULL;
this->length--;
}
}
void PointerList_removeTail(PointerList* this)
{
__PointerList_removeTail(this, true);
}
static inline void __PointerList_removeElem(PointerList* this, PointerListElem* elem, bool freeElem)
{
if(elem == this->head)
__PointerList_removeHead(this, freeElem);
else
if(elem == this->tail)
__PointerList_removeTail(this, freeElem);
else
{
// not head and not tail, so this elem is somewhere in the middle
PointerListElem* prev = elem->prev;
PointerListElem* next = elem->next;
prev->next = next;
next->prev = prev;
if (freeElem)
kfree(elem);
this->length--;
}
}
void PointerList_removeElem(PointerList* this, PointerListElem* elem)
{
__PointerList_removeElem(this, elem, true);
}
size_t PointerList_length(const PointerList* this)
{
return this->length;
}
void PointerList_clear(PointerList* this)
{
// free all elems
PointerListElem* elem = this->head;
while(elem)
{
PointerListElem* next = elem->next;
kfree(elem);
elem = next;
}
// reset attributes
this->head = NULL;
this->tail = NULL;
this->length = 0;
}
PointerListElem* PointerList_getTail(PointerList* this)
{
return this->tail;
}
PointerListElem* PointerList_getHead(PointerList* this)
{
return this->head;
}
void PointerList_moveToHead(PointerList* this, PointerListElem *elem)
{
__PointerList_removeElem(this, elem, false);
__PointerList_addHead(this, elem);
}
void PointerList_moveToTail(PointerList* this, PointerListElem *elem)
{
__PointerList_removeElem(this, elem, false);
__PointerList_addTail(this, elem);
}
#endif /*POINTERLIST_H_*/

View File

@@ -0,0 +1,62 @@
#ifndef POINTERLISTITER_H_
#define POINTERLISTITER_H_
#include "PointerList.h"
struct PointerListIter;
typedef struct PointerListIter PointerListIter;
static inline void PointerListIter_init(PointerListIter* this, PointerList* list);
static inline void PointerListIter_next(PointerListIter* this);
static inline void* PointerListIter_value(PointerListIter* this);
static inline bool PointerListIter_end(PointerListIter* this);
static inline PointerListIter PointerListIter_remove(PointerListIter* this);
struct PointerListIter
{
PointerList* list;
PointerListElem* elem;
};
void PointerListIter_init(PointerListIter* this, PointerList* list)
{
this->list = list;
this->elem = list->head;
}
void PointerListIter_next(PointerListIter* this)
{
// note: must not return the value because the current elem could be the end of the list
this->elem = this->elem->next;
}
void* PointerListIter_value(PointerListIter* this)
{
return this->elem->valuePointer;
}
bool PointerListIter_end(PointerListIter* this)
{
return (this->elem == NULL);
}
/**
* note: the current iterator becomes invalid after the call (use the returned iterator)
* @return the new iterator that points to the element just behind the erased one
*/
PointerListIter PointerListIter_remove(PointerListIter* this)
{
PointerListIter newIter = *this;
PointerListElem* elem = this->elem;
PointerListIter_next(&newIter);
PointerList_removeElem(this->list, elem);
return newIter;
}
#endif /*POINTERLISTITER_H_*/

View File

@@ -0,0 +1,77 @@
#ifndef STRCPYLIST_H_
#define STRCPYLIST_H_
#include "StringList.h"
struct StrCpyList;
typedef struct StrCpyList StrCpyList;
static inline void StrCpyList_init(StrCpyList* this);
static inline void StrCpyList_uninit(StrCpyList* this);
static inline void StrCpyList_addHead(StrCpyList* this, const char* valuePointer);
static inline void StrCpyList_append(StrCpyList* this, const char* valuePointer);
static inline size_t StrCpyList_length(StrCpyList* this);
static inline void StrCpyList_clear(StrCpyList* this);
struct StrCpyList
{
struct StringList stringList;
};
void StrCpyList_init(StrCpyList* this)
{
StringList_init( (StringList*)this);
}
void StrCpyList_uninit(StrCpyList* this)
{
struct PointerListElem* elem = ( (PointerList*)this)->head;
while(elem)
{
struct PointerListElem* next = elem->next;
kfree(elem->valuePointer);
elem = next;
}
StringList_uninit( (StringList*)this);
}
void StrCpyList_addHead(StrCpyList* this, const char* valuePointer)
{
size_t valueLen = strlen(valuePointer)+1;
char* valueCopy = (char*)os_kmalloc(valueLen);
memcpy(valueCopy, valuePointer, valueLen);
StringList_addHead( (StringList*)this, valueCopy);
}
void StrCpyList_append(StrCpyList* this, const char* valuePointer)
{
size_t valueLen = strlen(valuePointer)+1;
char* valueCopy = (char*)os_kmalloc(valueLen);
memcpy(valueCopy, valuePointer, valueLen);
StringList_append( (StringList*)this, valueCopy);
}
size_t StrCpyList_length(StrCpyList* this)
{
return StringList_length( (StringList*)this);
}
void StrCpyList_clear(StrCpyList* this)
{
struct PointerListElem* elem = ( (PointerList*)this)->head;
while(elem)
{
struct PointerListElem* next = elem->next;
kfree(elem->valuePointer);
elem = next;
}
StringList_clear( (StringList*)this);
}
#endif /*STRCPYLIST_H_*/

View File

@@ -0,0 +1,43 @@
#ifndef STRCPYLISTITER_H_
#define STRCPYLISTITER_H_
#include "StrCpyList.h"
#include "StringListIter.h"
struct StrCpyListIter;
typedef struct StrCpyListIter StrCpyListIter;
static inline void StrCpyListIter_init(StrCpyListIter* this, StrCpyList* list);
static inline void StrCpyListIter_next(StrCpyListIter* this);
static inline char* StrCpyListIter_value(StrCpyListIter* this);
static inline bool StrCpyListIter_end(StrCpyListIter* this);
struct StrCpyListIter
{
struct StringListIter stringListIter;
};
void StrCpyListIter_init(StrCpyListIter* this, StrCpyList* list)
{
StringListIter_init( (StringListIter*)this, (StringList*)list);
}
void StrCpyListIter_next(StrCpyListIter* this)
{
StringListIter_next( (StringListIter*)this);
}
char* StrCpyListIter_value(StrCpyListIter* this)
{
return (char*)StringListIter_value( (StringListIter*)this);
}
bool StrCpyListIter_end(StrCpyListIter* this)
{
return StringListIter_end( (StringListIter*)this);
}
#endif /*STRCPYLISTITER_H_*/

View File

@@ -0,0 +1,52 @@
#ifndef STRINGLIST_H_
#define STRINGLIST_H_
#include "PointerList.h"
struct StringList;
typedef struct StringList StringList;
static inline void StringList_init(StringList* this);
static inline void StringList_uninit(StringList* this);
static inline void StringList_addHead(StringList* this, char* valuePointer);
static inline void StringList_append(StringList* this, char* valuePointer);
static inline size_t StringList_length(StringList* this);
static inline void StringList_clear(StringList* this);
struct StringList
{
PointerList pointerList;
};
void StringList_init(StringList* this)
{
PointerList_init( (PointerList*)this);
}
void StringList_uninit(StringList* this)
{
PointerList_uninit( (PointerList*)this);
}
void StringList_addHead(StringList* this, char* valuePointer)
{
PointerList_addHead( (PointerList*)this, valuePointer);
}
void StringList_append(StringList* this, char* valuePointer)
{
PointerList_append( (PointerList*)this, valuePointer);
}
size_t StringList_length(StringList* this)
{
return PointerList_length( (PointerList*)this);
}
void StringList_clear(StringList* this)
{
PointerList_clear( (PointerList*)this);
}
#endif /*STRINGLIST_H_*/

View File

@@ -0,0 +1,43 @@
#ifndef STRINGLISTITER_H_
#define STRINGLISTITER_H_
#include "StringList.h"
#include "PointerListIter.h"
struct StringListIter;
typedef struct StringListIter StringListIter;
static inline void StringListIter_init(StringListIter* this, StringList* list);
static inline void StringListIter_next(StringListIter* this);
static inline char* StringListIter_value(StringListIter* this);
static inline bool StringListIter_end(StringListIter* this);
struct StringListIter
{
PointerListIter pointerListIter;
};
void StringListIter_init(StringListIter* this, StringList* list)
{
PointerListIter_init( (PointerListIter*)this, (PointerList*)list);
}
void StringListIter_next(StringListIter* this)
{
PointerListIter_next( (PointerListIter*)this);
}
char* StringListIter_value(StringListIter* this)
{
return (char*)PointerListIter_value( (PointerListIter*)this);
}
bool StringListIter_end(StringListIter* this)
{
return PointerListIter_end( (PointerListIter*)this);
}
#endif /*STRINGLISTITER_H_*/

View File

@@ -0,0 +1,53 @@
#ifndef UINT16LIST_H_
#define UINT16LIST_H_
#include <common/toolkit/list/PointerList.h>
/**
* Derived from PointerList. Internally, we cast uint16_t values directly to pointers here (instead
* of allocating them and assigning the pointer to the allocated mem here).
*/
struct UInt16List;
typedef struct UInt16List UInt16List;
static inline void UInt16List_init(UInt16List* this);
static inline void UInt16List_uninit(UInt16List* this);
static inline void UInt16List_append(UInt16List* this, uint16_t value);
static inline size_t UInt16List_length(UInt16List* this);
static inline void UInt16List_clear(UInt16List* this);
struct UInt16List
{
struct PointerList pointerList;
};
void UInt16List_init(UInt16List* this)
{
PointerList_init( (PointerList*)this);
}
void UInt16List_uninit(UInt16List* this)
{
PointerList_uninit( (PointerList*)this);
}
void UInt16List_append(UInt16List* this, uint16_t value)
{
/* cast value directly to pointer type here to store value directly in the pointer variable
without allocating extra mem */
PointerList_append( (PointerList*)this, (void*)(size_t)value);
}
static inline size_t UInt16List_length(UInt16List* this)
{
return PointerList_length( (PointerList*)this);
}
void UInt16List_clear(UInt16List* this)
{
PointerList_clear( (PointerList*)this);
}
#endif /* UINT16LIST_H_ */

View File

@@ -0,0 +1,43 @@
#ifndef UINT16LISTITER_H_
#define UINT16LISTITER_H_
#include <common/toolkit/list/PointerListIter.h>
#include "UInt16List.h"
struct UInt16ListIter;
typedef struct UInt16ListIter UInt16ListIter;
static inline void UInt16ListIter_init(UInt16ListIter* this, UInt16List* list);
static inline void UInt16ListIter_next(UInt16ListIter* this);
static inline uint16_t UInt16ListIter_value(UInt16ListIter* this);
static inline bool UInt16ListIter_end(UInt16ListIter* this);
struct UInt16ListIter
{
struct PointerListIter pointerListIter;
};
void UInt16ListIter_init(UInt16ListIter* this, UInt16List* list)
{
PointerListIter_init( (PointerListIter*)this, (PointerList*)list);
}
void UInt16ListIter_next(UInt16ListIter* this)
{
PointerListIter_next( (PointerListIter*)this);
}
uint16_t UInt16ListIter_value(UInt16ListIter* this)
{
return (uint16_t)(size_t)PointerListIter_value( (PointerListIter*)this);
}
bool UInt16ListIter_end(UInt16ListIter* this)
{
return PointerListIter_end( (PointerListIter*)this);
}
#endif /* UINT16LISTITER_H_ */

View File

@@ -0,0 +1,53 @@
#ifndef UINT8LIST_H_
#define UINT8LIST_H_
#include <common/toolkit/list/PointerList.h>
/**
* Derived from PointerList. Internally, we cast uint8_t values directly to pointers here (instead
* of allocating them and assigning the pointer to the allocated mem here).
*/
struct UInt8List;
typedef struct UInt8List UInt8List;
static inline void UInt8List_init(UInt8List* this);
static inline void UInt8List_uninit(UInt8List* this);
static inline void UInt8List_append(UInt8List* this, uint8_t value);
static inline size_t UInt8List_length(UInt8List* this);
static inline void UInt8List_clear(UInt8List* this);
struct UInt8List
{
struct PointerList pointerList;
};
void UInt8List_init(UInt8List* this)
{
PointerList_init( (PointerList*)this);
}
void UInt8List_uninit(UInt8List* this)
{
PointerList_uninit( (PointerList*)this);
}
void UInt8List_append(UInt8List* this, uint8_t value)
{
/* cast value directly to pointer type here to store value directly in the pointer variable
without allocating extra mem */
PointerList_append( (PointerList*)this, (void*)(size_t)value);
}
static inline size_t UInt8List_length(UInt8List* this)
{
return PointerList_length( (PointerList*)this);
}
void UInt8List_clear(UInt8List* this)
{
PointerList_clear( (PointerList*)this);
}
#endif /* UINT8LIST_H_ */

View File

@@ -0,0 +1,43 @@
#ifndef UINT8LISTITER_H_
#define UINT8LISTITER_H_
#include <common/toolkit/list/PointerListIter.h>
#include "UInt8List.h"
struct UInt8ListIter;
typedef struct UInt8ListIter UInt8ListIter;
static inline void UInt8ListIter_init(UInt8ListIter* this, UInt8List* list);
static inline void UInt8ListIter_next(UInt8ListIter* this);
static inline uint8_t UInt8ListIter_value(UInt8ListIter* this);
static inline bool UInt8ListIter_end(UInt8ListIter* this);
struct UInt8ListIter
{
struct PointerListIter pointerListIter;
};
void UInt8ListIter_init(UInt8ListIter* this, UInt8List* list)
{
PointerListIter_init( (PointerListIter*)this, (PointerList*)list);
}
void UInt8ListIter_next(UInt8ListIter* this)
{
PointerListIter_next( (PointerListIter*)this);
}
uint8_t UInt8ListIter_value(UInt8ListIter* this)
{
return (uint8_t)(size_t)PointerListIter_value( (PointerListIter*)this);
}
bool UInt8ListIter_end(UInt8ListIter* this)
{
return PointerListIter_end( (PointerListIter*)this);
}
#endif /* UINT8LISTITER_H_ */

View File

@@ -0,0 +1,24 @@
#include <common/toolkit/tree/IntMap.h>
#include <common/toolkit/tree/IntMapIter.h>
IntMapIter IntMap_find(IntMap* this, const int searchKey)
{
RBTreeElem* treeElem = _PointerRBTree_findElem(
(RBTree*)this, (const void*)(const size_t)searchKey);
IntMapIter iter;
IntMapIter_init(&iter, this, treeElem);
return iter;
}
IntMapIter IntMap_begin(IntMap* this)
{
struct rb_node* node = rb_first(&this->rbTree.treeroot);
RBTreeElem* treeElem = node ? container_of(node, RBTreeElem, treenode) : NULL;
IntMapIter iter;
IntMapIter_init(&iter, this, treeElem);
return iter;
}

View File

@@ -0,0 +1,88 @@
#ifndef INTMAP_H_
#define INTMAP_H_
#include "PointerRBTree.h"
#include "PointerRBTreeIter.h"
/**
* We assign the integer keys directly to the key pointers (i.e. no extra allocation involved,
* but a lot of casting to convince gcc that we know what we're doing).
* Values are just arbitrary pointers.
*/
struct IntMapElem;
typedef struct IntMapElem IntMapElem;
struct IntMap;
typedef struct IntMap IntMap;
struct IntMapIter; // forward declaration of the iterator
static inline void IntMap_init(IntMap* this);
static inline void IntMap_uninit(IntMap* this);
static inline bool IntMap_insert(IntMap* this, int newKey, char* newValue);
static inline bool IntMap_erase(IntMap* this, const int eraseKey);
static inline size_t IntMap_length(IntMap* this);
static inline void IntMap_clear(IntMap* this);
extern struct IntMapIter IntMap_find(IntMap* this, const int searchKey);
extern struct IntMapIter IntMap_begin(IntMap* this);
struct IntMapElem
{
RBTreeElem rbTreeElem;
};
struct IntMap
{
RBTree rbTree;
};
void IntMap_init(IntMap* this)
{
PointerRBTree_init( (RBTree*)this, PointerRBTree_keyCompare);
}
void IntMap_uninit(IntMap* this)
{
// (nothing alloc'ed by this sub map type => nothing special here to be free'd)
PointerRBTree_uninit( (RBTree*)this);
}
/**
* @param newValue just assigned, not copied.
* @return true if element was inserted, false if key already existed (in which case
* nothing is changed)
*/
bool IntMap_insert(IntMap* this, int newKey, char* newValue)
{
return PointerRBTree_insert( (RBTree*)this, (void*)(size_t)newKey, newValue);
}
/**
* @return false if no element with the given key existed
*/
bool IntMap_erase(IntMap* this, const int eraseKey)
{
return PointerRBTree_erase( (RBTree*)this, (const void*)(const size_t)eraseKey);
}
size_t IntMap_length(IntMap* this)
{
return PointerRBTree_length( (RBTree*)this);
}
void IntMap_clear(IntMap* this)
{
PointerRBTree_clear(&this->rbTree);
}
#endif /* INTMAP_H_ */

View File

@@ -0,0 +1,45 @@
#ifndef INTMAPITER_H_
#define INTMAPITER_H_
#include "IntMap.h"
struct IntMapIter;
typedef struct IntMapIter IntMapIter;
static inline void IntMapIter_init(IntMapIter* this, IntMap* map, RBTreeElem* treeElem);
static inline char* IntMapIter_next(IntMapIter* this);
static inline int IntMapIter_key(IntMapIter* this);
static inline char* IntMapIter_value(IntMapIter* this);
static inline bool IntMapIter_end(IntMapIter* this);
struct IntMapIter
{
RBTreeIter rbTreeIter;
};
void IntMapIter_init(IntMapIter* this, IntMap* map, RBTreeElem* treeElem)
{
PointerRBTreeIter_init( (RBTreeIter*)this, (RBTree*)map, (RBTreeElem*)treeElem);
}
char* IntMapIter_next(IntMapIter* this)
{
return (char*)PointerRBTreeIter_next( (RBTreeIter*)this);
}
int IntMapIter_key(IntMapIter* this)
{
return (int)(size_t)PointerRBTreeIter_key( (RBTreeIter*)this);
}
char* IntMapIter_value(IntMapIter* this)
{
return (char*)PointerRBTreeIter_value( (RBTreeIter*)this);
}
bool IntMapIter_end(IntMapIter* this)
{
return PointerRBTreeIter_end( (RBTreeIter*)this);
}
#endif /* INTMAPITER_H_ */

View File

@@ -0,0 +1,24 @@
#include <common/toolkit/tree/PointerRBTree.h>
#include <common/toolkit/tree/PointerRBTreeIter.h>
RBTreeIter PointerRBTree_find(RBTree* this, const void* searchKey)
{
RBTreeElem* treeElem = _PointerRBTree_findElem(this, searchKey);
RBTreeIter iter;
PointerRBTreeIter_init(&iter, this, treeElem);
return iter;
}
RBTreeIter PointerRBTree_begin(RBTree* this)
{
struct rb_node* node = rb_first(&this->treeroot);
RBTreeElem* treeElem = node ? container_of(node, RBTreeElem, treenode) : NULL;
RBTreeIter iter;
PointerRBTreeIter_init(&iter, this, treeElem);
return iter;
}

View File

@@ -0,0 +1,201 @@
#ifndef POINTERRBTREE_H_
#define POINTERRBTREE_H_
#include <common/Common.h>
#include <linux/rbtree.h>
struct RBTreeElem;
typedef struct RBTreeElem RBTreeElem;
struct RBTree;
typedef struct RBTree RBTree;
/**
* @return: <0 if key1<key2, 0 for equal keys, >0 otherwise
*/
typedef int (*TreeElemsComparator)(const void* key1, const void* key2);
struct RBTreeIter; // forward declaration of the iterator
static inline void PointerRBTree_init(RBTree* this, TreeElemsComparator compareTreeElems);
static inline void PointerRBTree_uninit(RBTree* this);
static inline RBTreeElem* _PointerRBTree_findElem(RBTree* this, const void* searchKey);
static inline bool PointerRBTree_insert(RBTree* this, void* newKey, void* newValue);
static bool PointerRBTree_erase(RBTree* this, const void* eraseKey);
static inline size_t PointerRBTree_length(RBTree* this);
static inline void PointerRBTree_clear(RBTree* this);
static inline int PointerRBTree_keyCompare(const void* a, const void* b);
extern struct RBTreeIter PointerRBTree_find(RBTree* this, const void* searchKey);
extern struct RBTreeIter PointerRBTree_begin(RBTree* this);
struct RBTreeElem
{
struct rb_node treenode;
void* key;
void* value;
};
struct RBTree
{
struct rb_root treeroot;
size_t length;
TreeElemsComparator compareTreeElems;
};
void PointerRBTree_init(RBTree* this, TreeElemsComparator compareTreeElems)
{
this->treeroot.rb_node = NULL;
this->length = 0;
this->compareTreeElems = compareTreeElems;
}
void PointerRBTree_uninit(RBTree* this)
{
PointerRBTree_clear(this);
}
/**
* @return NULL if the element was not found
*/
RBTreeElem* _PointerRBTree_findElem(RBTree* this, const void* searchKey)
{
int compRes;
struct rb_node* node = this->treeroot.rb_node;
while(node)
{
RBTreeElem* treeElem = container_of(node, RBTreeElem, treenode);
compRes = this->compareTreeElems(searchKey, treeElem->key);
if(compRes < 0)
node = node->rb_left;
else
if(compRes > 0)
node = node->rb_right;
else
{ // element found => return it
return treeElem;
}
}
// element not found
return NULL;
}
/**
* @return true if element was inserted, false if it already existed (in which case
* nothing is changed) or if out of mem.
*/
bool PointerRBTree_insert(RBTree* this, void* newKey, void* newValue)
{
RBTreeElem* newElem;
// the parent's (left or right) link to which the child will be connected
struct rb_node** link = &this->treeroot.rb_node;
// the parent of the new node
struct rb_node* parent = NULL;
while(*link)
{
int compRes;
RBTreeElem* treeElem;
parent = *link;
treeElem = container_of(parent, RBTreeElem, treenode);
compRes = this->compareTreeElems(newKey, treeElem->key);
if(compRes < 0)
link = &(*link)->rb_left;
else
if(compRes > 0)
link = &(*link)->rb_right;
else
{ // target already exists => do nothing (according to the behavior of c++ map::insert)
//rbReplaceNode(parent, newElem, this);
return false;
}
}
// create new element
newElem = os_kmalloc(sizeof(*newElem) );
newElem->key = newKey;
newElem->value = newValue;
// link the new element
rb_link_node(&newElem->treenode, parent, link);
rb_insert_color(&newElem->treenode, &this->treeroot);
this->length++;
return true;
}
/**
* @return false if no element with the given key existed
*/
bool PointerRBTree_erase(RBTree* this, const void* eraseKey)
{
RBTreeElem* treeElem;
treeElem = _PointerRBTree_findElem(this, eraseKey);
if(!treeElem)
{ // element not found
return false;
}
// unlink the element
rb_erase(&treeElem->treenode, &this->treeroot);
kfree(treeElem);
this->length--;
return true;
}
size_t PointerRBTree_length(RBTree* this)
{
return this->length;
}
void PointerRBTree_clear(RBTree* this)
{
while(this->length)
{
RBTreeElem* root = container_of(this->treeroot.rb_node, RBTreeElem, treenode);
PointerRBTree_erase(this, root->key);
}
}
int PointerRBTree_keyCompare(const void* a, const void* b)
{
if (a < b)
return -1;
if (a == b)
return 0;
return 1;
}
#endif /*POINTERRBTREE_H_*/

View File

@@ -0,0 +1,57 @@
#ifndef POINTERRBTREEITER_H_
#define POINTERRBTREEITER_H_
#include "PointerRBTree.h"
struct RBTreeIter;
typedef struct RBTreeIter RBTreeIter;
static inline void PointerRBTreeIter_init(
RBTreeIter* this, RBTree* tree, RBTreeElem* treeElem);
static inline void* PointerRBTreeIter_next(RBTreeIter* this);
static inline void* PointerRBTreeIter_key(RBTreeIter* this);
static inline void* PointerRBTreeIter_value(RBTreeIter* this);
static inline bool PointerRBTreeIter_end(RBTreeIter* this);
struct RBTreeIter
{
RBTree* tree;
RBTreeElem* treeElem;
};
void PointerRBTreeIter_init(RBTreeIter* this, RBTree* tree, RBTreeElem* treeElem)
{
this->tree = tree;
this->treeElem = treeElem;
}
void* PointerRBTreeIter_next(RBTreeIter* this)
{
struct rb_node* next = rb_next(&this->treeElem->treenode);
this->treeElem = next ? container_of(next, RBTreeElem, treenode) : NULL;
return this->treeElem;
}
void* PointerRBTreeIter_key(RBTreeIter* this)
{
return this->treeElem->key;
}
void* PointerRBTreeIter_value(RBTreeIter* this)
{
return this->treeElem->value;
}
/**
* Return true if the end of the iterator was reached
*/
bool PointerRBTreeIter_end(RBTreeIter* this)
{
return (this->treeElem == NULL);
}
#endif /*POINTERRBTREEITER_H_*/

View File

@@ -0,0 +1,30 @@
#include "StrCpyMap.h"
#include "StrCpyMapIter.h"
StrCpyMapIter StrCpyMap_find(StrCpyMap* this, const char* searchKey)
{
RBTreeElem* treeElem = _PointerRBTree_findElem( (RBTree*)this, searchKey);
StrCpyMapIter iter;
StrCpyMapIter_init(&iter, this, treeElem);
return iter;
}
StrCpyMapIter StrCpyMap_begin(StrCpyMap* this)
{
struct rb_node* node = rb_first(&this->rbTree.treeroot);
RBTreeElem* treeElem = node ? container_of(node, RBTreeElem, treenode) : NULL;
StrCpyMapIter iter;
StrCpyMapIter_init(&iter, this, treeElem);
return iter;
}
int compareStrCpyMapElems(const void* key1, const void* key2)
{
return strcmp(key1, key2);
}

View File

@@ -0,0 +1,131 @@
#ifndef STRCPYMAP_H_
#define STRCPYMAP_H_
#include <common/toolkit/tree/PointerRBTree.h>
#include <common/toolkit/tree/PointerRBTreeIter.h>
struct StrCpyMapElem;
typedef struct StrCpyMapElem StrCpyMapElem;
struct StrCpyMap;
typedef struct StrCpyMap StrCpyMap;
struct StrCpyMapIter; // forward declaration of the iterator
static inline void StrCpyMap_init(StrCpyMap* this);
static inline void StrCpyMap_uninit(StrCpyMap* this);
static inline bool StrCpyMap_insert(StrCpyMap* this, const char* newKey,
const char* newValue);
static inline bool StrCpyMap_erase(StrCpyMap* this, const char* eraseKey);
static inline size_t StrCpyMap_length(StrCpyMap* this);
static inline void StrCpyMap_clear(StrCpyMap* this);
extern struct StrCpyMapIter StrCpyMap_find(StrCpyMap* this, const char* searchKey);
extern struct StrCpyMapIter StrCpyMap_begin(StrCpyMap* this);
extern int compareStrCpyMapElems(const void* key1, const void* key2);
struct StrCpyMapElem
{
RBTreeElem rbTreeElem;
};
struct StrCpyMap
{
RBTree rbTree;
};
void StrCpyMap_init(StrCpyMap* this)
{
PointerRBTree_init( (RBTree*)this, compareStrCpyMapElems);
}
void StrCpyMap_uninit(StrCpyMap* this)
{
StrCpyMap_clear(this);
PointerRBTree_uninit( (RBTree*)this);
}
/**
* @return true if element was inserted, false if key already existed (in which case
* nothing is changed)
*/
bool StrCpyMap_insert(StrCpyMap* this, const char* newKey, const char* newValue)
{
size_t keyLen;
char* keyCopy;
size_t valueLen;
char* valueCopy;
bool insRes;
// copy key
keyLen = strlen(newKey)+1;
keyCopy = (char*)os_kmalloc(keyLen);
memcpy(keyCopy, newKey, keyLen);
// copy value
valueLen = strlen(newValue)+1;
valueCopy = (char*)os_kmalloc(valueLen);
memcpy(valueCopy, newValue, valueLen);
insRes = PointerRBTree_insert( (RBTree*)this, keyCopy, valueCopy);
if(!insRes)
{
// not inserted because the key already existed => free up the copies
kfree(keyCopy);
kfree(valueCopy);
}
return insRes;
}
/**
* @return false if no element with the given key existed
*/
bool StrCpyMap_erase(StrCpyMap* this, const char* eraseKey)
{
bool eraseRes;
void* elemKey;
void* elemValue;
RBTreeElem* treeElem = _PointerRBTree_findElem( (RBTree*)this, eraseKey);
if(!treeElem)
{ // element not found
return false;
}
elemKey = treeElem->key;
elemValue = treeElem->value;
eraseRes = PointerRBTree_erase( (RBTree*)this, eraseKey);
if(eraseRes)
{ // treeElem has been erased
kfree(elemKey);
kfree(elemValue);
}
return eraseRes;
}
size_t StrCpyMap_length(StrCpyMap* this)
{
return PointerRBTree_length( (RBTree*)this);
}
void StrCpyMap_clear(StrCpyMap* this)
{
while(this->rbTree.length)
{
RBTreeElem* root = container_of(this->rbTree.treeroot.rb_node, RBTreeElem, treenode);
StrCpyMap_erase(this, root->key);
}
}
#endif /*STRCPYMAP_H_*/

View File

@@ -0,0 +1,45 @@
#ifndef STRCPYMAPITER_H_
#define STRCPYMAPITER_H_
#include "StrCpyMap.h"
struct StrCpyMapIter;
typedef struct StrCpyMapIter StrCpyMapIter;
static inline void StrCpyMapIter_init(StrCpyMapIter* this, StrCpyMap* map, RBTreeElem* treeElem);
static inline char* StrCpyMapIter_next(StrCpyMapIter* this);
static inline char* StrCpyMapIter_key(StrCpyMapIter* this);
static inline char* StrCpyMapIter_value(StrCpyMapIter* this);
static inline bool StrCpyMapIter_end(StrCpyMapIter* this);
struct StrCpyMapIter
{
RBTreeIter rbTreeIter;
};
void StrCpyMapIter_init(StrCpyMapIter* this, StrCpyMap* map, RBTreeElem* treeElem)
{
PointerRBTreeIter_init( (RBTreeIter*)this, (RBTree*)map, (RBTreeElem*)treeElem);
}
char* StrCpyMapIter_next(StrCpyMapIter* this)
{
return (char*)PointerRBTreeIter_next( (RBTreeIter*)this);
}
char* StrCpyMapIter_key(StrCpyMapIter* this)
{
return (char*)PointerRBTreeIter_key( (RBTreeIter*)this);
}
char* StrCpyMapIter_value(StrCpyMapIter* this)
{
return (char*)PointerRBTreeIter_value( (RBTreeIter*)this);
}
bool StrCpyMapIter_end(StrCpyMapIter* this)
{
return PointerRBTreeIter_end( (RBTreeIter*)this);
}
#endif /*STRCPYMAPITER_H_*/

View File

@@ -0,0 +1,89 @@
#ifndef INT64CPYVEC_H_
#define INT64CPYVEC_H_
#include <common/toolkit/list/Int64CpyList.h>
/**
* Note: Derived from the corresponding list. Use the list iterator for read-only access
*/
struct Int64CpyVec;
typedef struct Int64CpyVec Int64CpyVec;
static inline void Int64CpyVec_init(Int64CpyVec* this);
static inline void Int64CpyVec_uninit(Int64CpyVec* this);
static inline void Int64CpyVec_append(Int64CpyVec* this, int64_t value);
static inline size_t Int64CpyVec_length(Int64CpyVec* this);
static inline void Int64CpyVec_clear(Int64CpyVec* this);
// getters & setters
static inline int64_t Int64CpyVec_at(Int64CpyVec* this, size_t index);
struct Int64CpyVec
{
Int64CpyList Int64CpyList;
int64_t** vecArray;
size_t vecArrayLen;
};
void Int64CpyVec_init(Int64CpyVec* this)
{
Int64CpyList_init( (Int64CpyList*)this);
this->vecArrayLen = 4;
this->vecArray = (int64_t**)os_kmalloc(
this->vecArrayLen * sizeof(int64_t*) );
}
void Int64CpyVec_uninit(Int64CpyVec* this)
{
kfree(this->vecArray);
Int64CpyList_uninit( (Int64CpyList*)this);
}
void Int64CpyVec_append(Int64CpyVec* this, int64_t value)
{
PointerListElem* lastElem;
int64_t* lastElemValuePointer;
Int64CpyList_append( (Int64CpyList*)this, value);
// check if we have enough buffer space for new elem
if(Int64CpyList_length( (Int64CpyList*)this) > this->vecArrayLen)
{ // double vector array size (create new, copy, exchange, delete old)
int64_t** newVecArray =
(int64_t**)os_kmalloc(this->vecArrayLen*sizeof(int64_t*)*2);
memcpy(newVecArray, this->vecArray, this->vecArrayLen*sizeof(int64_t*) );
kfree(this->vecArray);
this->vecArrayLen = this->vecArrayLen * 2;
this->vecArray = newVecArray;
}
// get last elem and add the valuePointer to the array
lastElem = PointerList_getTail( (PointerList*)this);
lastElemValuePointer = (int64_t*)lastElem->valuePointer;
(this->vecArray)[Int64CpyList_length( (Int64CpyList*)this)-1] = lastElemValuePointer;
}
size_t Int64CpyVec_length(Int64CpyVec* this)
{
return Int64CpyList_length( (Int64CpyList*)this);
}
int64_t Int64CpyVec_at(Int64CpyVec* this, size_t index)
{
BEEGFS_BUG_ON_DEBUG(index >= Int64CpyVec_length(this), "Index out of bounds");
return *(this->vecArray[index]);
}
void Int64CpyVec_clear(Int64CpyVec* this)
{
Int64CpyList_clear( (Int64CpyList*)this);
}
#endif /*INT64CPYVEC_H_*/

View File

@@ -0,0 +1,89 @@
#ifndef STRCPYVEC_H_
#define STRCPYVEC_H_
#include <common/toolkit/list/StrCpyList.h>
/**
* Note: Derived from the corresponding list. Use the list iterator for read-only access
*/
struct StrCpyVec;
typedef struct StrCpyVec StrCpyVec;
static inline void StrCpyVec_init(StrCpyVec* this);
static inline void StrCpyVec_uninit(StrCpyVec* this);
static inline void StrCpyVec_append(StrCpyVec* this, const char* valuePointer);
static inline size_t StrCpyVec_length(StrCpyVec* this);
static inline void StrCpyVec_clear(StrCpyVec* this);
// getters & setters
static inline char* StrCpyVec_at(StrCpyVec* this, size_t index);
struct StrCpyVec
{
StrCpyList strCpyList;
char** vecArray;
size_t vecArrayLen;
};
void StrCpyVec_init(StrCpyVec* this)
{
StrCpyList_init( (StrCpyList*)this);
this->vecArrayLen = 4;
this->vecArray = (char**)os_kmalloc(
this->vecArrayLen * sizeof(char*) );
}
void StrCpyVec_uninit(StrCpyVec* this)
{
kfree(this->vecArray);
StrCpyList_uninit( (StrCpyList*)this);
}
void StrCpyVec_append(StrCpyVec* this, const char* valuePointer)
{
PointerListElem* lastElem;
char* lastElemValuePointer;
StrCpyList_append( (StrCpyList*)this, valuePointer);
// check if we have enough buffer space for new elem
if(StrCpyList_length( (StrCpyList*)this) > this->vecArrayLen)
{ // double vector array size (create new, copy, exchange, delete old)
char** newVecArray = (char**)os_kmalloc(this->vecArrayLen*sizeof(char*)*2);
memcpy(newVecArray, this->vecArray, this->vecArrayLen*sizeof(char*) );
kfree(this->vecArray);
this->vecArrayLen = this->vecArrayLen * 2;
this->vecArray = newVecArray;
}
// get last elem and add the valuePointer to the array
lastElem = PointerList_getTail( (PointerList*)this);
lastElemValuePointer = (char*)lastElem->valuePointer;
(this->vecArray)[StrCpyList_length( (StrCpyList*)this)-1] = lastElemValuePointer;
}
size_t StrCpyVec_length(StrCpyVec* this)
{
return StrCpyList_length( (StrCpyList*)this);
}
char* StrCpyVec_at(StrCpyVec* this, size_t index)
{
BEEGFS_BUG_ON_DEBUG(index >= StrCpyVec_length(this), "Index out of bounds");
return (this->vecArray)[index];
}
void StrCpyVec_clear(StrCpyVec* this)
{
StrCpyList_clear( (StrCpyList*)this);
}
#endif /*STRCPYVEC_H_*/

View File

@@ -0,0 +1,90 @@
#ifndef UINT16VEC_H_
#define UINT16VEC_H_
#include <common/toolkit/list/UInt16List.h>
struct UInt16Vec;
typedef struct UInt16Vec UInt16Vec;
static inline void UInt16Vec_init(UInt16Vec* this);
static inline void UInt16Vec_uninit(UInt16Vec* this);
static inline void UInt16Vec_append(UInt16Vec* this, uint16_t value);
static inline size_t UInt16Vec_length(UInt16Vec* this);
static inline void UInt16Vec_clear(UInt16Vec* this);
// getters & setters
static inline uint16_t UInt16Vec_at(UInt16Vec* this, size_t index);
/**
* Note: Derived from the corresponding list. Use the list iterator for read-only access
*/
struct UInt16Vec
{
UInt16List UInt16List;
uint16_t* vecArray;
size_t vecArrayLen;
};
void UInt16Vec_init(UInt16Vec* this)
{
UInt16List_init( (UInt16List*)this);
this->vecArrayLen = 4;
this->vecArray = (uint16_t*)os_kmalloc(this->vecArrayLen * sizeof(uint16_t) );
}
void UInt16Vec_uninit(UInt16Vec* this)
{
kfree(this->vecArray);
UInt16List_uninit( (UInt16List*)this);
}
void UInt16Vec_append(UInt16Vec* this, uint16_t value)
{
size_t newListLen;
UInt16List_append( (UInt16List*)this, value);
newListLen = UInt16List_length( (UInt16List*)this);
// check if we have enough buffer space for new elem
if(newListLen > this->vecArrayLen)
{ // double vector array size: alloc new, copy values, delete old, switch to new
uint16_t* newVecArray = (uint16_t*)os_kmalloc(this->vecArrayLen * sizeof(uint16_t) * 2);
memcpy(newVecArray, this->vecArray, this->vecArrayLen * sizeof(uint16_t) );
kfree(this->vecArray);
this->vecArrayLen = this->vecArrayLen * 2;
this->vecArray = newVecArray;
}
// add value to last array elem (determine last used index based on list length)
(this->vecArray)[newListLen-1] = value;
}
size_t UInt16Vec_length(UInt16Vec* this)
{
return UInt16List_length( (UInt16List*)this);
}
uint16_t UInt16Vec_at(UInt16Vec* this, size_t index)
{
BEEGFS_BUG_ON_DEBUG(index >= UInt16Vec_length(this), "Index out of bounds");
return this->vecArray[index];
}
void UInt16Vec_clear(UInt16Vec* this)
{
UInt16List_clear( (UInt16List*)this);
}
#endif /* UINT16VEC_H_ */

View File

@@ -0,0 +1,92 @@
#ifndef UINT8VEC_H_
#define UINT8VEC_H_
#include <common/toolkit/list/UInt8List.h>
struct UInt8Vec;
typedef struct UInt8Vec UInt8Vec;
static inline void UInt8Vec_init(UInt8Vec* this);
static inline void UInt8Vec_uninit(UInt8Vec* this);
static inline void UInt8Vec_append(UInt8Vec* this, uint8_t value);
static inline size_t UInt8Vec_length(UInt8Vec* this);
static inline void UInt8Vec_clear(UInt8Vec* this);
// getters & setters
static inline uint8_t UInt8Vec_at(UInt8Vec* this, size_t index);
/**
* Note: Derived from the corresponding list. Use the list iterator for read-only access
*/
struct UInt8Vec
{
UInt8List UInt8List;
uint8_t* vecArray;
size_t vecArrayLen;
};
void UInt8Vec_init(UInt8Vec* this)
{
UInt8List_init( (UInt8List*)this);
this->vecArrayLen = 4;
this->vecArray = (uint8_t*)os_kmalloc(this->vecArrayLen * sizeof(uint8_t) );
}
void UInt8Vec_uninit(UInt8Vec* this)
{
kfree(this->vecArray);
UInt8List_uninit( (UInt8List*)this);
}
void UInt8Vec_append(UInt8Vec* this, uint8_t value)
{
size_t newListLen;
UInt8List_append( (UInt8List*)this, value);
newListLen = UInt8List_length( (UInt8List*)this);
// check if we have enough buffer space for new elem
if(newListLen > this->vecArrayLen)
{ // double vector array size: alloc new, copy values, delete old, switch to new
uint8_t* newVecArray = (uint8_t*)os_kmalloc(this->vecArrayLen * sizeof(uint8_t) * 2);
memcpy(newVecArray, this->vecArray, this->vecArrayLen * sizeof(uint8_t) );
kfree(this->vecArray);
this->vecArrayLen = this->vecArrayLen * 2;
this->vecArray = newVecArray;
}
// add value to last array elem (determine last used index based on list length)
(this->vecArray)[newListLen-1] = value;
}
size_t UInt8Vec_length(UInt8Vec* this)
{
return UInt8List_length( (UInt8List*)this);
}
uint8_t UInt8Vec_at(UInt8Vec* this, size_t index)
{
BEEGFS_BUG_ON_DEBUG(index >= UInt8Vec_length(this), "Index out of bounds");
return this->vecArray[index];
}
void UInt8Vec_clear(UInt8Vec* this)
{
UInt8List_clear( (UInt8List*)this);
}
#endif /* UINT8VEC_H_ */