136af84cdSRashmica Gupta // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) 236af84cdSRashmica Gupta #define _GNU_SOURCE 3a918a628SAndrew Jeffery #include "libpldm/instance-id.h" 436af84cdSRashmica Gupta #include "libpldm/pldm.h" 536af84cdSRashmica Gupta #include <errno.h> 636af84cdSRashmica Gupta #include <fcntl.h> 736af84cdSRashmica Gupta #include <stdlib.h> 8*a6f0cf3eSAndrew Jeffery #include <sys/stat.h> 936af84cdSRashmica Gupta #include <unistd.h> 1036af84cdSRashmica Gupta 110aea707bSAndrew Jeffery #define BIT(i) (1UL << (i)) 120aea707bSAndrew Jeffery 1336af84cdSRashmica Gupta #define PLDM_TID_MAX 256 1436af84cdSRashmica Gupta #define PLDM_INST_ID_MAX 32 1536af84cdSRashmica Gupta 160aea707bSAndrew Jeffery /* We need to track our allocations explicitly due to OFD lock merging/splitting 170aea707bSAndrew Jeffery */ 180aea707bSAndrew Jeffery struct pldm_tid_state { 190aea707bSAndrew Jeffery pldm_instance_id_t prev; 200aea707bSAndrew Jeffery uint32_t allocations; 210aea707bSAndrew Jeffery }; 220aea707bSAndrew Jeffery 2336af84cdSRashmica Gupta struct pldm_instance_db { 240aea707bSAndrew Jeffery struct pldm_tid_state state[PLDM_TID_MAX]; 2536af84cdSRashmica Gupta int lock_db_fd; 2636af84cdSRashmica Gupta }; 2736af84cdSRashmica Gupta 2836af84cdSRashmica Gupta static inline int iid_next(pldm_instance_id_t cur) 2936af84cdSRashmica Gupta { 3036af84cdSRashmica Gupta return (cur + 1) % PLDM_INST_ID_MAX; 3136af84cdSRashmica Gupta } 3236af84cdSRashmica Gupta 3336af84cdSRashmica Gupta int pldm_instance_db_init(struct pldm_instance_db **ctx, const char *dbpath) 3436af84cdSRashmica Gupta { 3536af84cdSRashmica Gupta struct pldm_instance_db *l_ctx; 36*a6f0cf3eSAndrew Jeffery struct stat statbuf; 37*a6f0cf3eSAndrew Jeffery int rc; 3836af84cdSRashmica Gupta 3936af84cdSRashmica Gupta /* Make sure the provided pointer was initialised to NULL. In the future 4036af84cdSRashmica Gupta * if we stabilise the ABI and expose the struct definition the caller 4136af84cdSRashmica Gupta * can potentially pass a valid pointer to a struct they've allocated 4236af84cdSRashmica Gupta */ 4336af84cdSRashmica Gupta if (!ctx || *ctx) { 4436af84cdSRashmica Gupta return -EINVAL; 4536af84cdSRashmica Gupta } 4636af84cdSRashmica Gupta 47*a6f0cf3eSAndrew Jeffery /* Ensure the underlying file is sized for properly managing allocations 48*a6f0cf3eSAndrew Jeffery */ 49*a6f0cf3eSAndrew Jeffery rc = stat(dbpath, &statbuf); 50*a6f0cf3eSAndrew Jeffery if (rc < 0) { 51*a6f0cf3eSAndrew Jeffery return -EINVAL; 52*a6f0cf3eSAndrew Jeffery } 53*a6f0cf3eSAndrew Jeffery 54*a6f0cf3eSAndrew Jeffery if (statbuf.st_size < 55*a6f0cf3eSAndrew Jeffery ((off_t)(PLDM_TID_MAX) * (off_t)(PLDM_INST_ID_MAX))) { 56*a6f0cf3eSAndrew Jeffery return -EINVAL; 57*a6f0cf3eSAndrew Jeffery } 58*a6f0cf3eSAndrew Jeffery 5936af84cdSRashmica Gupta l_ctx = calloc(1, sizeof(struct pldm_instance_db)); 6036af84cdSRashmica Gupta if (!l_ctx) { 6136af84cdSRashmica Gupta return -ENOMEM; 6236af84cdSRashmica Gupta } 6336af84cdSRashmica Gupta 6436af84cdSRashmica Gupta /* Initialise previous ID values so the next one is zero */ 6536af84cdSRashmica Gupta for (int i = 0; i < PLDM_TID_MAX; i++) { 660aea707bSAndrew Jeffery l_ctx->state[i].prev = 31; 6736af84cdSRashmica Gupta } 6836af84cdSRashmica Gupta 6936af84cdSRashmica Gupta /* Lock database may be read-only, either by permissions or mountpoint 7036af84cdSRashmica Gupta */ 7136af84cdSRashmica Gupta l_ctx->lock_db_fd = open(dbpath, O_RDONLY | O_CLOEXEC); 7236af84cdSRashmica Gupta if (l_ctx->lock_db_fd < 0) { 7336af84cdSRashmica Gupta free(l_ctx); 7436af84cdSRashmica Gupta return -errno; 7536af84cdSRashmica Gupta } 7636af84cdSRashmica Gupta *ctx = l_ctx; 7736af84cdSRashmica Gupta 7836af84cdSRashmica Gupta return 0; 7936af84cdSRashmica Gupta } 8036af84cdSRashmica Gupta 8136af84cdSRashmica Gupta int pldm_instance_db_init_default(struct pldm_instance_db **ctx) 8236af84cdSRashmica Gupta { 8336af84cdSRashmica Gupta return pldm_instance_db_init(ctx, 8436af84cdSRashmica Gupta "/usr/share/libpldm/instance-db/default"); 8536af84cdSRashmica Gupta } 8636af84cdSRashmica Gupta 8736af84cdSRashmica Gupta int pldm_instance_db_destroy(struct pldm_instance_db *ctx) 8836af84cdSRashmica Gupta { 8936af84cdSRashmica Gupta if (!ctx) { 9036af84cdSRashmica Gupta return 0; 9136af84cdSRashmica Gupta } 9236af84cdSRashmica Gupta close(ctx->lock_db_fd); 9336af84cdSRashmica Gupta free(ctx); 9436af84cdSRashmica Gupta return 0; 9536af84cdSRashmica Gupta } 9636af84cdSRashmica Gupta 9736af84cdSRashmica Gupta int pldm_instance_id_alloc(struct pldm_instance_db *ctx, pldm_tid_t tid, 9836af84cdSRashmica Gupta pldm_instance_id_t *iid) 9936af84cdSRashmica Gupta { 10036af84cdSRashmica Gupta static const struct flock cfls = { 10136af84cdSRashmica Gupta .l_type = F_RDLCK, 10236af84cdSRashmica Gupta .l_whence = SEEK_SET, 10336af84cdSRashmica Gupta .l_len = 1, 10436af84cdSRashmica Gupta }; 10536af84cdSRashmica Gupta static const struct flock cflx = { 10636af84cdSRashmica Gupta .l_type = F_WRLCK, 10736af84cdSRashmica Gupta .l_whence = SEEK_SET, 10836af84cdSRashmica Gupta .l_len = 1, 10936af84cdSRashmica Gupta }; 11036af84cdSRashmica Gupta uint8_t l_iid; 11136af84cdSRashmica Gupta 11236af84cdSRashmica Gupta if (!iid) { 11336af84cdSRashmica Gupta return -EINVAL; 11436af84cdSRashmica Gupta } 11536af84cdSRashmica Gupta 1160aea707bSAndrew Jeffery l_iid = ctx->state[tid].prev; 11736af84cdSRashmica Gupta if (l_iid >= PLDM_INST_ID_MAX) { 11836af84cdSRashmica Gupta return -EPROTO; 11936af84cdSRashmica Gupta } 12036af84cdSRashmica Gupta 1210aea707bSAndrew Jeffery while ((l_iid = iid_next(l_iid)) != ctx->state[tid].prev) { 12236af84cdSRashmica Gupta struct flock flop; 12336af84cdSRashmica Gupta off_t loff; 12436af84cdSRashmica Gupta int rc; 12536af84cdSRashmica Gupta 1260aea707bSAndrew Jeffery /* Have we already allocated this instance ID? */ 1270aea707bSAndrew Jeffery if (ctx->state[tid].allocations & BIT(l_iid)) { 1280aea707bSAndrew Jeffery continue; 1290aea707bSAndrew Jeffery } 1300aea707bSAndrew Jeffery 13136af84cdSRashmica Gupta /* Derive the instance ID offset in the lock database */ 13236af84cdSRashmica Gupta loff = tid * PLDM_INST_ID_MAX + l_iid; 13336af84cdSRashmica Gupta 13436af84cdSRashmica Gupta /* Reserving the TID's IID. Done via a shared lock */ 13536af84cdSRashmica Gupta flop = cfls; 13636af84cdSRashmica Gupta flop.l_start = loff; 13736af84cdSRashmica Gupta rc = fcntl(ctx->lock_db_fd, F_OFD_SETLK, &flop); 13836af84cdSRashmica Gupta if (rc < 0) { 13936af84cdSRashmica Gupta if (errno == EAGAIN || errno == EINTR) { 14036af84cdSRashmica Gupta return -EAGAIN; 14136af84cdSRashmica Gupta } 14236af84cdSRashmica Gupta return -EPROTO; 14336af84cdSRashmica Gupta } 14436af84cdSRashmica Gupta 14536af84cdSRashmica Gupta /* 14636af84cdSRashmica Gupta * If we *may* promote the lock to exclusive then this IID is 14736af84cdSRashmica Gupta * only reserved by us. This is now our allocated IID. 14836af84cdSRashmica Gupta * 14936af84cdSRashmica Gupta * If we *may not* promote the lock to exclusive then this IID 15036af84cdSRashmica Gupta * is also reserved on another file descriptor. Move on to the 15136af84cdSRashmica Gupta * next IID index. 15236af84cdSRashmica Gupta * 15336af84cdSRashmica Gupta * Note that we cannot actually *perform* the promotion in 15436af84cdSRashmica Gupta * practice because this is prevented by the lock database being 15536af84cdSRashmica Gupta * opened O_RDONLY. 15636af84cdSRashmica Gupta */ 15736af84cdSRashmica Gupta flop = cflx; 15836af84cdSRashmica Gupta flop.l_start = loff; 15936af84cdSRashmica Gupta rc = fcntl(ctx->lock_db_fd, F_OFD_GETLK, &flop); 16036af84cdSRashmica Gupta if (rc < 0) { 16136af84cdSRashmica Gupta if (errno == EAGAIN || errno == EINTR) { 16236af84cdSRashmica Gupta return -EAGAIN; 16336af84cdSRashmica Gupta } 16436af84cdSRashmica Gupta return -EPROTO; 16536af84cdSRashmica Gupta } 16636af84cdSRashmica Gupta 16736af84cdSRashmica Gupta /* F_UNLCK is the type of the lock if we could successfully 16836af84cdSRashmica Gupta * promote it to F_WRLCK */ 16936af84cdSRashmica Gupta if (flop.l_type == F_UNLCK) { 1700aea707bSAndrew Jeffery ctx->state[tid].prev = l_iid; 1710aea707bSAndrew Jeffery ctx->state[tid].allocations |= BIT(l_iid); 17236af84cdSRashmica Gupta *iid = l_iid; 17336af84cdSRashmica Gupta return 0; 17436af84cdSRashmica Gupta } 17536af84cdSRashmica Gupta if (flop.l_type != F_RDLCK) { 17636af84cdSRashmica Gupta return -EPROTO; 17736af84cdSRashmica Gupta } 17836af84cdSRashmica Gupta } 17936af84cdSRashmica Gupta 18036af84cdSRashmica Gupta /* Failed to allocate an IID after a full loop. Make the caller try 18136af84cdSRashmica Gupta * again */ 18236af84cdSRashmica Gupta return -EAGAIN; 18336af84cdSRashmica Gupta } 18436af84cdSRashmica Gupta 18536af84cdSRashmica Gupta int pldm_instance_id_free(struct pldm_instance_db *ctx, pldm_tid_t tid, 18636af84cdSRashmica Gupta pldm_instance_id_t iid) 18736af84cdSRashmica Gupta { 18836af84cdSRashmica Gupta static const struct flock cflu = { 18936af84cdSRashmica Gupta .l_type = F_UNLCK, 19036af84cdSRashmica Gupta .l_whence = SEEK_SET, 19136af84cdSRashmica Gupta .l_len = 1, 19236af84cdSRashmica Gupta }; 19336af84cdSRashmica Gupta struct flock flop; 19436af84cdSRashmica Gupta int rc; 19536af84cdSRashmica Gupta 1960aea707bSAndrew Jeffery /* Trying to free an instance ID that is not currently allocated */ 1970aea707bSAndrew Jeffery if (!(ctx->state[tid].allocations & BIT(iid))) { 1980aea707bSAndrew Jeffery return -EINVAL; 1990aea707bSAndrew Jeffery } 2000aea707bSAndrew Jeffery 20136af84cdSRashmica Gupta flop = cflu; 20236af84cdSRashmica Gupta flop.l_start = tid * PLDM_INST_ID_MAX + iid; 20336af84cdSRashmica Gupta rc = fcntl(ctx->lock_db_fd, F_OFD_SETLK, &flop); 20436af84cdSRashmica Gupta if (rc < 0) { 20536af84cdSRashmica Gupta if (errno == EAGAIN || errno == EINTR) { 20636af84cdSRashmica Gupta return -EAGAIN; 20736af84cdSRashmica Gupta } 20836af84cdSRashmica Gupta return -EPROTO; 20936af84cdSRashmica Gupta } 21036af84cdSRashmica Gupta 2110aea707bSAndrew Jeffery /* Mark the instance ID as no-longer allocated */ 2120aea707bSAndrew Jeffery ctx->state[tid].allocations &= ~BIT(iid); 2130aea707bSAndrew Jeffery 21436af84cdSRashmica Gupta return 0; 21536af84cdSRashmica Gupta } 216